package channel import ( "database/sql" "encoding/json" "net/http" "git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware" "github.com/go-chi/chi/v5" ) type forumTag struct { ID string `json:"id"` Name string `json:"name"` Emoji *string `json:"emoji"` Color *string `json:"color"` TagID string `json:"tag_id"` } type forumPost struct { threadResponse TagIDs []string `json:"tag_ids"` } func (h *Handler) registerForumRoutes(r chi.Router) { r.Get("/{channelID}/forum-tags", h.ListForumTags) r.Post("/{channelID}/forum-tags", h.CreateForumTag) r.Delete("/forum-tags/{tagID}", h.DeleteForumTag) } // CreateForumTag creates a tag for a forum channel. func (h *Handler) CreateForumTag(w http.ResponseWriter, r *http.Request) { channelID := chi.URLParam(r, "channelID") userID, ok := middleware.UserIDFromContext(r.Context()) if !ok { http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized) return } serverID, err := h.serverIDForChannel(r.Context(), channelID) if err != nil { http.Error(w, `{"error":"channel not found"}`, http.StatusNotFound) return } member, err := h.isMember(r.Context(), userID, serverID) if err != nil || !member { http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden) return } var req struct { Name string `json:"name"` Emoji *string `json:"emoji"` Color *string `json:"color"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Name == "" { http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest) return } var tag forumTag err = h.db.QueryRowContext(r.Context(), ` INSERT INTO forum_tags (channel_id, name, emoji, color) VALUES ($1, $2, $3, $4) RETURNING id, name, emoji, color `, channelID, req.Name, req.Emoji, req.Color).Scan(&tag.ID, &tag.Name, &tag.Emoji, &tag.Color) if err != nil { http.Error(w, `{"error":"failed to create tag"}`, http.StatusInternalServerError) return } tag.TagID = tag.ID w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(tag) } // ListForumTags lists tags for a forum channel. func (h *Handler) ListForumTags(w http.ResponseWriter, r *http.Request) { channelID := chi.URLParam(r, "channelID") userID, ok := middleware.UserIDFromContext(r.Context()) if !ok { http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized) return } serverID, err := h.serverIDForChannel(r.Context(), channelID) if err != nil { http.Error(w, `{"error":"channel not found"}`, http.StatusNotFound) return } member, err := h.isMember(r.Context(), userID, serverID) if err != nil || !member { http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden) return } rows, err := h.db.QueryContext(r.Context(), ` SELECT id, name, emoji, color FROM forum_tags WHERE channel_id = $1 ORDER BY name `, channelID) if err != nil { http.Error(w, `{"error":"server error"}`, http.StatusInternalServerError) return } defer rows.Close() tags := make([]forumTag, 0) for rows.Next() { var t forumTag var emoji, color sql.NullString if err := rows.Scan(&t.ID, &t.Name, &emoji, &color); err != nil { continue } if emoji.Valid { t.Emoji = &emoji.String } if color.Valid { t.Color = &color.String } t.TagID = t.ID tags = append(tags, t) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(tags) } // DeleteForumTag deletes a forum tag. func (h *Handler) DeleteForumTag(w http.ResponseWriter, r *http.Request) { tagID := chi.URLParam(r, "tagID") userID, ok := middleware.UserIDFromContext(r.Context()) if !ok { http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized) return } var channelID string err := h.db.QueryRowContext(r.Context(), `SELECT channel_id FROM forum_tags WHERE id = $1`, tagID).Scan(&channelID) if err != nil { http.Error(w, `{"error":"tag not found"}`, http.StatusNotFound) return } serverID, err := h.serverIDForChannel(r.Context(), channelID) if err != nil { http.Error(w, `{"error":"channel not found"}`, http.StatusNotFound) return } member, err := h.isMember(r.Context(), userID, serverID) if err != nil || !member { http.Error(w, `{"error":"forbidden"}`, http.StatusForbidden) return } _, err = h.db.ExecContext(r.Context(), `DELETE FROM forum_tags WHERE id = $1`, tagID) if err != nil { http.Error(w, `{"error":"failed to delete tag"}`, http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }