package admin import ( "encoding/json" "net/http" "reflect" "codeberg.org/pronounscc/pronouns.cc/backend/log" "codeberg.org/pronounscc/pronouns.cc/backend/server" "github.com/aarondl/opt/omit" "github.com/go-chi/render" "github.com/google/uuid" ) const MaxReasonLength = 2048 type UserActionRequest struct { Type string `json:"type"` // `ignore`, `warn`, `suspend` ReportID omit.Val[int64] `json:"report_id"` // The report ID associated with this action, only required if type is ignore. Will close this report. Reason string `json:"reason"` // The reason for the action. Always logged for moderators, only shown to user for `warn` and `suspend` Clear struct { // Profile fields to clear DisplayName bool `json:"display_name"` Bio bool `json:"bio"` Links bool `json:"links"` Names []int `json:"names"` // Indexes of names to clear Pronouns []int `json:"pronouns"` // Indexes of pronouns to clear Fields []int `json:"fields"` // Indexes of fields to clear CustomPreferences []uuid.UUID `json:"custom_preferences"` // Custom preference IDs to clear // TODO: remove flags, maybe? } `json:"clear"` } const ( ActionTypeIgnore = "ignore" ActionTypeWarn = "warn" ActionTypeSuspend = "suspend" ) func (req UserActionRequest) Validate() (errs []server.ModelParseError) { switch req.Type { case ActionTypeIgnore, ActionTypeWarn, ActionTypeSuspend: default: errs = append(errs, server.NewModelParseErrorWithValues("type", "", []any{ActionTypeIgnore, ActionTypeSuspend, ActionTypeWarn}, req.Type)) } if req.Type != ActionTypeIgnore && req.Reason == "" { errs = append(errs, server.NewModelParseError("reason", "reason cannot be empty if type is not ignore")) } if req.Type == ActionTypeIgnore && req.ReportID.IsUnset() { errs = append(errs, server.NewModelParseError("report_id", "report_id cannot be empty if type is ignore")) } if req.Type == ActionTypeIgnore && (req.Clear.DisplayName || req.Clear.Bio || req.Clear.Links || len(req.Clear.Names) != 0 || len(req.Clear.Pronouns) != 0 || len(req.Clear.Fields) != 0 || len(req.Clear.CustomPreferences) != 0) { errs = append(errs, server.NewModelParseError("clear", "clear cannot be set if report is being ignored")) } return errs } func (s *Server) UserAction(w http.ResponseWriter, r *http.Request) (err error) { ctx := r.Context() claims, _ := server.ClaimsFromContext(ctx) var req UserActionRequest err = json.NewDecoder(r.Body).Decode(&req) if err != nil { // TODO: figure out why this isn't working log.Debug(reflect.TypeOf(err).String()) log.Debugf("%#v", err) log.Debugf("%T", err) if pe, ok := err.(*json.UnmarshalTypeError); ok { log.Debugf("value = %q, field = %q\n", pe.Value, pe.Field) } else { log.Debugf("type assertion for %T to *json.UnmarshalTypeError failed", err) } return server.NewV2Error(server.ErrBadRequest, "") } if errs := req.Validate(); len(errs) != 0 { return server.NewV2Error(server.ErrBadRequest, "", errs...) } render.JSON(w, r, claims) return nil }