monorepo/cloud/maplefile-backend/internal/interface/http/collection/sync.go

127 lines
4 KiB
Go

// monorepo/cloud/backend/internal/maplefile/interface/http/collection/sync.go
package collection
import (
"encoding/json"
"net/http"
"strconv"
"go.uber.org/zap"
"github.com/gocql/gocql"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
dom_sync "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/domain/collection"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/interface/http/middleware"
svc_collection "codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/internal/service/collection"
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
)
type CollectionSyncHTTPHandler struct {
config *config.Configuration
logger *zap.Logger
service svc_collection.GetCollectionSyncDataService
middleware middleware.Middleware
}
func NewCollectionSyncHTTPHandler(
config *config.Configuration,
logger *zap.Logger,
service svc_collection.GetCollectionSyncDataService,
middleware middleware.Middleware,
) *CollectionSyncHTTPHandler {
logger = logger.Named("CollectionSyncHTTPHandler")
return &CollectionSyncHTTPHandler{
config: config,
logger: logger,
service: service,
middleware: middleware,
}
}
func (*CollectionSyncHTTPHandler) Pattern() string {
return "POST /api/v1/collections/sync"
}
func (h *CollectionSyncHTTPHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Apply middleware before handling the request
h.middleware.Attach(h.Execute)(w, req)
}
func (h *CollectionSyncHTTPHandler) Execute(w http.ResponseWriter, r *http.Request) {
// Set response content type
w.Header().Set("Content-Type", "application/json")
ctx := r.Context()
// Get user ID from context
userID, ok := ctx.Value(constants.SessionUserID).(gocql.UUID)
if !ok {
h.logger.Error("Failed getting user ID from context")
httperror.RespondWithError(w, r, httperror.NewForInternalServerErrorWithSingleField("message", "Authentication context error"))
return
}
// Parse query parameters
queryParams := r.URL.Query()
// Parse limit parameter (default: 1000, max: 5000)
limit := int64(1000)
if limitStr := queryParams.Get("limit"); limitStr != "" {
if parsedLimit, err := strconv.ParseInt(limitStr, 10, 64); err == nil {
if parsedLimit > 0 && parsedLimit <= 5000 {
limit = parsedLimit
} else {
h.logger.Warn("Invalid limit parameter, using default",
zap.String("limit", limitStr),
zap.Int64("default", limit))
}
} else {
h.logger.Warn("Failed to parse limit parameter, using default",
zap.String("limit", limitStr),
zap.Error(err))
}
}
// Parse cursor parameter
var cursor *dom_sync.CollectionSyncCursor
if cursorStr := queryParams.Get("cursor"); cursorStr != "" {
var parsedCursor dom_sync.CollectionSyncCursor
if err := json.Unmarshal([]byte(cursorStr), &parsedCursor); err != nil {
h.logger.Error("Failed to parse cursor parameter",
zap.String("cursor", cursorStr),
zap.Error(err))
httperror.RespondWithError(w, r, httperror.NewForBadRequestWithSingleField("cursor", "Invalid cursor format"))
return
}
cursor = &parsedCursor
}
h.logger.Debug("Processing collection sync request",
zap.Any("user_id", userID),
zap.Int64("limit", limit),
zap.Any("cursor", cursor))
// Call service to get sync data
response, err := h.service.Execute(ctx, userID, cursor, limit, "all")
if err != nil {
h.logger.Error("Failed to get collection sync data",
zap.Any("user_id", userID),
zap.Error(err))
httperror.RespondWithError(w, r, err)
return
}
// Encode and return response
if err := json.NewEncoder(w).Encode(response); err != nil {
h.logger.Error("Failed to encode collection sync response",
zap.Error(err))
httperror.RespondWithError(w, r, err)
return
}
h.logger.Info("Successfully served collection sync data",
zap.Any("user_id", userID),
zap.Int("collections_count", len(response.Collections)),
zap.Bool("has_more", response.HasMore))
}