Files
Messenger/server/internal/api/reactions.go
T

94 lines
2.8 KiB
Go
Raw Normal View History

package api
import (
"encoding/json"
"net/http"
"strconv"
)
func (h *apiHandler) addReaction(w http.ResponseWriter, r *http.Request) {
userID, _ := userIDFrom(r.Context())
convID, msgID, ok := h.parseMessagePath(w, r)
if !ok {
return
}
var req struct {
Emoji string `json:"emoji"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeError(w, http.StatusBadRequest, "invalid json")
return
}
if len(req.Emoji) == 0 || len(req.Emoji) > 32 {
writeError(w, http.StatusBadRequest, "emoji must be 1-32 chars")
return
}
if err := h.store.AddReaction(r.Context(), msgID, userID, req.Emoji); err != nil {
writeError(w, http.StatusInternalServerError, "internal server error")
return
}
h.hub.PublishReactionChanged(convID, msgID, userID, req.Emoji, true)
h.writeMessageWithReactions(w, r, convID, msgID)
}
func (h *apiHandler) removeReaction(w http.ResponseWriter, r *http.Request) {
userID, _ := userIDFrom(r.Context())
convID, msgID, ok := h.parseMessagePath(w, r)
if !ok {
return
}
emoji := r.PathValue("emoji")
if emoji == "" {
writeError(w, http.StatusBadRequest, "emoji is required")
return
}
if err := h.store.RemoveReaction(r.Context(), msgID, userID, emoji); err != nil {
writeError(w, http.StatusInternalServerError, "internal server error")
return
}
h.hub.PublishReactionChanged(convID, msgID, userID, emoji, false)
h.writeMessageWithReactions(w, r, convID, msgID)
}
func (h *apiHandler) parseMessagePath(w http.ResponseWriter, r *http.Request) (convID, msgID int64, ok bool) {
userID, _ := userIDFrom(r.Context())
convID, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil || convID <= 0 {
writeError(w, http.StatusBadRequest, "invalid conversation id")
return 0, 0, false
}
msgID, err = strconv.ParseInt(r.PathValue("msg_id"), 10, 64)
if err != nil || msgID <= 0 {
writeError(w, http.StatusBadRequest, "invalid message id")
return 0, 0, false
}
if member, err := h.store.IsMember(r.Context(), convID, userID); err != nil || !member {
writeError(w, http.StatusForbidden, "not a member")
return 0, 0, false
}
belongs, err := h.store.MessageBelongsToConversation(r.Context(), convID, msgID)
if err != nil || !belongs {
writeError(w, http.StatusNotFound, "message not found")
return 0, 0, false
}
return convID, msgID, true
}
func (h *apiHandler) writeMessageWithReactions(w http.ResponseWriter, r *http.Request, convID, msgID int64) {
msg, err := h.store.GetMessageByID(r.Context(), msgID)
if err != nil {
writeError(w, http.StatusInternalServerError, "internal server error")
return
}
msgs := []messageJSON{toMessageJSON(msg)}
reactions, err := h.store.ReactionsForMessages(r.Context(), []int64{msgID})
if err != nil {
writeError(w, http.StatusInternalServerError, "internal server error")
return
}
attachReactions(msgs, reactions)
writeJSON(w, http.StatusOK, msgs[0])
}