Add swaggo annotations to all handlers and regenerate full Swagger docs

- Added @Summary/@Router/@Param/@Success/@Security annotations to all API handlers
- Regenerated docs/swagger.json, docs/swagger.yaml, docs/docs.go with full endpoint definitions
- Fixed generated docs.go to remove unsupported LeftDelim/RightDelim fields
This commit is contained in:
2026-06-28 19:16:42 -04:00
parent 1b7778930c
commit 72ca99b58d
14 changed files with 9581 additions and 4 deletions
+44
View File
@@ -78,6 +78,16 @@ func gravatarURL(email string) string {
return fmt.Sprintf("https://www.gravatar.com/avatar/%s?d=identicon&s=256", hex.EncodeToString(hash[:]))
}
// @Summary Register a new user
// @Description Create a new user account
// @Tags auth
// @Accept json
// @Produce json
// @Param body body registerRequest true "Registration data"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 409 {object} map[string]string
// @Router /auth/register [post]
func (h *Handler) Register(w http.ResponseWriter, r *http.Request) {
var req registerRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -123,6 +133,16 @@ func (h *Handler) Register(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"id": userID})
}
// @Summary Login with email and password
// @Description Authenticate with email and password
// @Tags auth
// @Accept json
// @Produce json
// @Param body body loginRequest true "Login credentials"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /auth/login/password [post]
func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
var req loginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -156,6 +176,11 @@ func (h *Handler) Login(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"id": userID})
}
// @Summary Logout
// @Description End the current session
// @Tags auth
// @Success 204
// @Router /auth/logout [post]
func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie(h.cfg.Session.CookieName)
if err == nil {
@@ -173,6 +198,14 @@ func (h *Handler) Logout(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary Get current user profile
// @Description Get the authenticated user's profile
// @Tags auth
// @Produce json
// @Security SessionAuth
// @Success 200 {object} UserProfile
// @Failure 401 {object} map[string]string
// @Router /auth/me [get]
func (h *Handler) Me(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -190,6 +223,17 @@ func (h *Handler) Me(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(user)
}
// @Summary Update current user profile
// @Description Update the authenticated user's profile
// @Tags auth
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body updateProfileRequest true "Profile update data"
// @Success 200 {object} UserProfile
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /auth/me [patch]
func (h *Handler) UpdateProfile(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
+36
View File
@@ -88,6 +88,16 @@ func (h *WebAuthnHandler) RegisterRoutes(r *http.ServeMux) {
r.HandleFunc("POST /auth/webauthn/login/finish", h.LoginFinish)
}
// @Summary Begin passkey registration
// @Description Start passkey registration for an authenticated user
// @Tags webauthn
// @Produce json
// @Security SessionAuth
// @Success 200 {object} object "WebAuthn registration options"
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/webauthn/register/begin [post]
// RegisterBegin starts passkey registration for an authenticated user.
func (h *WebAuthnHandler) RegisterBegin(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -116,6 +126,16 @@ func (h *WebAuthnHandler) RegisterBegin(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(options)
}
// @Summary Finish passkey registration
// @Description Complete passkey registration
// @Tags webauthn
// @Produce json
// @Security SessionAuth
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /auth/webauthn/register/finish [post]
// RegisterFinish completes passkey registration.
func (h *WebAuthnHandler) RegisterFinish(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -163,6 +183,13 @@ func (h *WebAuthnHandler) RegisterFinish(w http.ResponseWriter, r *http.Request)
json.NewEncoder(w).Encode(map[string]string{"status": "registered"})
}
// @Summary Begin passkey login
// @Description Start passkey authentication
// @Tags webauthn
// @Produce json
// @Success 200 {object} object "WebAuthn login options"
// @Failure 500 {object} map[string]string
// @Router /auth/webauthn/login/begin [post]
// LoginBegin starts passkey authentication (no auth required).
func (h *WebAuthnHandler) LoginBegin(w http.ResponseWriter, r *http.Request) {
// Get all registered credentials for the login ceremony
@@ -213,6 +240,15 @@ func (h *WebAuthnHandler) LoginBegin(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(options)
}
// @Summary Finish passkey login
// @Description Complete passkey authentication
// @Tags webauthn
// @Accept json
// @Produce json
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /auth/webauthn/login/finish [post]
// LoginFinish completes passkey authentication.
func (h *WebAuthnHandler) LoginFinish(w http.ResponseWriter, r *http.Request) {
// Get challenge key from cookie
+44 -1
View File
@@ -58,6 +58,20 @@ type createCommandRequest struct {
// ---- handlers ----
// @Summary Create a slash command
// @Description Create a new slash command for a bot
// @Tags bot commands
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Param body body createCommandRequest true "Command data"
// @Success 201 {object} slashCommandResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 409 {object} map[string]string
// @Router /bots/{botID}/commands [post]
func (h *CommandHandler) Create(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -131,6 +145,17 @@ func (h *CommandHandler) Create(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, cmd)
}
// @Summary List bot commands
// @Description List all slash commands for a bot
// @Tags bot commands
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Success 200 {array} slashCommandResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID}/commands [get]
func (h *CommandHandler) ListByBot(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -180,6 +205,17 @@ func (h *CommandHandler) ListByBot(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, cmds)
}
// @Summary Delete a slash command
// @Description Delete a slash command
// @Tags bot commands
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Param cmdID path string true "Command ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID}/commands/{cmdID} [delete]
func (h *CommandHandler) Delete(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -217,7 +253,14 @@ func (h *CommandHandler) Delete(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// ListByServer returns all slash commands registered in a server (public, no auth).
// @Summary List server commands
// @Description List all slash commands registered in a server (public)
// @Tags bot commands
// @Produce json
// @Param serverID path string true "Server ID"
// @Success 200 {array} slashCommandResponse
// @Failure 500 {object} map[string]string
// @Router /bots/servers/{serverID}/commands [get]
func (h *CommandHandler) ListByServer(w http.ResponseWriter, r *http.Request) {
serverID := chi.URLParam(r, "serverID")
+90
View File
@@ -78,6 +78,17 @@ func writeErr(w http.ResponseWriter, status int, msg string) {
// ---- handlers ----
// @Summary Create a bot
// @Description Create a new bot
// @Tags bots
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body createBotRequest true "Bot data"
// @Success 201 {object} botWithToken
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /bots [post]
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -121,6 +132,14 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, bot)
}
// @Summary List bots
// @Description List all bots owned by the current user
// @Tags bots
// @Produce json
// @Security SessionAuth
// @Success 200 {array} botResponse
// @Failure 401 {object} map[string]string
// @Router /bots [get]
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -161,6 +180,17 @@ func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, bots)
}
// @Summary Get a bot
// @Description Get a bot by ID (owner only)
// @Tags bots
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Success 200 {object} botResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID} [get]
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -197,6 +227,20 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, b)
}
// @Summary Update a bot
// @Description Update a bot's name, description, or avatar (owner only)
// @Tags bots
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Param body body updateBotRequest true "Bot update data"
// @Success 200 {object} botResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID} [patch]
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -259,6 +303,16 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, b)
}
// @Summary Delete a bot
// @Description Delete a bot (owner only)
// @Tags bots
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID} [delete]
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -294,6 +348,20 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary Add bot to server
// @Description Add a bot to a server
// @Tags bots
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Param body body addToServerRequest true "Server data"
// @Success 201 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID}/servers [post]
func (h *Handler) AddToServer(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -361,6 +429,17 @@ func (h *Handler) AddToServer(w http.ResponseWriter, r *http.Request) {
})
}
// @Summary Remove bot from server
// @Description Remove a bot from a server
// @Tags bots
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Param serverID path string true "Server ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID}/servers/{serverID} [delete]
func (h *Handler) RemoveFromServer(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -405,6 +484,17 @@ func (h *Handler) RemoveFromServer(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary Regenerate bot token
// @Description Regenerate a bot's API token (owner only)
// @Tags bots
// @Produce json
// @Security SessionAuth
// @Param botID path string true "Bot ID"
// @Success 200 {object} botWithToken
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /bots/{botID}/regenerate-token [post]
func (h *Handler) RegenerateToken(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
+58
View File
@@ -63,6 +63,18 @@ func (h *Handler) serverIDForChannel(ctx context.Context, channelID string) (str
return serverID, err
}
// @Summary Create a channel
// @Description Create a new channel in a server
// @Tags channels
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body createChannelRequest true "Channel data"
// @Success 201 {object} channelResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /servers/{serverID}/channels [post]
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -121,6 +133,17 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(ch)
}
// @Summary List channels
// @Description List channels in a server
// @Tags channels
// @Produce json
// @Security SessionAuth
// @Param server_id query string true "Server ID"
// @Success 200 {array} channelResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /servers/{serverID}/channels [get]
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -174,6 +197,17 @@ func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(channels)
}
// @Summary Get a channel
// @Description Get a channel by ID
// @Tags channels
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Success 200 {object} channelResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /servers/{serverID}/channels/{channelID} [get]
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -218,6 +252,20 @@ type updateChannelRequest struct {
Position *int `json:"position"`
}
// @Summary Update a channel
// @Description Update a channel's properties
// @Tags channels
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param body body updateChannelRequest true "Channel update data"
// @Success 200 {object} channelResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /servers/{serverID}/channels/{channelID} [patch]
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -279,6 +327,16 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(ch)
}
// @Summary Delete a channel
// @Description Delete a channel (server owner only)
// @Tags channels
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /servers/{serverID}/channels/{channelID} [delete]
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
+32
View File
@@ -61,6 +61,18 @@ func generateCode(length int) (string, error) {
return string(result), nil
}
// @Summary Create an invite
// @Description Create an invite code for a server
// @Tags invites
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param serverID path string true "Server ID"
// @Param body body createInviteRequest false "Invite options"
// @Success 201 {object} inviteResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /servers/{serverID}/invites [post]
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
serverID := chi.URLParam(r, "serverID")
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -163,6 +175,14 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(invite)
}
// @Summary Get invite info
// @Description Get information about an invite by code
// @Tags invites
// @Produce json
// @Param code path string true "Invite code"
// @Success 200 {object} inviteResponse
// @Failure 404 {object} map[string]string
// @Router /invites/{code} [get]
func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
code := chi.URLParam(r, "code")
@@ -197,6 +217,18 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(invite)
}
// @Summary Join server via invite
// @Description Join a server using an invite code
// @Tags invites
// @Produce json
// @Security SessionAuth
// @Param code path string true "Invite code"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 409 {object} map[string]string
// @Router /invites/{code}/join [post]
func (h *Handler) Join(w http.ResponseWriter, r *http.Request) {
code := chi.URLParam(r, "code")
userID, ok := middleware.UserIDFromContext(r.Context())
+49
View File
@@ -61,6 +61,19 @@ type createMessageRequest struct {
ReplyTo *string `json:"reply_to,omitempty"`
}
// @Summary Create a message
// @Description Send a message to a channel
// @Tags messages
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param body body createMessageRequest true "Message data"
// @Success 201 {object} messageResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /channels/{channelID}/messages [post]
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
channelID := chi.URLParam(r, "channelID")
userID, ok := h.requireChannelAccess(w, r, channelID)
@@ -129,6 +142,20 @@ type updateMessageRequest struct {
Content string `json:"content"`
}
// @Summary Update a message
// @Description Edit a message (author only)
// @Tags messages
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param messageID path string true "Message ID"
// @Param body body updateMessageRequest true "Message update data"
// @Success 200 {object} messageResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /channels/{channelID}/messages/{messageID} [patch]
func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
messageID := chi.URLParam(r, "messageID")
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -188,6 +215,16 @@ func (h *Handler) Update(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(msg)
}
// @Summary Delete a message
// @Description Delete a message (author only)
// @Tags messages
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param messageID path string true "Message ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /channels/{channelID}/messages/{messageID} [delete]
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
messageID := chi.URLParam(r, "messageID")
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -221,6 +258,18 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary List messages
// @Description List messages in a channel with pagination
// @Tags messages
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param limit query int false "Max messages to return (1-100, default 50)"
// @Param before query string false "Message ID to fetch messages before"
// @Success 200 {array} messageResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /channels/{channelID}/messages [get]
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
channelID := chi.URLParam(r, "channelID")
userID, ok := h.requireChannelAccess(w, r, channelID)
+28
View File
@@ -37,11 +37,28 @@ func (h *Handler) RegisterRoutes(r *http.ServeMux) {
r.HandleFunc("GET /push/vapid-public-key", h.GetPublicKey)
}
// @Summary Get VAPID public key
// @Description Get the VAPID public key for push notification subscriptions
// @Tags push
// @Produce json
// @Success 200 {object} map[string]string
// @Router /push/vapid-public-key [get]
func (h *Handler) GetPublicKey(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{"publicKey": h.vapidPub})
}
// @Summary Subscribe to push notifications
// @Description Subscribe to push notifications
// @Tags push
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body object true "Push subscription with endpoint, p256dh, and auth"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /push/subscribe [post]
func (h *Handler) Subscribe(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -75,6 +92,17 @@ func (h *Handler) Subscribe(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{"status": "subscribed"})
}
// @Summary Unsubscribe from push notifications
// @Description Unsubscribe from push notifications
// @Tags push
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body object true "Endpoint to unsubscribe"
// @Success 200 {object} map[string]string
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Router /push/unsubscribe [post]
func (h *Handler) Unsubscribe(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
+34
View File
@@ -99,6 +99,19 @@ func (h *Handler) requireMessageAccess(w http.ResponseWriter, r *http.Request, m
return userID, channelID, serverID, true
}
// @Summary Add a reaction
// @Description Add a reaction to a message
// @Tags reactions
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param messageID path string true "Message ID"
// @Param body body addReactionRequest true "Reaction data"
// @Success 201 {object} reactionResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /messages/{messageID}/reactions [post]
func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
messageID := chi.URLParam(r, "messageID")
userID, channelID, _, ok := h.requireMessageAccess(w, r, messageID)
@@ -146,6 +159,17 @@ func (h *Handler) Add(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(reaction)
}
// @Summary Remove a reaction
// @Description Remove a reaction from a message
// @Tags reactions
// @Security SessionAuth
// @Param messageID path string true "Message ID"
// @Param emoji path string true "Emoji to remove"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /messages/{messageID}/reactions/{emoji} [delete]
func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
messageID := chi.URLParam(r, "messageID")
emoji := chi.URLParam(r, "emoji")
@@ -185,6 +209,16 @@ func (h *Handler) Remove(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary List reactions
// @Description List reactions on a message grouped by emoji
// @Tags reactions
// @Produce json
// @Security SessionAuth
// @Param messageID path string true "Message ID"
// @Success 200 {array} emojiGroup
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Router /messages/{messageID}/reactions [get]
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
messageID := chi.URLParam(r, "messageID")
if _, _, _, ok := h.requireMessageAccess(w, r, messageID); !ok {
+21
View File
@@ -39,6 +39,18 @@ type tokenResponse struct {
LiveKitURL string `json:"livekit_url"`
}
// @Summary Get voice token
// @Description Get a LiveKit access token for a voice room
// @Tags voice
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param body body tokenRequest true "Room data"
// @Success 200 {object} tokenResponse
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /voice/token [post]
func (h *Handler) GetToken(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
if !ok {
@@ -94,6 +106,15 @@ func (h *Handler) GetToken(w http.ResponseWriter, r *http.Request) {
})
}
// @Summary Get voice room participants
// @Description Get participants in a voice room
// @Tags voice
// @Produce json
// @Param roomID path string true "Room ID"
// @Success 200 {array} object
// @Failure 400 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Router /voice/rooms/{roomID}/participants [get]
func (h *Handler) GetParticipants(w http.ResponseWriter, r *http.Request) {
roomID := chi.URLParam(r, "roomID")
if roomID == "" {
+48
View File
@@ -82,6 +82,20 @@ func writeErr(w http.ResponseWriter, status int, msg string) {
// ---- handlers ----
// @Summary Create a webhook
// @Description Create a new webhook for a channel
// @Tags webhooks
// @Accept json
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Param body body createWebhookRequest true "Webhook data"
// @Success 201 {object} webhookWithToken
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /channels/{channelID}/webhooks [post]
// Create creates a new webhook for a channel.
func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -148,6 +162,17 @@ func (h *Handler) Create(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, wh)
}
// @Summary List webhooks
// @Description List webhooks for a channel
// @Tags webhooks
// @Produce json
// @Security SessionAuth
// @Param channelID path string true "Channel ID"
// @Success 200 {array} webhookResponse
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /channels/{channelID}/webhooks [get]
// List returns all webhooks for a channel.
func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -211,6 +236,16 @@ func (h *Handler) List(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, webhooks)
}
// @Summary Delete a webhook
// @Description Delete a webhook
// @Tags webhooks
// @Security SessionAuth
// @Param webhookID path string true "Webhook ID"
// @Success 204
// @Failure 401 {object} map[string]string
// @Failure 403 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /webhooks/{webhookID} [delete]
// Delete removes a webhook.
func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
userID, ok := middleware.UserIDFromContext(r.Context())
@@ -247,6 +282,19 @@ func (h *Handler) Delete(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
// @Summary Execute a webhook
// @Description Execute a webhook to send a message (no auth required)
// @Tags webhooks
// @Accept json
// @Produce json
// @Param webhookID path string true "Webhook ID"
// @Param token path string true "Webhook token"
// @Param body body executeWebhookRequest true "Message data"
// @Success 201 {object} map[string]interface{}
// @Failure 400 {object} map[string]string
// @Failure 401 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Router /webhooks/{webhookID}/{token} [post]
// Execute sends a message to a channel via webhook (no auth required).
func (h *Handler) Execute(w http.ResponseWriter, r *http.Request) {
webhookID := chi.URLParam(r, "webhookID")