package handler import ( "encoding/json" "errors" "net/http" "strings" "5803025015/w04/internal/middleware" "5803025015/w04/internal/models" "5803025015/w04/internal/store" "github.com/google/uuid" ) type SnippetHandler struct { snippetStore SnippetStore } func NewSnippetHandler(snippetStore SnippetStore) *SnippetHandler { return &SnippetHandler{snippetStore: snippetStore} } type snippetRequest struct { Title string `json:"title"` Content string `json:"content"` } type snippetResponse struct { ID string `json:"id"` Title string `json:"title"` Content string `json:"content"` } func toSnippetResponse(s *models.Snippet) snippetResponse { return snippetResponse{ID: s.ID, Title: s.Title, Content: s.Content} } func (h *SnippetHandler) Snippets(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: h.List(w, r) case http.MethodPost: h.Create(w, r) default: writeError(w, http.StatusMethodNotAllowed, "method not allowed") } } func (h *SnippetHandler) SnippetByID(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: h.Get(w, r) case http.MethodDelete: h.Delete(w, r) default: writeError(w, http.StatusMethodNotAllowed, "method not allowed") } } func (h *SnippetHandler) Create(w http.ResponseWriter, r *http.Request) { userID := middleware.GetUserID(r.Context()) if userID == "" { writeError(w, http.StatusUnauthorized, "unauthorized") return } var req snippetRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeError(w, http.StatusBadRequest, "invalid request body") return } req.Title = strings.TrimSpace(req.Title) req.Content = strings.TrimSpace(req.Content) if req.Title == "" || req.Content == "" { writeError(w, http.StatusBadRequest, "title and content are required") return } snippet := &models.Snippet{ ID: uuid.New().String(), Title: req.Title, Content: req.Content, UserID: userID, } if err := h.snippetStore.Create(r.Context(), snippet); err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } writeJSON(w, http.StatusCreated, toSnippetResponse(snippet)) } func (h *SnippetHandler) List(w http.ResponseWriter, r *http.Request) { userID := middleware.GetUserID(r.Context()) if userID == "" { writeError(w, http.StatusUnauthorized, "unauthorized") return } snippets, err := h.snippetStore.ListByOwner(r.Context(), userID) if err != nil { writeError(w, http.StatusInternalServerError, "internal error") return } out := make([]snippetResponse, 0, len(snippets)) for _, s := range snippets { out = append(out, toSnippetResponse(s)) } writeJSON(w, http.StatusOK, out) } func (h *SnippetHandler) Get(w http.ResponseWriter, r *http.Request) { id := extractID(r) if id == "" { writeError(w, http.StatusBadRequest, "missing id") return } snippet, err := h.snippetStore.GetByID(r.Context(), id) if err != nil { if errors.Is(err, store.ErrNotFound) { writeError(w, http.StatusNotFound, "snippet not found") return } writeError(w, http.StatusInternalServerError, "internal error") return } writeJSON(w, http.StatusOK, toSnippetResponse(snippet)) } func (h *SnippetHandler) Delete(w http.ResponseWriter, r *http.Request) { userID := middleware.GetUserID(r.Context()) if userID == "" { writeError(w, http.StatusUnauthorized, "unauthorized") return } id := extractID(r) if id == "" { writeError(w, http.StatusBadRequest, "missing id") return } snippet, err := h.snippetStore.GetByID(r.Context(), id) if err != nil { if errors.Is(err, store.ErrNotFound) { writeError(w, http.StatusNotFound, "snippet not found") return } writeError(w, http.StatusInternalServerError, "internal error") return } if snippet.UserID != userID { writeError(w, http.StatusForbidden, "forbidden") return } if err := h.snippetStore.Delete(r.Context(), id); err != nil { if errors.Is(err, store.ErrNotFound) { writeError(w, http.StatusNotFound, "snippet not found") return } writeError(w, http.StatusInternalServerError, "internal error") return } w.WriteHeader(http.StatusNoContent) } func extractID(r *http.Request) string { if id := r.PathValue("id"); id != "" { return id } path := strings.TrimPrefix(r.URL.Path, "/snippets/") path = strings.TrimSuffix(path, "/") return path }