213 lines
5.8 KiB
Go
213 lines
5.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/gorilla/mux"
|
|
"go.mongodb.org/mongo-driver/v2/bson"
|
|
|
|
"gitea.hostxtra.co.uk/mrhid6/notely/backend/internal/application/dto"
|
|
"gitea.hostxtra.co.uk/mrhid6/notely/backend/internal/application/services"
|
|
"gitea.hostxtra.co.uk/mrhid6/notely/backend/internal/interfaces/middleware"
|
|
)
|
|
|
|
// CategoryHandler handles category endpoints
|
|
type CategoryHandler struct {
|
|
categoryService *services.CategoryService
|
|
}
|
|
|
|
// NewCategoryHandler creates a new category handler
|
|
func NewCategoryHandler(categoryService *services.CategoryService) *CategoryHandler {
|
|
return &CategoryHandler{categoryService: categoryService}
|
|
}
|
|
|
|
// GetCategoryTree returns the full category tree for a space
|
|
func (h *CategoryHandler) GetCategoryTree(w http.ResponseWriter, r *http.Request) {
|
|
userID, err := getUserObjectID(r)
|
|
if err != nil {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid space id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
tree, err := h.categoryService.GetCategoryTree(r.Context(), spaceID, userID)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusForbidden)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(tree)
|
|
}
|
|
|
|
// CreateCategory creates a new category in a space
|
|
func (h *CategoryHandler) CreateCategory(w http.ResponseWriter, r *http.Request) {
|
|
userID, err := getUserObjectID(r)
|
|
if err != nil {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid space id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req dto.CreateCategoryRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
category, err := h.categoryService.CreateCategory(r.Context(), spaceID, userID, &req)
|
|
if err != nil {
|
|
if err.Error() == "unauthorized" {
|
|
http.Error(w, err.Error(), http.StatusForbidden)
|
|
} else {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(category)
|
|
}
|
|
|
|
// UpdateCategory updates a category
|
|
func (h *CategoryHandler) UpdateCategory(w http.ResponseWriter, r *http.Request) {
|
|
userID, err := getUserObjectID(r)
|
|
if err != nil {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid space id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
categoryID, err := bson.ObjectIDFromHex(vars["categoryId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid category id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req dto.UpdateCategoryRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
category, err := h.categoryService.UpdateCategory(r.Context(), categoryID, spaceID, userID, &req)
|
|
if err != nil {
|
|
if err.Error() == "unauthorized" {
|
|
http.Error(w, err.Error(), http.StatusForbidden)
|
|
} else {
|
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(category)
|
|
}
|
|
|
|
// DeleteCategory deletes a category
|
|
func (h *CategoryHandler) DeleteCategory(w http.ResponseWriter, r *http.Request) {
|
|
userID, err := getUserObjectID(r)
|
|
if err != nil {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid space id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
categoryID, err := bson.ObjectIDFromHex(vars["categoryId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid category id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var moveNotesTo *string
|
|
if v := r.URL.Query().Get("moveNotesTo"); v != "" {
|
|
moveNotesTo = &v
|
|
}
|
|
|
|
if err := h.categoryService.DeleteCategory(r.Context(), categoryID, spaceID, userID, moveNotesTo); err != nil {
|
|
if err.Error() == "unauthorized" {
|
|
http.Error(w, err.Error(), http.StatusForbidden)
|
|
} else {
|
|
http.Error(w, err.Error(), http.StatusNotFound)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusNoContent)
|
|
}
|
|
|
|
// MoveCategory moves a category to a new parent
|
|
func (h *CategoryHandler) MoveCategory(w http.ResponseWriter, r *http.Request) {
|
|
userID, err := getUserObjectID(r)
|
|
if err != nil {
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
vars := mux.Vars(r)
|
|
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid space id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
categoryID, err := bson.ObjectIDFromHex(vars["categoryId"])
|
|
if err != nil {
|
|
http.Error(w, "invalid category id", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var body struct {
|
|
ParentID *string `json:"parent_id"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
|
http.Error(w, "invalid request body", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
category, err := h.categoryService.MoveCategory(r.Context(), categoryID, spaceID, userID, body.ParentID)
|
|
if err != nil {
|
|
if err.Error() == "unauthorized" {
|
|
http.Error(w, err.Error(), http.StatusForbidden)
|
|
} else {
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
}
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(category)
|
|
}
|
|
|
|
// getUserObjectID extracts the user ObjectID from the request context
|
|
func getUserObjectID(r *http.Request) (bson.ObjectID, error) {
|
|
userIDStr, ok := r.Context().Value(middleware.UserIDKey).(string)
|
|
if !ok || userIDStr == "" {
|
|
return bson.NilObjectID, http.ErrNoCookie
|
|
}
|
|
return bson.ObjectIDFromHex(userIDStr)
|
|
}
|