Feature 19: Notifications - Web Push and Google Chat (#169)
CI / ci (push) Successful in 8m31s
CI / ci (push) Successful in 8m31s
Co-authored-by: orchestrator-agent <20+orchestrator-agent@code.cubecraftcreations.com>
This commit was merged in pull request #169.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"code.cubecraftlabs.com/Maniacs_Mansion/Meal-Quest/internal/chat"
|
||||
)
|
||||
|
||||
// chatWebhookBody is the PUT /settings/chat-webhook body. Both fields are
|
||||
// required.
|
||||
type chatWebhookBody struct {
|
||||
URL *string `json:"url"`
|
||||
SpaceLabel *string `json:"space_label"`
|
||||
}
|
||||
|
||||
// getChatWebhook answers the stored webhook's settings, which never hold
|
||||
// its URL.
|
||||
func getChatWebhook(logger *slog.Logger, svc *chat.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
settings, err := svc.Get(r.Context())
|
||||
if err != nil {
|
||||
logger.ErrorContext(r.Context(), "get chat webhook", "error", err)
|
||||
writeError(w, r, logger, http.StatusInternalServerError, "internal", "internal error")
|
||||
return
|
||||
}
|
||||
writeJSON(w, r, logger, http.StatusOK, settings)
|
||||
}
|
||||
}
|
||||
|
||||
// putChatWebhook stores the webhook URL sealed, with its space label, and
|
||||
// answers the settings as GET does.
|
||||
func putChatWebhook(logger *slog.Logger, svc *chat.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
body, err := decodePatch[chatWebhookBody](http.MaxBytesReader(w, r.Body, maxSettingsBody))
|
||||
if err != nil {
|
||||
writeError(w, r, logger, http.StatusBadRequest, "invalid_request", err.Error())
|
||||
return
|
||||
}
|
||||
if body.URL == nil || body.SpaceLabel == nil {
|
||||
writeError(w, r, logger, http.StatusBadRequest, "invalid_request", "url and space_label are required")
|
||||
return
|
||||
}
|
||||
settings, err := svc.Put(r.Context(), *body.URL, *body.SpaceLabel)
|
||||
var invalid *chat.ValidationError
|
||||
if errors.As(err, &invalid) {
|
||||
writeError(w, r, logger, http.StatusBadRequest, "invalid_webhook", invalid.Error())
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
logger.ErrorContext(r.Context(), "save chat webhook", "error", err)
|
||||
writeError(w, r, logger, http.StatusInternalServerError, "internal", "internal error")
|
||||
return
|
||||
}
|
||||
writeJSON(w, r, logger, http.StatusOK, settings)
|
||||
}
|
||||
}
|
||||
|
||||
// postChatWebhookTest sends chat.TestText to the stored webhook and answers
|
||||
// 200 with the status Google Chat answered, whatever it was, and the
|
||||
// recorded outcome. No webhook stored, or one replaced during the test, is
|
||||
// 409; no answer from Google Chat is 502.
|
||||
func postChatWebhookTest(logger *slog.Logger, svc *chat.Service) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
result, err := svc.Test(r.Context())
|
||||
switch {
|
||||
case errors.Is(err, chat.ErrNotConfigured):
|
||||
writeError(w, r, logger, http.StatusConflict, "not_configured", "no Google Chat webhook is configured")
|
||||
case errors.Is(err, chat.ErrWebhookChanged):
|
||||
writeError(w, r, logger, http.StatusConflict, "webhook_changed", "the Google Chat webhook changed during the test; test it again")
|
||||
case err != nil && r.Context().Err() != nil:
|
||||
logger.WarnContext(r.Context(), "chat webhook test interrupted", "error", err)
|
||||
case errors.Is(err, chat.ErrUnreachable):
|
||||
logger.WarnContext(r.Context(), "chat webhook test failed", "error", err)
|
||||
writeError(w, r, logger, http.StatusBadGateway, "chat_unreachable", "Google Chat did not answer the test message")
|
||||
case err != nil:
|
||||
logger.ErrorContext(r.Context(), "chat webhook test", "error", err)
|
||||
writeError(w, r, logger, http.StatusInternalServerError, "internal", "internal error")
|
||||
default:
|
||||
writeJSON(w, r, logger, http.StatusOK, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user