MCPcopy Index your code
hub / github.com/coder/coder / postCustomNotification

Method postCustomNotification

coderd/notifications.go:357–428  ·  view source on GitHub ↗

@Summary Send a custom notification @ID send-a-custom-notification @Security CoderSessionToken @Tags Notifications @Accept json @Produce json @Param request body codersdk.CustomNotificationRequest true "Provide a non-empty title or message" @Success 204 "No Content" @Failure 400 {object} codersdk.Re

(rw http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

355// @Failure 500 {object} codersdk.Response "Failed to send custom notification"
356// @Router /api/v2/notifications/custom [post]
357func (api *API) postCustomNotification(rw http.ResponseWriter, r *http.Request) {
358 var (
359 ctx = r.Context()
360 apiKey = httpmw.APIKey(r)
361 )
362
363 // Parse request
364 var req codersdk.CustomNotificationRequest
365 if !httpapi.Read(ctx, rw, r, &req) {
366 return
367 }
368
369 // Validate request: require `content` and non-empty `title` and `message`
370 if err := req.Validate(); err != nil {
371 api.Logger.Error(ctx, "send custom notification: validation failed", slog.Error(err))
372 httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
373 Message: "Invalid request body",
374 Detail: err.Error(),
375 })
376 return
377 }
378
379 // Block system users from sending custom notifications
380 user, err := api.Database.GetUserByID(ctx, apiKey.UserID)
381 if err != nil {
382 api.Logger.Error(ctx, "send custom notification", slog.Error(err))
383 httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
384 Message: "Failed to send custom notification",
385 Detail: err.Error(),
386 })
387 return
388 }
389 if user.IsSystem {
390 api.Logger.Error(ctx, "send custom notification: system user is not allowed",
391 slog.F("id", user.ID.String()), slog.F("name", user.Name))
392 httpapi.Write(ctx, rw, http.StatusForbidden, codersdk.Response{
393 Message: "Forbidden",
394 Detail: "System users cannot send custom notifications.",
395 })
396 return
397 }
398
399 if _, err := api.NotificationsEnqueuer.EnqueueWithData(
400 //nolint:gocritic // We need to be notifier to send the notification.
401 dbauthz.AsNotifier(ctx),
402 user.ID,
403 notifications.TemplateCustomNotification,
404 map[string]string{
405 "custom_title": req.Content.Title,
406 "custom_message": req.Content.Message,
407 },
408 map[string]any{
409 // Current dedupe is done via an hash of (template, user, method, payload, targets, day).
410 // Include a minute-bucketed timestamp to bypass per-day dedupe for self-sends,
411 // letting the caller resend identical content the same day (but not more than
412 // once per minute).
413 // TODO(ssncferreira): When custom notifications can target multiple users/roles,
414 // enforce proper deduplication across recipients to reduce noise and prevent spam.

Callers

nothing calls this directly

Calls 11

ValidateMethod · 0.95
APIKeyFunction · 0.92
ReadFunction · 0.92
WriteFunction · 0.92
AsNotifierFunction · 0.92
ContextMethod · 0.65
GetUserByIDMethod · 0.65
EnqueueWithDataMethod · 0.65
ErrorMethod · 0.45
StringMethod · 0.45
WriteHeaderMethod · 0.45

Tested by

no test coverage detected