From 46a4e5a8ca46335661eb762c7c39dcea0bb5e9d0 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:02:35 -0800 Subject: [PATCH 1/7] openapi: add combobulate endpoint --- openapi.yaml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openapi.yaml b/openapi.yaml index 7a2d1fa..4e3e153 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -184,6 +184,29 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /maps/{MapID}/combobulate: + post: + summary: Queue a map for combobulator processing + operationId: combobulate + tags: + - Maps + parameters: + - name: MapID + in: path + required: true + schema: + type: integer + format: int64 + minimum: 0 + responses: + "204": + description: Successful response + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /maps/{MapID}/download: get: summary: Download the map asset -- 2.49.1 From 3927c525dd008ca8284bf8fbc7d6e924f4779a68 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:02:51 -0800 Subject: [PATCH 2/7] openapi: generate --- pkg/api/oas_client_gen.go | 132 ++++++++++++++++++ pkg/api/oas_handlers_gen.go | 200 +++++++++++++++++++++++++++ pkg/api/oas_operations_gen.go | 1 + pkg/api/oas_parameters_gen.go | 83 +++++++++++ pkg/api/oas_response_decoders_gen.go | 60 ++++++++ pkg/api/oas_response_encoders_gen.go | 7 + pkg/api/oas_router_gen.go | 198 ++++++++++++++++++-------- pkg/api/oas_schemas_gen.go | 3 + pkg/api/oas_security_gen.go | 1 + pkg/api/oas_server_gen.go | 6 + pkg/api/oas_unimplemented_gen.go | 9 ++ 11 files changed, 641 insertions(+), 59 deletions(-) diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index 9451c01..1dc24a9 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -193,6 +193,12 @@ type Invoker interface { // // POST /usernames BatchUsernames(ctx context.Context, request *BatchUsernamesReq) (*BatchUsernamesOK, error) + // Combobulate invokes combobulate operation. + // + // Queue a map for combobulator processing. + // + // POST /maps/{MapID}/combobulate + Combobulate(ctx context.Context, params CombobulateParams) error // CreateMapfix invokes createMapfix operation. // // Trigger the validator to create a mapfix. @@ -3722,6 +3728,132 @@ func (c *Client) sendBatchUsernames(ctx context.Context, request *BatchUsernames return result, nil } +// Combobulate invokes combobulate operation. +// +// Queue a map for combobulator processing. +// +// POST /maps/{MapID}/combobulate +func (c *Client) Combobulate(ctx context.Context, params CombobulateParams) error { + _, err := c.sendCombobulate(ctx, params) + return err +} + +func (c *Client) sendCombobulate(ctx context.Context, params CombobulateParams) (res *CombobulateNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("combobulate"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.URLTemplateKey.String("/maps/{MapID}/combobulate"), + } + otelAttrs = append(otelAttrs, c.cfg.Attributes...) + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, CombobulateOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [3]string + pathParts[0] = "/maps/" + { + // Encode "MapID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "MapID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.MapID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/combobulate" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + { + type bitset = [1]uint8 + var satisfied bitset + { + stage = "Security:CookieAuth" + switch err := c.securityCookieAuth(ctx, CombobulateOperation, r); { + case err == nil: // if NO error + satisfied[0] |= 1 << 0 + case errors.Is(err, ogenerrors.ErrSkipClientSecurity): + // Skip this security. + default: + return res, errors.Wrap(err, "security \"CookieAuth\"") + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied + } + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + body := resp.Body + defer body.Close() + + stage = "DecodeResponse" + result, err := decodeCombobulateResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // CreateMapfix invokes createMapfix operation. // // Trigger the validator to create a mapfix. diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 9db5b66..04a0de0 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -5298,6 +5298,206 @@ func (s *Server) handleBatchUsernamesRequest(args [0]string, argsEscaped bool, w } } +// handleCombobulateRequest handles combobulate operation. +// +// Queue a map for combobulator processing. +// +// POST /maps/{MapID}/combobulate +func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("combobulate"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/maps/{MapID}/combobulate"), + } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), CombobulateOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code < 100 || code >= 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: CombobulateOperation, + ID: "combobulate", + } + ) + { + type bitset = [1]uint8 + var satisfied bitset + { + sctx, ok, err := s.securityCookieAuth(ctx, CombobulateOperation, r) + if err != nil { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Security: "CookieAuth", + Err: err, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security:CookieAuth", err) + } + return + } + if ok { + satisfied[0] |= 1 << 0 + ctx = sctx + } + } + + if ok := func() bool { + nextRequirement: + for _, requirement := range []bitset{ + {0b00000001}, + } { + for i, mask := range requirement { + if satisfied[i]&mask != mask { + continue nextRequirement + } + } + return true + } + return false + }(); !ok { + err = &ogenerrors.SecurityError{ + OperationContext: opErrContext, + Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied, + } + if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil { + defer recordError("Security", err) + } + return + } + } + params, err := decodeCombobulateParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var rawBody []byte + + var response *CombobulateNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: CombobulateOperation, + OperationSummary: "Queue a map for combobulator processing", + OperationID: "combobulate", + Body: nil, + RawBody: rawBody, + Params: middleware.Parameters{ + { + Name: "MapID", + In: "path", + }: params.MapID, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = CombobulateParams + Response = *CombobulateNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackCombobulateParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.Combobulate(ctx, params) + return response, err + }, + ) + } else { + err = s.h.Combobulate(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeCombobulateResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleCreateMapfixRequest handles createMapfix operation. // // Trigger the validator to create a mapfix. diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index f251574..df65845 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -33,6 +33,7 @@ const ( BatchAssetThumbnailsOperation OperationName = "BatchAssetThumbnails" BatchUserThumbnailsOperation OperationName = "BatchUserThumbnails" BatchUsernamesOperation OperationName = "BatchUsernames" + CombobulateOperation OperationName = "Combobulate" CreateMapfixOperation OperationName = "CreateMapfix" CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment" CreateScriptOperation OperationName = "CreateScript" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go index 8703b44..fbfc95c 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/api/oas_parameters_gen.go @@ -2030,6 +2030,89 @@ func decodeActionSubmissionValidatedParams(args [1]string, argsEscaped bool, r * return params, nil } +// CombobulateParams is parameters of combobulate operation. +type CombobulateParams struct { + MapID int64 +} + +func unpackCombobulateParams(packed middleware.Parameters) (params CombobulateParams) { + { + key := middleware.ParameterKey{ + Name: "MapID", + In: "path", + } + params.MapID = packed[key].(int64) + } + return params +} + +func decodeCombobulateParams(args [1]string, argsEscaped bool, r *http.Request) (params CombobulateParams, _ error) { + // Decode path: MapID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "MapID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.MapID = c + return nil + }(); err != nil { + return err + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + Pattern: nil, + }).Validate(int64(params.MapID)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "MapID", + In: "path", + Err: err, + } + } + return params, nil +} + // CreateMapfixAuditCommentParams is parameters of createMapfixAuditComment operation. type CreateMapfixAuditCommentParams struct { // The unique identifier for a mapfix. diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index 9134132..0429402 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -1733,6 +1733,66 @@ func decodeBatchUsernamesResponse(resp *http.Response) (res *BatchUsernamesOK, _ return res, errors.Wrap(defRes, "error") } +func decodeCombobulateResponse(resp *http.Response) (res *CombobulateNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &CombobulateNoContent{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeCreateMapfixResponse(resp *http.Response) (res *OperationID, _ error) { switch resp.StatusCode { case 201: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index aa75e85..551e412 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -225,6 +225,13 @@ func encodeBatchUsernamesResponse(response *BatchUsernamesOK, w http.ResponseWri return nil } +func encodeCombobulateResponse(response *CombobulateNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + func encodeCreateMapfixResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(201) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index f44d473..50530dc 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -11,37 +11,37 @@ import ( ) var ( - rn42AllowedHeaders = map[string]string{ - "POST": "Content-Type", - } - rn44AllowedHeaders = map[string]string{ - "POST": "Content-Type", - } - rn83AllowedHeaders = map[string]string{ - "PATCH": "Content-Type", - } - rn73AllowedHeaders = map[string]string{ + rn46AllowedHeaders = map[string]string{ "POST": "Content-Type", } rn48AllowedHeaders = map[string]string{ "POST": "Content-Type", } - rn56AllowedHeaders = map[string]string{ + rn85AllowedHeaders = map[string]string{ + "PATCH": "Content-Type", + } + rn75AllowedHeaders = map[string]string{ "POST": "Content-Type", } - rn46AllowedHeaders = map[string]string{ + rn52AllowedHeaders = map[string]string{ "POST": "Content-Type", } - rn54AllowedHeaders = map[string]string{ - "POST": "Content-Type", - } - rn49AllowedHeaders = map[string]string{ + rn60AllowedHeaders = map[string]string{ "POST": "Content-Type", } rn50AllowedHeaders = map[string]string{ "POST": "Content-Type", } - rn52AllowedHeaders = map[string]string{ + rn58AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn53AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn54AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn56AllowedHeaders = map[string]string{ "POST": "Content-Type", } rn38AllowedHeaders = map[string]string{ @@ -135,7 +135,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "GET,POST", - allowedHeaders: rn42AllowedHeaders, + allowedHeaders: rn46AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -248,7 +248,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "POST", - allowedHeaders: rn44AllowedHeaders, + allowedHeaders: rn48AllowedHeaders, acceptPost: "text/plain", acceptPatch: "", }) @@ -304,7 +304,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "PATCH", - allowedHeaders: rn83AllowedHeaders, + allowedHeaders: rn85AllowedHeaders, acceptPost: "", acceptPatch: "text/plain", }) @@ -838,31 +838,72 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } switch elem[0] { - case '/': // Prefix: "/download" + case '/': // Prefix: "/" - if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { elem = elem[l:] } else { break } if len(elem) == 0 { - // Leaf node. - switch r.Method { - case "GET": - s.handleDownloadMapAssetRequest([1]string{ - args[0], - }, elemIsEscaped, w, r) - default: - s.notAllowed(w, r, notAllowedParams{ - allowedMethods: "GET", - allowedHeaders: nil, - acceptPost: "", - acceptPatch: "", - }) + break + } + switch elem[0] { + case 'c': // Prefix: "combobulate" + + if l := len("combobulate"); len(elem) >= l && elem[0:l] == "combobulate" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleCombobulateRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) + } + + return + } + + case 'd': // Prefix: "download" + + if l := len("download"); len(elem) >= l && elem[0:l] == "download" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "GET": + s.handleDownloadMapAssetRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) + } + + return } - return } } @@ -923,7 +964,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "POST", - allowedHeaders: rn73AllowedHeaders, + allowedHeaders: rn75AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -973,7 +1014,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "GET,POST", - allowedHeaders: rn48AllowedHeaders, + allowedHeaders: rn52AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1017,7 +1058,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "DELETE,GET,POST", - allowedHeaders: rn56AllowedHeaders, + allowedHeaders: rn60AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1045,7 +1086,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "GET,POST", - allowedHeaders: rn46AllowedHeaders, + allowedHeaders: rn50AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1089,7 +1130,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "DELETE,GET,POST", - allowedHeaders: rn54AllowedHeaders, + allowedHeaders: rn58AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1233,7 +1274,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "GET,POST", - allowedHeaders: rn49AllowedHeaders, + allowedHeaders: rn53AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1258,7 +1299,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "POST", - allowedHeaders: rn50AllowedHeaders, + allowedHeaders: rn54AllowedHeaders, acceptPost: "application/json", acceptPatch: "", }) @@ -1371,7 +1412,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { default: s.notAllowed(w, r, notAllowedParams{ allowedMethods: "POST", - allowedHeaders: rn52AllowedHeaders, + allowedHeaders: rn56AllowedHeaders, acceptPost: "text/plain", acceptPatch: "", }) @@ -2786,29 +2827,68 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } } switch elem[0] { - case '/': // Prefix: "/download" + case '/': // Prefix: "/" - if l := len("/download"); len(elem) >= l && elem[0:l] == "/download" { + if l := len("/"); len(elem) >= l && elem[0:l] == "/" { elem = elem[l:] } else { break } if len(elem) == 0 { - // Leaf node. - switch method { - case "GET": - r.name = DownloadMapAssetOperation - r.summary = "Download the map asset" - r.operationID = "downloadMapAsset" - r.operationGroup = "" - r.pathPattern = "/maps/{MapID}/download" - r.args = args - r.count = 1 - return r, true - default: - return + break + } + switch elem[0] { + case 'c': // Prefix: "combobulate" + + if l := len("combobulate"); len(elem) >= l && elem[0:l] == "combobulate" { + elem = elem[l:] + } else { + break } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = CombobulateOperation + r.summary = "Queue a map for combobulator processing" + r.operationID = "combobulate" + r.operationGroup = "" + r.pathPattern = "/maps/{MapID}/combobulate" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + + case 'd': // Prefix: "download" + + if l := len("download"); len(elem) >= l && elem[0:l] == "download" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "GET": + r.name = DownloadMapAssetOperation + r.summary = "Download the map asset" + r.operationID = "downloadMapAsset" + r.operationGroup = "" + r.pathPattern = "/maps/{MapID}/download" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + } } diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 3f100e0..4092020 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -441,6 +441,9 @@ func (s *BatchUsernamesReq) SetUserIds(val []uint64) { s.UserIds = val } +// CombobulateNoContent is response for Combobulate operation. +type CombobulateNoContent struct{} + type CookieAuth struct { APIKey string Roles []string diff --git a/pkg/api/oas_security_gen.go b/pkg/api/oas_security_gen.go index f299a04..bce84f3 100644 --- a/pkg/api/oas_security_gen.go +++ b/pkg/api/oas_security_gen.go @@ -58,6 +58,7 @@ var operationRolesCookieAuth = map[string][]string{ ActionSubmissionTriggerUploadOperation: []string{}, ActionSubmissionTriggerValidateOperation: []string{}, ActionSubmissionValidatedOperation: []string{}, + CombobulateOperation: []string{}, CreateMapfixOperation: []string{}, CreateMapfixAuditCommentOperation: []string{}, CreateScriptOperation: []string{}, diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index 707c53f..4da38ab 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -173,6 +173,12 @@ type Handler interface { // // POST /usernames BatchUsernames(ctx context.Context, req *BatchUsernamesReq) (*BatchUsernamesOK, error) + // Combobulate implements combobulate operation. + // + // Queue a map for combobulator processing. + // + // POST /maps/{MapID}/combobulate + Combobulate(ctx context.Context, params CombobulateParams) error // CreateMapfix implements createMapfix operation. // // Trigger the validator to create a mapfix. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index dc5a3fa..1e29290 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -259,6 +259,15 @@ func (UnimplementedHandler) BatchUsernames(ctx context.Context, req *BatchUserna return r, ht.ErrNotImplemented } +// Combobulate implements combobulate operation. +// +// Queue a map for combobulator processing. +// +// POST /maps/{MapID}/combobulate +func (UnimplementedHandler) Combobulate(ctx context.Context, params CombobulateParams) error { + return ht.ErrNotImplemented +} + // CreateMapfix implements createMapfix operation. // // Trigger the validator to create a mapfix. -- 2.49.1 From 57654ad9a6ef87ea7e726188250b964bfe8ca301 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:04:34 -0800 Subject: [PATCH 3/7] web_api: combobulate --- pkg/web_api/maps.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index 5764f7c..5ad7cd1 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -119,6 +119,28 @@ func (svc *Service) SeedCombobulator(ctx context.Context) error { return nil } +// Combobulate implements combobulate operation. +// +// Queue a map for combobulator processing. +// +// POST /maps-admin/combobulate +func (svc *Service) Combobulate(ctx context.Context, params api.CombobulateParams) error { + userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle) + if !ok { + return ErrUserInfo + } + + has_role, err := userInfo.HasRoleSubmissionRelease() + if err != nil { + return err + } + if !has_role { + return ErrPermissionDeniedNeedRoleSubmissionRelease + } + + return svc.inner.NatsSeedCombobulator(uint64(params.MapID)); +} + // DownloadMapAsset invokes downloadMapAsset operation. // // Download the map asset. -- 2.49.1 From a425524fdd347ef627cf043f359524330fd92527 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:06:52 -0800 Subject: [PATCH 4/7] openapi: rename --- openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi.yaml b/openapi.yaml index 4e3e153..3aae3bc 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -187,7 +187,7 @@ paths: /maps/{MapID}/combobulate: post: summary: Queue a map for combobulator processing - operationId: combobulate + operationId: combobulateMap tags: - Maps parameters: -- 2.49.1 From 1dbf4fc745dba8dfc4eae993d7aeefee00a1a661 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:07:01 -0800 Subject: [PATCH 5/7] openapi: generate --- pkg/api/oas_client_gen.go | 20 ++++++++-------- pkg/api/oas_handlers_gen.go | 34 ++++++++++++++-------------- pkg/api/oas_operations_gen.go | 2 +- pkg/api/oas_parameters_gen.go | 8 +++---- pkg/api/oas_response_decoders_gen.go | 4 ++-- pkg/api/oas_response_encoders_gen.go | 2 +- pkg/api/oas_router_gen.go | 6 ++--- pkg/api/oas_schemas_gen.go | 4 ++-- pkg/api/oas_security_gen.go | 2 +- pkg/api/oas_server_gen.go | 4 ++-- pkg/api/oas_unimplemented_gen.go | 4 ++-- 11 files changed, 45 insertions(+), 45 deletions(-) diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index 1dc24a9..002aa22 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -193,12 +193,12 @@ type Invoker interface { // // POST /usernames BatchUsernames(ctx context.Context, request *BatchUsernamesReq) (*BatchUsernamesOK, error) - // Combobulate invokes combobulate operation. + // CombobulateMap invokes combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps/{MapID}/combobulate - Combobulate(ctx context.Context, params CombobulateParams) error + CombobulateMap(ctx context.Context, params CombobulateMapParams) error // CreateMapfix invokes createMapfix operation. // // Trigger the validator to create a mapfix. @@ -3728,19 +3728,19 @@ func (c *Client) sendBatchUsernames(ctx context.Context, request *BatchUsernames return result, nil } -// Combobulate invokes combobulate operation. +// CombobulateMap invokes combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps/{MapID}/combobulate -func (c *Client) Combobulate(ctx context.Context, params CombobulateParams) error { - _, err := c.sendCombobulate(ctx, params) +func (c *Client) CombobulateMap(ctx context.Context, params CombobulateMapParams) error { + _, err := c.sendCombobulateMap(ctx, params) return err } -func (c *Client) sendCombobulate(ctx context.Context, params CombobulateParams) (res *CombobulateNoContent, err error) { +func (c *Client) sendCombobulateMap(ctx context.Context, params CombobulateMapParams) (res *CombobulateMapNoContent, err error) { otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("combobulate"), + otelogen.OperationID("combobulateMap"), semconv.HTTPRequestMethodKey.String("POST"), semconv.URLTemplateKey.String("/maps/{MapID}/combobulate"), } @@ -3758,7 +3758,7 @@ func (c *Client) sendCombobulate(ctx context.Context, params CombobulateParams) c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) // Start a span for this request. - ctx, span := c.cfg.Tracer.Start(ctx, CombobulateOperation, + ctx, span := c.cfg.Tracer.Start(ctx, CombobulateMapOperation, trace.WithAttributes(otelAttrs...), clientSpanKind, ) @@ -3809,7 +3809,7 @@ func (c *Client) sendCombobulate(ctx context.Context, params CombobulateParams) var satisfied bitset { stage = "Security:CookieAuth" - switch err := c.securityCookieAuth(ctx, CombobulateOperation, r); { + switch err := c.securityCookieAuth(ctx, CombobulateMapOperation, r); { case err == nil: // if NO error satisfied[0] |= 1 << 0 case errors.Is(err, ogenerrors.ErrSkipClientSecurity): @@ -3846,7 +3846,7 @@ func (c *Client) sendCombobulate(ctx context.Context, params CombobulateParams) defer body.Close() stage = "DecodeResponse" - result, err := decodeCombobulateResponse(resp) + result, err := decodeCombobulateMapResponse(resp) if err != nil { return res, errors.Wrap(err, "decode response") } diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 04a0de0..ef3b979 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -5298,16 +5298,16 @@ func (s *Server) handleBatchUsernamesRequest(args [0]string, argsEscaped bool, w } } -// handleCombobulateRequest handles combobulate operation. +// handleCombobulateMapRequest handles combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps/{MapID}/combobulate -func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { +func (s *Server) handleCombobulateMapRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { statusWriter := &codeRecorder{ResponseWriter: w} w = statusWriter otelAttrs := []attribute.KeyValue{ - otelogen.OperationID("combobulate"), + otelogen.OperationID("combobulateMap"), semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/maps/{MapID}/combobulate"), } @@ -5315,7 +5315,7 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. - ctx, span := s.cfg.Tracer.Start(r.Context(), CombobulateOperation, + ctx, span := s.cfg.Tracer.Start(r.Context(), CombobulateMapOperation, trace.WithAttributes(otelAttrs...), serverSpanKind, ) @@ -5370,15 +5370,15 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht } err error opErrContext = ogenerrors.OperationContext{ - Name: CombobulateOperation, - ID: "combobulate", + Name: CombobulateMapOperation, + ID: "combobulateMap", } ) { type bitset = [1]uint8 var satisfied bitset { - sctx, ok, err := s.securityCookieAuth(ctx, CombobulateOperation, r) + sctx, ok, err := s.securityCookieAuth(ctx, CombobulateMapOperation, r) if err != nil { err = &ogenerrors.SecurityError{ OperationContext: opErrContext, @@ -5420,7 +5420,7 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht return } } - params, err := decodeCombobulateParams(args, argsEscaped, r) + params, err := decodeCombobulateMapParams(args, argsEscaped, r) if err != nil { err = &ogenerrors.DecodeParamsError{ OperationContext: opErrContext, @@ -5433,13 +5433,13 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht var rawBody []byte - var response *CombobulateNoContent + var response *CombobulateMapNoContent if m := s.cfg.Middleware; m != nil { mreq := middleware.Request{ Context: ctx, - OperationName: CombobulateOperation, + OperationName: CombobulateMapOperation, OperationSummary: "Queue a map for combobulator processing", - OperationID: "combobulate", + OperationID: "combobulateMap", Body: nil, RawBody: rawBody, Params: middleware.Parameters{ @@ -5453,8 +5453,8 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht type ( Request = struct{} - Params = CombobulateParams - Response = *CombobulateNoContent + Params = CombobulateMapParams + Response = *CombobulateMapNoContent ) response, err = middleware.HookMiddleware[ Request, @@ -5463,14 +5463,14 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht ]( m, mreq, - unpackCombobulateParams, + unpackCombobulateMapParams, func(ctx context.Context, request Request, params Params) (response Response, err error) { - err = s.h.Combobulate(ctx, params) + err = s.h.CombobulateMap(ctx, params) return response, err }, ) } else { - err = s.h.Combobulate(ctx, params) + err = s.h.CombobulateMap(ctx, params) } if err != nil { if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { @@ -5489,7 +5489,7 @@ func (s *Server) handleCombobulateRequest(args [1]string, argsEscaped bool, w ht return } - if err := encodeCombobulateResponse(response, w, span); err != nil { + if err := encodeCombobulateMapResponse(response, w, span); err != nil { defer recordError("EncodeResponse", err) if !errors.Is(err, ht.ErrInternalServerErrorResponse) { s.cfg.ErrorHandler(ctx, w, r, err) diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index df65845..43ba0ff 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -33,7 +33,7 @@ const ( BatchAssetThumbnailsOperation OperationName = "BatchAssetThumbnails" BatchUserThumbnailsOperation OperationName = "BatchUserThumbnails" BatchUsernamesOperation OperationName = "BatchUsernames" - CombobulateOperation OperationName = "Combobulate" + CombobulateMapOperation OperationName = "CombobulateMap" CreateMapfixOperation OperationName = "CreateMapfix" CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment" CreateScriptOperation OperationName = "CreateScript" diff --git a/pkg/api/oas_parameters_gen.go b/pkg/api/oas_parameters_gen.go index fbfc95c..32b100d 100644 --- a/pkg/api/oas_parameters_gen.go +++ b/pkg/api/oas_parameters_gen.go @@ -2030,12 +2030,12 @@ func decodeActionSubmissionValidatedParams(args [1]string, argsEscaped bool, r * return params, nil } -// CombobulateParams is parameters of combobulate operation. -type CombobulateParams struct { +// CombobulateMapParams is parameters of combobulateMap operation. +type CombobulateMapParams struct { MapID int64 } -func unpackCombobulateParams(packed middleware.Parameters) (params CombobulateParams) { +func unpackCombobulateMapParams(packed middleware.Parameters) (params CombobulateMapParams) { { key := middleware.ParameterKey{ Name: "MapID", @@ -2046,7 +2046,7 @@ func unpackCombobulateParams(packed middleware.Parameters) (params CombobulatePa return params } -func decodeCombobulateParams(args [1]string, argsEscaped bool, r *http.Request) (params CombobulateParams, _ error) { +func decodeCombobulateMapParams(args [1]string, argsEscaped bool, r *http.Request) (params CombobulateMapParams, _ error) { // Decode path: MapID. if err := func() error { param := args[0] diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index 0429402..dae8855 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -1733,11 +1733,11 @@ func decodeBatchUsernamesResponse(resp *http.Response) (res *BatchUsernamesOK, _ return res, errors.Wrap(defRes, "error") } -func decodeCombobulateResponse(resp *http.Response) (res *CombobulateNoContent, _ error) { +func decodeCombobulateMapResponse(resp *http.Response) (res *CombobulateMapNoContent, _ error) { switch resp.StatusCode { case 204: // Code 204. - return &CombobulateNoContent{}, nil + return &CombobulateMapNoContent{}, nil } // Convenient error response. defRes, err := func() (res *ErrorStatusCode, err error) { diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index 551e412..080467c 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -225,7 +225,7 @@ func encodeBatchUsernamesResponse(response *BatchUsernamesOK, w http.ResponseWri return nil } -func encodeCombobulateResponse(response *CombobulateNoContent, w http.ResponseWriter, span trace.Span) error { +func encodeCombobulateMapResponse(response *CombobulateMapNoContent, w http.ResponseWriter, span trace.Span) error { w.WriteHeader(204) span.SetStatus(codes.Ok, http.StatusText(204)) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index 50530dc..5ae69e5 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -862,7 +862,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Leaf node. switch r.Method { case "POST": - s.handleCombobulateRequest([1]string{ + s.handleCombobulateMapRequest([1]string{ args[0], }, elemIsEscaped, w, r) default: @@ -2851,9 +2851,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { // Leaf node. switch method { case "POST": - r.name = CombobulateOperation + r.name = CombobulateMapOperation r.summary = "Queue a map for combobulator processing" - r.operationID = "combobulate" + r.operationID = "combobulateMap" r.operationGroup = "" r.pathPattern = "/maps/{MapID}/combobulate" r.args = args diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index 4092020..89a4c70 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -441,8 +441,8 @@ func (s *BatchUsernamesReq) SetUserIds(val []uint64) { s.UserIds = val } -// CombobulateNoContent is response for Combobulate operation. -type CombobulateNoContent struct{} +// CombobulateMapNoContent is response for CombobulateMap operation. +type CombobulateMapNoContent struct{} type CookieAuth struct { APIKey string diff --git a/pkg/api/oas_security_gen.go b/pkg/api/oas_security_gen.go index bce84f3..9e10ff0 100644 --- a/pkg/api/oas_security_gen.go +++ b/pkg/api/oas_security_gen.go @@ -58,7 +58,7 @@ var operationRolesCookieAuth = map[string][]string{ ActionSubmissionTriggerUploadOperation: []string{}, ActionSubmissionTriggerValidateOperation: []string{}, ActionSubmissionValidatedOperation: []string{}, - CombobulateOperation: []string{}, + CombobulateMapOperation: []string{}, CreateMapfixOperation: []string{}, CreateMapfixAuditCommentOperation: []string{}, CreateScriptOperation: []string{}, diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index 4da38ab..fcafe01 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -173,12 +173,12 @@ type Handler interface { // // POST /usernames BatchUsernames(ctx context.Context, req *BatchUsernamesReq) (*BatchUsernamesOK, error) - // Combobulate implements combobulate operation. + // CombobulateMap implements combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps/{MapID}/combobulate - Combobulate(ctx context.Context, params CombobulateParams) error + CombobulateMap(ctx context.Context, params CombobulateMapParams) error // CreateMapfix implements createMapfix operation. // // Trigger the validator to create a mapfix. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index 1e29290..b8db61a 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -259,12 +259,12 @@ func (UnimplementedHandler) BatchUsernames(ctx context.Context, req *BatchUserna return r, ht.ErrNotImplemented } -// Combobulate implements combobulate operation. +// CombobulateMap implements combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps/{MapID}/combobulate -func (UnimplementedHandler) Combobulate(ctx context.Context, params CombobulateParams) error { +func (UnimplementedHandler) CombobulateMap(ctx context.Context, params CombobulateMapParams) error { return ht.ErrNotImplemented } -- 2.49.1 From f68a9492a81580191b9e309e164282379bafb465 Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:07:04 -0800 Subject: [PATCH 6/7] web_api: rename --- pkg/web_api/maps.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index 5ad7cd1..304c8ef 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -119,12 +119,12 @@ func (svc *Service) SeedCombobulator(ctx context.Context) error { return nil } -// Combobulate implements combobulate operation. +// CombobulateMap implements combobulateMap operation. // // Queue a map for combobulator processing. // // POST /maps-admin/combobulate -func (svc *Service) Combobulate(ctx context.Context, params api.CombobulateParams) error { +func (svc *Service) CombobulateMap(ctx context.Context, params api.CombobulateMapParams) error { userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle) if !ok { return ErrUserInfo -- 2.49.1 From ed12957f9a3a72e25c69f7ec1ff8998df2fbf62f Mon Sep 17 00:00:00 2001 From: Rhys Lloyd Date: Thu, 5 Mar 2026 09:08:40 -0800 Subject: [PATCH 7/7] web_api: fix comment --- pkg/web_api/maps.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index 304c8ef..b421d11 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -123,7 +123,7 @@ func (svc *Service) SeedCombobulator(ctx context.Context) error { // // Queue a map for combobulator processing. // -// POST /maps-admin/combobulate +// POST /maps/{MapID}/combobulate func (svc *Service) CombobulateMap(ctx context.Context, params api.CombobulateMapParams) error { userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle) if !ok { -- 2.49.1