ultisuite-backend/internal/api/drive/validate.go
R3D347HR4Y 1d063237b9
Some checks are pending
CI / Go tests (push) Waiting to run
CI / Integration tests (push) Waiting to run
CI / DB migrations (push) Waiting to run
feat(transcription): integrate Faster Whisper for Jitsi transcriptions
- Added support for Faster Whisper transcription via Jigasi and Skynet.
- Updated .env.example to include new environment variables for transcription settings.
- Enhanced Jitsi Docker Compose configuration to include Skynet and Jigasi services.
- Introduced new API endpoints for managing organizational folders in the drive service.
- Updated Nextcloud initialization script to enable external file mounting.
- Improved error handling and response structures in the drive API.
- Added new properties for organization settings related to transcription and agenda management.
2026-06-12 19:10:18 +02:00

244 lines
7.3 KiB
Go

package drive
import (
"net/url"
"strings"
"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
"github.com/ultisuite/ulti-backend/internal/nextcloud"
)
const maxJSONRequestBody = 32 << 10
type moveRequest struct {
Source string `json:"source"`
Destination string `json:"destination"`
SourceRoot string `json:"source_root,omitempty"`
SourceRootID string `json:"source_root_id,omitempty"`
DestinationRoot string `json:"destination_root,omitempty"`
DestinationRootID string `json:"destination_root_id,omitempty"`
}
type copyRequest struct {
Source string `json:"source"`
Destination string `json:"destination"`
SourceRoot string `json:"source_root,omitempty"`
SourceRootID string `json:"source_root_id,omitempty"`
DestinationRoot string `json:"destination_root,omitempty"`
DestinationRootID string `json:"destination_root_id,omitempty"`
}
type renameRequest struct {
Path string `json:"path"`
NewName string `json:"new_name"`
Root string `json:"root,omitempty"`
RootID string `json:"root_id,omitempty"`
}
type favoriteRequest struct {
Path string `json:"path"`
Favorite bool `json:"favorite"`
Root string `json:"root,omitempty"`
RootID string `json:"root_id,omitempty"`
}
type createMountRequest struct {
Scope string `json:"scope"`
OrgSlug string `json:"org_slug,omitempty"`
DisplayName string `json:"display_name"`
BackendType string `json:"backend_type"`
WebDAV *nextcloud.WebDAVMountConfig `json:"webdav,omitempty"`
OAuthBackend string `json:"oauth_backend,omitempty"`
OAuthAuth string `json:"oauth_auth,omitempty"`
}
func validateMoveRequest(req *moveRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.Source) == "" {
details = append(details, apivalidate.FieldDetail{Field: "source", Message: "required"})
}
if strings.TrimSpace(req.Destination) == "" {
details = append(details, apivalidate.FieldDetail{Field: "destination", Message: "required"})
}
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
func validateCopyRequest(req *copyRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.Source) == "" {
details = append(details, apivalidate.FieldDetail{Field: "source", Message: "required"})
}
if strings.TrimSpace(req.Destination) == "" {
details = append(details, apivalidate.FieldDetail{Field: "destination", Message: "required"})
}
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
func validateRenameRequest(req *renameRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.Path) == "" {
details = append(details, apivalidate.FieldDetail{Field: "path", Message: "required"})
}
newName := strings.TrimSpace(req.NewName)
if newName == "" {
details = append(details, apivalidate.FieldDetail{Field: "new_name", Message: "required"})
} else if strings.Contains(newName, "/") {
details = append(details, apivalidate.FieldDetail{Field: "new_name", Message: "invalid"})
}
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
type createShareRequest struct {
Path string `json:"path"`
ShareType int `json:"share_type"`
Permissions int `json:"permissions"`
Role string `json:"role"`
Mode string `json:"mode"`
ShareWith string `json:"share_with"`
Note string `json:"note"`
SendMail *bool `json:"send_mail"`
Root string `json:"root,omitempty"`
RootID string `json:"root_id,omitempty"`
}
func sharePermissionsForRole(role string) (int, bool) {
switch strings.TrimSpace(strings.ToLower(role)) {
case "owner":
return 31, true
case "editor":
return 15, true
case "viewer":
return 1, true
default:
return 0, false
}
}
func validateCreateShareRequest(req *createShareRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.Path) == "" {
details = append(details, apivalidate.FieldDetail{Field: "path", Message: "required"})
}
if role := strings.TrimSpace(req.Role); role != "" {
if _, ok := sharePermissionsForRole(role); !ok {
details = append(details, apivalidate.FieldDetail{Field: "role", Message: "invalid"})
}
}
mode := strings.TrimSpace(strings.ToLower(req.Mode))
switch mode {
case "", "public", "internal":
case "contact":
if strings.TrimSpace(req.ShareWith) == "" {
details = append(details, apivalidate.FieldDetail{Field: "share_with", Message: "required"})
}
default:
details = append(details, apivalidate.FieldDetail{Field: "mode", Message: "invalid"})
}
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
type restoreTrashRequest struct {
Name string `json:"name"`
}
func validateRestoreTrashRequest(req *restoreTrashRequest) *apivalidate.ValidationError {
if strings.TrimSpace(req.Name) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "name", Message: "required",
})
}
return nil
}
type deleteTrashRequest struct {
Name string `json:"name"`
}
func validateDeleteTrashRequest(req *deleteTrashRequest) *apivalidate.ValidationError {
if strings.TrimSpace(req.Name) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "name", Message: "required",
})
}
return nil
}
func validateFavoriteRequest(req *favoriteRequest) *apivalidate.ValidationError {
if strings.TrimSpace(req.Path) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "path", Message: "required",
})
}
return nil
}
type updateShareRequest struct {
Permissions int `json:"permissions"`
Role string `json:"role"`
ExpireDate string `json:"expire_date"`
Password string `json:"password"`
}
type newFileRequest struct {
ParentPath string `json:"parent_path"`
Name string `json:"name"`
Kind string `json:"kind"`
}
func validateNewFileRequest(req *newFileRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if strings.TrimSpace(req.Name) == "" {
details = append(details, apivalidate.FieldDetail{Field: "name", Message: "required"})
}
k := strings.TrimSpace(strings.ToLower(req.Kind))
if k != "document" && k != "spreadsheet" && k != "presentation" && k != "drawing" {
details = append(details, apivalidate.FieldDetail{Field: "kind", Message: "invalid"})
}
if len(details) > 0 {
return apivalidate.NewValidationError(details...)
}
return nil
}
func validatePath(path string) *apivalidate.ValidationError {
if strings.TrimSpace(path) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "path", Message: "required",
})
}
return nil
}
const mountOAuthCallbackPath = "/drive/mounts/oauth/callback"
func validateMountOAuthRedirectURI(raw string) error {
raw = strings.TrimSpace(raw)
if raw == "" {
return ErrInvalid
}
parsed, err := url.Parse(raw)
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
return ErrInvalid
}
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return ErrInvalid
}
path := strings.TrimRight(parsed.Path, "/")
if path != mountOAuthCallbackPath {
return ErrInvalid
}
return nil
}