Allow arbitrary responses from form-encoded POST

Useful for returning full objects
This commit is contained in:
Eli Ribble 2026-04-01 21:34:17 +00:00
parent a89a4fbec5
commit 4145944b1b
No known key found for this signature in database
2 changed files with 28 additions and 16 deletions

View file

@ -126,23 +126,29 @@ func authenticatedHandlerJSONSlice[T any](f handlerFunctionGetSlice[T]) http.Han
}
type handlerFunctionPost[ReqType any] func(context.Context, *http.Request, ReqType) (string, *nhttp.ErrorWithStatus)
type handlerFunctionPostAuthenticated[ReqType any] func(context.Context, *http.Request, platform.User, ReqType) (string, *nhttp.ErrorWithStatus)
type handlerFunctionPostAuthenticated[RequestType any, ResponseType any] func(context.Context, *http.Request, platform.User, RequestType) (ResponseType, *nhttp.ErrorWithStatus)
func authenticatedHandlerJSONPost[ReqType any](f handlerFunctionPostAuthenticated[ReqType]) http.Handler {
func authenticatedHandlerJSONPost[RequestType any, ResponseType any](f handlerFunctionPostAuthenticated[RequestType, ResponseType]) http.Handler {
return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u platform.User) {
w.Header().Set("Content-Type", "application/json")
req, e := parseRequest[ReqType](r)
req, e := parseRequest[RequestType](r)
if e != nil {
serializeError(w, e)
return
}
ctx := r.Context()
path, e := f(ctx, r, u, *req)
resp, e := f(ctx, r, u, *req)
if e != nil {
serializeError(w, e)
return
}
http.Redirect(w, r, path, http.StatusFound)
body, err := json.Marshal(resp)
if err != nil {
log.Error().Err(err).Msg("failed to marshal json")
http.Error(w, "{\"message\": \"failed to marshal json\"}", http.StatusInternalServerError)
return
}
w.Write(body)
})
}
@ -214,7 +220,7 @@ type postMultipartResponse struct {
URI string `json:"uri"`
}
func authenticatedHandlerPostMultipart(f handlerFunctionPostAuthenticated[[]file.Upload], collection file.Collection) http.Handler {
func authenticatedHandlerPostMultipart[ResponseType any](f handlerFunctionPostAuthenticated[[]file.Upload, ResponseType], collection file.Collection) http.Handler {
return auth.NewEnsureAuth(func(w http.ResponseWriter, r *http.Request, u platform.User) {
err := r.ParseMultipartForm(32 << 10) // 32 MB buffer
if err != nil {
@ -235,14 +241,12 @@ func authenticatedHandlerPostMultipart(f handlerFunctionPostAuthenticated[[]file
}
*/
ctx := r.Context()
path, e := f(ctx, r, u, uploads)
resp, e := f(ctx, r, u, uploads)
if e != nil {
http.Error(w, e.Error(), e.Status)
return
}
body, err := json.Marshal(postMultipartResponse{
URI: path,
})
body, err := json.Marshal(resp)
if err != nil {
log.Error().Err(err).Msg("failed to marshal json")
http.Error(w, "{\"message\": \"failed to marshal json\"}", http.StatusInternalServerError)

View file

@ -2,7 +2,6 @@ package resource
import (
"context"
"fmt"
"net/http"
nhttp "github.com/Gleipnir-Technology/nidus-sync/http"
@ -21,6 +20,9 @@ func Avatar(r *router) *avatarR {
type avatarR struct {
router *router
}
type avatar struct {
URI string `json:"uri"`
}
func (res *avatarR) ByIDGet(ctx context.Context, r *http.Request, u platform.User) (file.Collection, uuid.UUID, *nhttp.ErrorWithStatus) {
vars := mux.Vars(r)
@ -31,17 +33,23 @@ func (res *avatarR) ByIDGet(ctx context.Context, r *http.Request, u platform.Use
}
return file.CollectionAvatar, uid, nil
}
func (res *avatarR) Create(ctx context.Context, r *http.Request, u platform.User, uploads []file.Upload) (string, *nhttp.ErrorWithStatus) {
func (res *avatarR) Create(ctx context.Context, r *http.Request, u platform.User, uploads []file.Upload) (*avatar, *nhttp.ErrorWithStatus) {
if len(uploads) == 0 {
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "No upload found")
}
if len(uploads) != 1 {
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "You must only submit one file at a time")
}
upload := uploads[0]
err := platform.AvatarCreate(r.Context(), u, upload)
if err != nil {
return "", nhttp.NewErrorStatus(http.StatusBadRequest, "Create avatar: %w", err)
return nil, nhttp.NewErrorStatus(http.StatusBadRequest, "Create avatar: %w", err)
}
return fmt.Sprintf("/avatar/%s", upload.UUID.String()), nil
uri, err := res.router.UUIDToURI("avatar.ByIDGet", &upload.UUID)
if err != nil {
return nil, nhttp.NewError("create uri: %w", err)
}
return &avatar{
URI: *uri,
}, nil
}