package adminapi import ( "errors" "net/http" "github.com/dariuszjaniak/warp/server/internal/httputil" "github.com/dariuszjaniak/warp/server/internal/servernotices" "github.com/dariuszjaniak/warp/server/internal/userapi" ) // serverNoticeRequest is the POST /server_notices body. type serverNoticeRequest struct { UserID string `json:"user_id"` // Content is an m.room.message content. A body is required; a missing // msgtype becomes m.text. Content map[string]any `json:"content"` } // handlePostServerNotice implements POST /_warp/admin/v1/server_notices: // send a message from the server to one of its users. // // The notice goes into the user's server notice room, which is made the // first time and which the user is invited back to if they left it. The // user does not have to be online or to accept anything first: the // invite and the message wait for them. func (a *AdminAPI) handlePostServerNotice(w http.ResponseWriter, r *http.Request, auth userapi.Authenticated) error { if a.notices == nil { return httputil.NewError(http.StatusConflict, httputil.ErrCodeForbidden, "Server notices are not configured (server_notices.enabled is false, or the server has no signing key)") } var req serverNoticeRequest if err := httputil.DecodeJSON(w, r, &req); err != nil { return err } if req.UserID == "" { return httputil.MissingParam("user_id is required") } if body, _ := req.Content["body"].(string); body == "" { return httputil.MissingParam("content.body is required") } localpart, err := a.users.ParseLocalUserID(req.UserID) if err != nil { return httputil.InvalidParam("%s is not a user of this server", req.UserID) } roomID, eventID, err := a.notices.Send(r.Context(), localpart, req.Content) switch { case errors.Is(err, servernotices.ErrNoSuchUser): return httputil.NotFound("No such user") case errors.Is(err, servernotices.ErrDeactivated): return httputil.Forbidden("%s is deactivated", req.UserID) case err != nil: return roomError(err) } a.audit(r.Context(), auth, auditServerNotice, a.users.UserID(localpart), map[string]any{ "room_id": roomID, "event_id": eventID, }) httputil.WriteJSON(w, http.StatusOK, map[string]string{"room_id": roomID, "event_id": eventID}) return nil }