package handler import ( "net/http" "strings" "github.com/go-chi/chi/v5" "github.com/google/uuid" "learning-service/internal/model" "learning-service/internal/repository" ) type CourseHandler struct { repo *repository.CourseRepository } func NewCourseHandler(repo *repository.CourseRepository) *CourseHandler { return &CourseHandler{repo: repo} } // List — GET /courses?mine=true. Поведение зеркально TestHandler.List: // // mine=true → только мои (owner_user_id = X-User-Id); // без mine → только опубликованные. // // В будущей итерации access_grants добавят visibleIDs-фильтр. func (h *CourseHandler) List(w http.ResponseWriter, r *http.Request) { uid, ok := userIDFromHeader(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } mine := r.URL.Query().Get("mine") == "true" var ownerFilter *uuid.UUID if mine { ownerFilter = &uid } items, err := h.repo.List(r.Context(), ownerFilter, !mine, nil) if err != nil { writeRepoError(w, r, err, "list courses") return } writeJSON(w, http.StatusOK, map[string]any{"items": items}) } func (h *CourseHandler) Get(w http.ResponseWriter, r *http.Request) { id, err := parseUUID(chi.URLParam(r, "id")) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } c, err := h.repo.Get(r.Context(), id) if err != nil { writeRepoError(w, r, err, "get course") return } writeJSON(w, http.StatusOK, c) } func (h *CourseHandler) Create(w http.ResponseWriter, r *http.Request) { uid, ok := userIDFromHeader(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } var req model.CreateCourseRequest if err := decodeJSON(r, &req); err != nil { writeError(w, http.StatusBadRequest, "invalid body") return } if strings.TrimSpace(req.Title) == "" { writeError(w, http.StatusBadRequest, "title is required") return } c, err := h.repo.Create(r.Context(), uid, req) if err != nil { writeRepoError(w, r, err, "create course") return } writeJSON(w, http.StatusCreated, c) } func (h *CourseHandler) Update(w http.ResponseWriter, r *http.Request) { uid, ok := userIDFromHeader(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } id, err := parseUUID(chi.URLParam(r, "id")) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } existing, err := h.repo.Get(r.Context(), id) if err != nil { writeRepoError(w, r, err, "get course for update") return } if existing.OwnerUserID != uid { writeError(w, http.StatusForbidden, "only owner can edit") return } var req model.UpdateCourseRequest if err := decodeJSON(r, &req); err != nil { writeError(w, http.StatusBadRequest, "invalid body") return } c, err := h.repo.Update(r.Context(), id, req) if err != nil { writeRepoError(w, r, err, "update course") return } writeJSON(w, http.StatusOK, c) } func (h *CourseHandler) Delete(w http.ResponseWriter, r *http.Request) { uid, ok := userIDFromHeader(r) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } id, err := parseUUID(chi.URLParam(r, "id")) if err != nil { writeError(w, http.StatusBadRequest, "invalid id") return } existing, err := h.repo.Get(r.Context(), id) if err != nil { writeRepoError(w, r, err, "get course for delete") return } if existing.OwnerUserID != uid { writeError(w, http.StatusForbidden, "only owner can delete") return } if err := h.repo.Delete(r.Context(), id); err != nil { writeRepoError(w, r, err, "delete course") return } w.WriteHeader(http.StatusNoContent) }