Files
notely/backend/internal/interfaces/handlers/public_handler.go
2026-03-26 16:27:14 +00:00

157 lines
4.7 KiB
Go

package handlers
import (
"encoding/json"
"net/http"
"strconv"
"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"
)
// PublicHandler handles unauthenticated public read-only requests
type PublicHandler struct {
spaceService *services.SpaceService
noteService *services.NoteService
}
// NewPublicHandler creates a new PublicHandler
func NewPublicHandler(spaceService *services.SpaceService, noteService *services.NoteService) *PublicHandler {
return &PublicHandler{spaceService: spaceService, noteService: noteService}
}
// GetPublicSpace handles GET /public/spaces/{spaceId}
func (h *PublicHandler) GetPublicSpace(w http.ResponseWriter, r *http.Request) {
spaceID, err := bson.ObjectIDFromHex(mux.Vars(r)["spaceId"])
if err != nil {
http.Error(w, "invalid space id", http.StatusBadRequest)
return
}
space, err := h.spaceService.GetPublicSpace(r.Context(), spaceID)
if err != nil {
if err.Error() == "space is not public" {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(space)
}
// ListPublicSpaces handles GET /public/spaces
func (h *PublicHandler) ListPublicSpaces(w http.ResponseWriter, r *http.Request) {
spaces, err := h.spaceService.GetPublicSpaces(r.Context())
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{"spaces": spaces})
}
// GetPublicNotes handles GET /public/spaces/{spaceId}/notes
func (h *PublicHandler) GetPublicNotes(w http.ResponseWriter, r *http.Request) {
spaceID, err := bson.ObjectIDFromHex(mux.Vars(r)["spaceId"])
if err != nil {
http.Error(w, "invalid space id", http.StatusBadRequest)
return
}
skip := 0
limit := 50
if v := r.URL.Query().Get("skip"); v != "" {
if n, err := strconv.Atoi(v); err == nil && n >= 0 {
skip = n
}
}
if v := r.URL.Query().Get("limit"); v != "" {
if n, err := strconv.Atoi(v); err == nil && n > 0 && n <= 100 {
limit = n
}
}
notes, err := h.noteService.GetPublicNotesBySpace(r.Context(), spaceID, skip, limit)
if err != nil {
if err.Error() == "space is not public" {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{"notes": notes})
}
// GetPublicNote handles GET /public/spaces/{spaceId}/notes/{noteId}
func (h *PublicHandler) GetPublicNote(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
if err != nil {
http.Error(w, "invalid space id", http.StatusBadRequest)
return
}
noteID, err := bson.ObjectIDFromHex(vars["noteId"])
if err != nil {
http.Error(w, "invalid note id", http.StatusBadRequest)
return
}
note, err := h.noteService.GetPublicNoteBySpaceAndID(r.Context(), spaceID, noteID)
if err != nil {
if err.Error() == "space is not public" || err.Error() == "note is not public" || err.Error() == "space not found" || err.Error() == "note not found" {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(note)
}
// UnlockPublicNote verifies a public note password and returns full note content
func (h *PublicHandler) UnlockPublicNote(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
spaceID, err := bson.ObjectIDFromHex(vars["spaceId"])
if err != nil {
http.Error(w, "invalid space id", http.StatusBadRequest)
return
}
noteID, err := bson.ObjectIDFromHex(vars["noteId"])
if err != nil {
http.Error(w, "invalid note id", http.StatusBadRequest)
return
}
var req dto.UnlockNoteRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid request body", http.StatusBadRequest)
return
}
note, err := h.noteService.UnlockPublicNote(r.Context(), spaceID, noteID, req.Password)
if err != nil {
if err.Error() == "invalid note password" {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
}
if err.Error() == "space is not public" || err.Error() == "space not found" || err.Error() == "note not found" {
http.Error(w, "not found", http.StatusNotFound)
return
}
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(note)
}