ultisuite-backend/internal/api/photos/validate.go
R3D347HR4Y f0f0b31043 Implement Photos API robustness and quota integration
Improve Immich-backed photos endpoints with robust mapping/error handling, full albums CRUD, reliable list pagination/sorting/filtering, and shared Nextcloud quota checks before upload.
2026-05-22 21:09:13 +02:00

124 lines
3.2 KiB
Go

package photos
import (
"strings"
"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
)
const maxJSONRequestBody = 32 << 10
type createAlbumRequest struct {
Name string `json:"name"`
Description string `json:"description"`
AssetIDs []string `json:"asset_ids"`
}
type updateAlbumRequest struct {
Name *string `json:"name"`
Description *string `json:"description"`
}
type albumAssetsRequest struct {
AssetIDs []string `json:"asset_ids"`
}
func validateAssetID(assetID string) *apivalidate.ValidationError {
if strings.TrimSpace(assetID) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "asset_id", Message: "required",
})
}
return nil
}
func validateAlbumID(albumID string) *apivalidate.ValidationError {
if strings.TrimSpace(albumID) == "" {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "album_id", Message: "required",
})
}
return nil
}
func validateAlbumName(field, name string, required bool) *apivalidate.FieldDetail {
name = strings.TrimSpace(name)
if name == "" {
if required {
return &apivalidate.FieldDetail{Field: field, Message: "required"}
}
return nil
}
if strings.Contains(name, "\n") || strings.Contains(name, "\r") {
return &apivalidate.FieldDetail{Field: field, Message: "invalid"}
}
return nil
}
func validateAssetIDs(field string, assetIDs []string, required bool) []apivalidate.FieldDetail {
if len(assetIDs) == 0 {
if required {
return []apivalidate.FieldDetail{{Field: field, Message: "required"}}
}
return nil
}
var details []apivalidate.FieldDetail
for i, id := range assetIDs {
if strings.TrimSpace(id) == "" {
details = append(details, apivalidate.FieldDetail{
Field: field, Message: "invalid",
})
if i == 0 {
break
}
}
}
return details
}
func validateCreateAlbum(req *createAlbumRequest) *apivalidate.ValidationError {
var details []apivalidate.FieldDetail
if d := validateAlbumName("name", req.Name, true); d != nil {
details = append(details, *d)
}
if d := validateAlbumName("description", req.Description, false); d != nil {
details = append(details, *d)
}
details = append(details, validateAssetIDs("asset_ids", req.AssetIDs, false)...)
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
func validateUpdateAlbum(req *updateAlbumRequest) *apivalidate.ValidationError {
if req.Name == nil && req.Description == nil {
return apivalidate.NewValidationError(apivalidate.FieldDetail{
Field: "body", Message: "required",
})
}
var details []apivalidate.FieldDetail
if req.Name != nil {
if d := validateAlbumName("name", *req.Name, true); d != nil {
details = append(details, *d)
}
}
if req.Description != nil {
if d := validateAlbumName("description", *req.Description, false); d != nil {
details = append(details, *d)
}
}
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}
func validateAlbumAssetsRequest(req *albumAssetsRequest) *apivalidate.ValidationError {
details := validateAssetIDs("asset_ids", req.AssetIDs, true)
if len(details) == 0 {
return nil
}
return apivalidate.NewValidationError(details...)
}