From 078a3e4c4a4ddf86f37cbd693031e467281b9128 Mon Sep 17 00:00:00 2001 From: itzaname Date: Sun, 1 Mar 2026 17:41:11 -0500 Subject: [PATCH] Add map seed endpoint --- combobulator/src/main.rs | 20 +- combobulator/src/nats_types.rs | 10 +- combobulator/src/process.rs | 9 +- go.mod | 6 +- go.sum | 6 + openapi.yaml | 15 + pkg/api/oas_cfg_gen.go | 55 ++- pkg/api/oas_client_gen.go | 315 +++++++++++++---- pkg/api/oas_handlers_gen.go | 315 ++++++++++++++++- pkg/api/oas_operations_gen.go | 1 + pkg/api/oas_response_decoders_gen.go | 60 ++++ pkg/api/oas_response_encoders_gen.go | 9 + pkg/api/oas_router_gen.go | 487 ++++++++++++++++++++++++--- pkg/api/oas_schemas_gen.go | 3 + pkg/api/oas_security_gen.go | 23 ++ pkg/api/oas_server_gen.go | 6 + pkg/api/oas_unimplemented_gen.go | 9 + pkg/datastore/datastore.go | 1 + pkg/datastore/gormstore/maps.go | 8 + pkg/model/nats.go | 4 + pkg/service/maps.go | 4 + pkg/service/nats_maps.go | 21 ++ pkg/web_api/maps.go | 33 ++ 23 files changed, 1256 insertions(+), 164 deletions(-) create mode 100644 pkg/service/nats_maps.go diff --git a/combobulator/src/main.rs b/combobulator/src/main.rs index 529bf2f..cc356db 100644 --- a/combobulator/src/main.rs +++ b/combobulator/src/main.rs @@ -6,7 +6,7 @@ mod s3; const SUBJECT_MAPFIX_RELEASE:&str="maptest.mapfixes.release"; const SUBJECT_SUBMISSION_BATCHRELEASE:&str="maptest.submissions.batchrelease"; -const SUBJECT_SUBMISSION_RELEASE:&str="maptest.combobulator.submissions.release"; +const SUBJECT_SEED:&str="maptest.combobulator.seed"; #[derive(Debug)] pub enum StartupError{ @@ -55,22 +55,22 @@ async fn handle_message( message.ack().await.map_err(HandleMessageError::Ack)?; }, SUBJECT_SUBMISSION_BATCHRELEASE=>{ - // split batch into individual messages and republish + // split batch into individual seed messages let batch:nats_types::ReleaseSubmissionsBatchRequest=from_slice(&message.payload)?; println!("[combobulator] Splitting batch release (operation {}, {} submissions)", batch.OperationID,batch.Submissions.len()); for submission in batch.Submissions{ - let payload=serde_json::to_vec(&submission).map_err(HandleMessageError::Json)?; - jetstream.publish(SUBJECT_SUBMISSION_RELEASE,payload.into()) + let seed=nats_types::SeedCombobulatorRequest{AssetID:submission.UploadedAssetID}; + let payload=serde_json::to_vec(&seed).map_err(HandleMessageError::Json)?; + jetstream.publish(SUBJECT_SEED,payload.into()) .await.map_err(HandleMessageError::Publish)?; - println!("[combobulator] Published individual release for submission {}",submission.SubmissionID); + println!("[combobulator] Queued seed for asset {}",seed.AssetID); } - // ack the batch now that all individual messages are queued message.ack().await.map_err(HandleMessageError::Ack)?; }, - SUBJECT_SUBMISSION_RELEASE=>{ - let request:nats_types::ReleaseSubmissionRequest=from_slice(&message.payload)?; - processor.handle_submission_release(request).await.map_err(HandleMessageError::Process)?; + SUBJECT_SEED=>{ + let request:nats_types::SeedCombobulatorRequest=from_slice(&message.payload)?; + processor.handle_seed(request).await.map_err(HandleMessageError::Process)?; message.ack().await.map_err(HandleMessageError::Ack)?; }, other=>return Err(HandleMessageError::UnknownSubject(other.to_owned())), @@ -106,7 +106,7 @@ async fn main()->Result<(),StartupError>{ let filter_subjects=vec![ SUBJECT_MAPFIX_RELEASE.to_owned(), SUBJECT_SUBMISSION_BATCHRELEASE.to_owned(), - SUBJECT_SUBMISSION_RELEASE.to_owned(), + SUBJECT_SEED.to_owned(), ]; let nats_config=async_nats::jetstream::consumer::pull::Config{ diff --git a/combobulator/src/nats_types.rs b/combobulator/src/nats_types.rs index a6b6d99..4b99f94 100644 --- a/combobulator/src/nats_types.rs +++ b/combobulator/src/nats_types.rs @@ -7,8 +7,8 @@ pub struct ReleaseMapfixRequest{ pub TargetAssetID:u64, } -#[expect(nonstandard_style)] -#[derive(serde::Deserialize,serde::Serialize)] +#[expect(nonstandard_style,dead_code)] +#[derive(serde::Deserialize)] pub struct ReleaseSubmissionRequest{ pub SubmissionID:u64, pub ReleaseDate:i64, @@ -27,3 +27,9 @@ pub struct ReleaseSubmissionsBatchRequest{ pub Submissions:Vec, pub OperationID:u32, } + +#[expect(nonstandard_style)] +#[derive(serde::Deserialize,serde::Serialize)] +pub struct SeedCombobulatorRequest{ + pub AssetID:u64, +} diff --git a/combobulator/src/process.rs b/combobulator/src/process.rs index 356f099..da05776 100644 --- a/combobulator/src/process.rs +++ b/combobulator/src/process.rs @@ -131,10 +131,9 @@ impl Processor{ self.process_model(request.TargetAssetID).await } - /// Handle an individual submission release message. - pub async fn handle_submission_release(&self,request:crate::nats_types::ReleaseSubmissionRequest)->Result<(),Error>{ - println!("[combobulator] Processing submission {} (asset {})", - request.SubmissionID,request.UploadedAssetID); - self.process_model(request.UploadedAssetID).await + /// Handle a seed request (reprocess an existing map). + pub async fn handle_seed(&self,request:crate::nats_types::SeedCombobulatorRequest)->Result<(),Error>{ + println!("[combobulator] Seeding asset {}",request.AssetID); + self.process_model(request.AssetID).await } } diff --git a/go.mod b/go.mod index 61176ae..c384c54 100644 --- a/go.mod +++ b/go.mod @@ -20,9 +20,9 @@ require ( github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag v1.16.6 github.com/urfave/cli/v2 v2.27.6 - go.opentelemetry.io/otel v1.39.0 - go.opentelemetry.io/otel/metric v1.39.0 - go.opentelemetry.io/otel/trace v1.39.0 + go.opentelemetry.io/otel v1.40.0 + go.opentelemetry.io/otel/metric v1.40.0 + go.opentelemetry.io/otel/trace v1.40.0 google.golang.org/grpc v1.48.0 gorm.io/driver/postgres v1.6.0 gorm.io/gorm v1.25.12 diff --git a/go.sum b/go.sum index 096434b..2f68280 100644 --- a/go.sum +++ b/go.sum @@ -279,10 +279,16 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= diff --git a/openapi.yaml b/openapi.yaml index fb14d98..7a2d1fa 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -212,6 +212,21 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /maps-admin/seed-combobulator: + post: + summary: Queue all maps for combobulator processing + operationId: seedCombobulator + tags: + - Maps + responses: + "204": + description: Successful response + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /mapfixes: get: summary: Get list of mapfixes diff --git a/pkg/api/oas_cfg_gen.go b/pkg/api/oas_cfg_gen.go index 5dafb54..d8d3ddb 100644 --- a/pkg/api/oas_cfg_gen.go +++ b/pkg/api/oas_cfg_gen.go @@ -4,6 +4,7 @@ package api import ( "net/http" + "strings" ht "github.com/ogen-go/ogen/http" "github.com/ogen-go/ogen/middleware" @@ -82,18 +83,8 @@ func (o otelOptionFunc) applyServer(c *serverConfig) { func newServerConfig(opts ...ServerOption) serverConfig { cfg := serverConfig{ - NotFound: http.NotFound, - MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) { - status := http.StatusMethodNotAllowed - if r.Method == "OPTIONS" { - w.Header().Set("Access-Control-Allow-Methods", allowed) - w.Header().Set("Access-Control-Allow-Headers", "Content-Type") - status = http.StatusNoContent - } else { - w.Header().Set("Allow", allowed) - } - w.WriteHeader(status) - }, + NotFound: http.NotFound, + MethodNotAllowed: nil, ErrorHandler: ogenerrors.DefaultErrorHandler, Middleware: nil, MaxMultipartMemory: 32 << 20, // 32 MB @@ -116,8 +107,44 @@ func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) { s.cfg.NotFound(w, r) } -func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) { - s.cfg.MethodNotAllowed(w, r, allowed) +type notAllowedParams struct { + allowedMethods string + allowedHeaders map[string]string + acceptPost string + acceptPatch string +} + +func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, params notAllowedParams) { + h := w.Header() + isOptions := r.Method == "OPTIONS" + if isOptions { + h.Set("Access-Control-Allow-Methods", params.allowedMethods) + if params.allowedHeaders != nil { + m := r.Header.Get("Access-Control-Request-Method") + if m != "" { + allowedHeaders, ok := params.allowedHeaders[strings.ToUpper(m)] + if ok { + h.Set("Access-Control-Allow-Headers", allowedHeaders) + } + } + } + if params.acceptPost != "" { + h.Set("Accept-Post", params.acceptPost) + } + if params.acceptPatch != "" { + h.Set("Accept-Patch", params.acceptPatch) + } + } + if s.cfg.MethodNotAllowed != nil { + s.cfg.MethodNotAllowed(w, r, params.allowedMethods) + return + } + status := http.StatusNoContent + if !isOptions { + h.Set("Allow", params.allowedMethods) + status = http.StatusMethodNotAllowed + } + w.WriteHeader(status) } func (cfg serverConfig) baseServer() (s baseServer, err error) { diff --git a/pkg/api/oas_client_gen.go b/pkg/api/oas_client_gen.go index be72604..9451c01 100644 --- a/pkg/api/oas_client_gen.go +++ b/pkg/api/oas_client_gen.go @@ -17,7 +17,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.37.0" + semconv "go.opentelemetry.io/otel/semconv/v1.39.0" "go.opentelemetry.io/otel/trace" ) @@ -355,6 +355,12 @@ type Invoker interface { // // POST /release-submissions ReleaseSubmissions(ctx context.Context, request []ReleaseInfo) (*OperationID, error) + // SeedCombobulator invokes seedCombobulator operation. + // + // Queue all maps for combobulator processing. + // + // POST /maps-admin/seed-combobulator + SeedCombobulator(ctx context.Context) error // SessionRoles invokes sessionRoles operation. // // Get list of roles for the current session. @@ -423,14 +429,6 @@ type Client struct { sec SecuritySource baseClient } -type errorHandler interface { - NewError(ctx context.Context, err error) *ErrorStatusCode -} - -var _ Handler = struct { - errorHandler - *Client -}{} // NewClient initializes new Client defined by OAS. func NewClient(serverURL string, sec SecuritySource, opts ...ClientOption) (*Client, error) { @@ -580,7 +578,8 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixAcceptedResponse(resp) @@ -705,7 +704,8 @@ func (c *Client) sendActionMapfixReject(ctx context.Context, params ActionMapfix if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixRejectResponse(resp) @@ -830,7 +830,8 @@ func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params Acti if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixRequestChangesResponse(resp) @@ -956,7 +957,8 @@ func (c *Client) sendActionMapfixResetSubmitting(ctx context.Context, params Act if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixResetSubmittingResponse(resp) @@ -1081,7 +1083,8 @@ func (c *Client) sendActionMapfixRetryValidate(ctx context.Context, params Actio if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixRetryValidateResponse(resp) @@ -1206,7 +1209,8 @@ func (c *Client) sendActionMapfixRevoke(ctx context.Context, params ActionMapfix if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixRevokeResponse(resp) @@ -1331,7 +1335,8 @@ func (c *Client) sendActionMapfixTriggerRelease(ctx context.Context, params Acti if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixTriggerReleaseResponse(resp) @@ -1456,7 +1461,8 @@ func (c *Client) sendActionMapfixTriggerSubmit(ctx context.Context, params Actio if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixTriggerSubmitResponse(resp) @@ -1581,7 +1587,8 @@ func (c *Client) sendActionMapfixTriggerSubmitUnchecked(ctx context.Context, par if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixTriggerSubmitUncheckedResponse(resp) @@ -1706,7 +1713,8 @@ func (c *Client) sendActionMapfixTriggerUpload(ctx context.Context, params Actio if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixTriggerUploadResponse(resp) @@ -1831,7 +1839,8 @@ func (c *Client) sendActionMapfixTriggerValidate(ctx context.Context, params Act if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixTriggerValidateResponse(resp) @@ -1956,7 +1965,8 @@ func (c *Client) sendActionMapfixUploaded(ctx context.Context, params ActionMapf if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixUploadedResponse(resp) @@ -2081,7 +2091,8 @@ func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMap if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionMapfixValidatedResponse(resp) @@ -2206,7 +2217,8 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionAcceptedResponse(resp) @@ -2331,7 +2343,8 @@ func (c *Client) sendActionSubmissionReject(ctx context.Context, params ActionSu if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionRejectResponse(resp) @@ -2456,7 +2469,8 @@ func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionRequestChangesResponse(resp) @@ -2582,7 +2596,8 @@ func (c *Client) sendActionSubmissionResetSubmitting(ctx context.Context, params if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionResetSubmittingResponse(resp) @@ -2707,7 +2722,8 @@ func (c *Client) sendActionSubmissionRetryValidate(ctx context.Context, params A if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionRetryValidateResponse(resp) @@ -2832,7 +2848,8 @@ func (c *Client) sendActionSubmissionRevoke(ctx context.Context, params ActionSu if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionRevokeResponse(resp) @@ -2957,7 +2974,8 @@ func (c *Client) sendActionSubmissionTriggerSubmit(ctx context.Context, params A if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionTriggerSubmitResponse(resp) @@ -3082,7 +3100,8 @@ func (c *Client) sendActionSubmissionTriggerSubmitUnchecked(ctx context.Context, if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionTriggerSubmitUncheckedResponse(resp) @@ -3207,7 +3226,8 @@ func (c *Client) sendActionSubmissionTriggerUpload(ctx context.Context, params A if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionTriggerUploadResponse(resp) @@ -3332,7 +3352,8 @@ func (c *Client) sendActionSubmissionTriggerValidate(ctx context.Context, params if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionTriggerValidateResponse(resp) @@ -3458,7 +3479,8 @@ func (c *Client) sendActionSubmissionValidated(ctx context.Context, params Actio if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeActionSubmissionValidatedResponse(resp) @@ -3534,7 +3556,8 @@ func (c *Client) sendBatchAssetThumbnails(ctx context.Context, request *BatchAss if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeBatchAssetThumbnailsResponse(resp) @@ -3610,7 +3633,8 @@ func (c *Client) sendBatchUserThumbnails(ctx context.Context, request *BatchUser if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeBatchUserThumbnailsResponse(resp) @@ -3686,7 +3710,8 @@ func (c *Client) sendBatchUsernames(ctx context.Context, request *BatchUsernames if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeBatchUsernamesResponse(resp) @@ -3795,7 +3820,8 @@ func (c *Client) sendCreateMapfix(ctx context.Context, request *MapfixTriggerCre if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateMapfixResponse(resp) @@ -3923,7 +3949,8 @@ func (c *Client) sendCreateMapfixAuditComment(ctx context.Context, request Creat if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateMapfixAuditCommentResponse(resp) @@ -4032,7 +4059,8 @@ func (c *Client) sendCreateScript(ctx context.Context, request *ScriptCreate) (r if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateScriptResponse(resp) @@ -4141,7 +4169,8 @@ func (c *Client) sendCreateScriptPolicy(ctx context.Context, request *ScriptPoli if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateScriptPolicyResponse(resp) @@ -4250,7 +4279,8 @@ func (c *Client) sendCreateSubmission(ctx context.Context, request *SubmissionTr if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateSubmissionResponse(resp) @@ -4359,7 +4389,8 @@ func (c *Client) sendCreateSubmissionAdmin(ctx context.Context, request *Submiss if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateSubmissionAdminResponse(resp) @@ -4487,7 +4518,8 @@ func (c *Client) sendCreateSubmissionAuditComment(ctx context.Context, request C if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeCreateSubmissionAuditCommentResponse(resp) @@ -4611,7 +4643,8 @@ func (c *Client) sendDeleteScript(ctx context.Context, params DeleteScriptParams if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeDeleteScriptResponse(resp) @@ -4735,7 +4768,8 @@ func (c *Client) sendDeleteScriptPolicy(ctx context.Context, params DeleteScript if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeDeleteScriptPolicyResponse(resp) @@ -4860,7 +4894,8 @@ func (c *Client) sendDownloadMapAsset(ctx context.Context, params DownloadMapAss if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeDownloadMapAssetResponse(resp) @@ -4972,7 +5007,8 @@ func (c *Client) sendGetAssetThumbnail(ctx context.Context, params GetAssetThumb if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetAssetThumbnailResponse(resp) @@ -5063,7 +5099,8 @@ func (c *Client) sendGetMap(ctx context.Context, params GetMapParams) (res *Map, if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetMapResponse(resp) @@ -5154,7 +5191,8 @@ func (c *Client) sendGetMapfix(ctx context.Context, params GetMapfixParams) (res if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetMapfixResponse(resp) @@ -5278,7 +5316,8 @@ func (c *Client) sendGetOperation(ctx context.Context, params GetOperationParams if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetOperationResponse(resp) @@ -5369,7 +5408,8 @@ func (c *Client) sendGetScript(ctx context.Context, params GetScriptParams) (res if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetScriptResponse(resp) @@ -5460,7 +5500,8 @@ func (c *Client) sendGetScriptPolicy(ctx context.Context, params GetScriptPolicy if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetScriptPolicyResponse(resp) @@ -5533,7 +5574,8 @@ func (c *Client) sendGetStats(ctx context.Context) (res *Stats, err error) { if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetStatsResponse(resp) @@ -5624,7 +5666,8 @@ func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionPara if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetSubmissionResponse(resp) @@ -5736,7 +5779,8 @@ func (c *Client) sendGetUserThumbnail(ctx context.Context, params GetUserThumbna if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeGetUserThumbnailResponse(resp) @@ -5860,7 +5904,8 @@ func (c *Client) sendListMapfixAuditEvents(ctx context.Context, params ListMapfi if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListMapfixAuditEventsResponse(resp) @@ -6118,7 +6163,8 @@ func (c *Client) sendListMapfixes(ctx context.Context, params ListMapfixesParams if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListMapfixesResponse(resp) @@ -6291,7 +6337,8 @@ func (c *Client) sendListMaps(ctx context.Context, params ListMapsParams) (res [ if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListMapsResponse(resp) @@ -6447,7 +6494,8 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListScriptPolicyResponse(resp) @@ -6637,7 +6685,8 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams) if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListScriptsResponse(resp) @@ -6761,7 +6810,8 @@ func (c *Client) sendListSubmissionAuditEvents(ctx context.Context, params ListS if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListSubmissionAuditEventsResponse(resp) @@ -7019,7 +7069,8 @@ func (c *Client) sendListSubmissions(ctx context.Context, params ListSubmissions if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeListSubmissionsResponse(resp) @@ -7128,7 +7179,8 @@ func (c *Client) sendReleaseSubmissions(ctx context.Context, request []ReleaseIn if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeReleaseSubmissionsResponse(resp) @@ -7139,6 +7191,113 @@ func (c *Client) sendReleaseSubmissions(ctx context.Context, request []ReleaseIn return result, nil } +// SeedCombobulator invokes seedCombobulator operation. +// +// Queue all maps for combobulator processing. +// +// POST /maps-admin/seed-combobulator +func (c *Client) SeedCombobulator(ctx context.Context) error { + _, err := c.sendSeedCombobulator(ctx) + return err +} + +func (c *Client) sendSeedCombobulator(ctx context.Context) (res *SeedCombobulatorNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("seedCombobulator"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.URLTemplateKey.String("/maps-admin/seed-combobulator"), + } + 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, SeedCombobulatorOperation, + 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 [1]string + pathParts[0] = "/maps-admin/seed-combobulator" + 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, SeedCombobulatorOperation, 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 := decodeSeedCombobulatorResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // SessionRoles invokes sessionRoles operation. // // Get list of roles for the current session. @@ -7234,7 +7393,8 @@ func (c *Client) sendSessionRoles(ctx context.Context) (res *Roles, err error) { if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeSessionRolesResponse(resp) @@ -7340,7 +7500,8 @@ func (c *Client) sendSessionUser(ctx context.Context) (res *User, err error) { if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeSessionUserResponse(resp) @@ -7446,7 +7607,8 @@ func (c *Client) sendSessionValidate(ctx context.Context) (res bool, err error) if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeSessionValidateResponse(resp) @@ -7571,7 +7733,8 @@ func (c *Client) sendSetMapfixCompleted(ctx context.Context, params SetMapfixCom if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeSetMapfixCompletedResponse(resp) @@ -7696,7 +7859,8 @@ func (c *Client) sendSetSubmissionCompleted(ctx context.Context, params SetSubmi if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeSetSubmissionCompletedResponse(resp) @@ -7824,7 +7988,8 @@ func (c *Client) sendUpdateMapfixDescription(ctx context.Context, request Update if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeUpdateMapfixDescriptionResponse(resp) @@ -7981,7 +8146,8 @@ func (c *Client) sendUpdateMapfixModel(ctx context.Context, params UpdateMapfixM if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeUpdateMapfixModelResponse(resp) @@ -8108,7 +8274,8 @@ func (c *Client) sendUpdateScript(ctx context.Context, request *ScriptUpdate, pa if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeUpdateScriptResponse(resp) @@ -8235,7 +8402,8 @@ func (c *Client) sendUpdateScriptPolicy(ctx context.Context, request *ScriptPoli if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeUpdateScriptPolicyResponse(resp) @@ -8392,7 +8560,8 @@ func (c *Client) sendUpdateSubmissionModel(ctx context.Context, params UpdateSub if err != nil { return res, errors.Wrap(err, "do request") } - defer resp.Body.Close() + body := resp.Body + defer body.Close() stage = "DecodeResponse" result, err := decodeUpdateSubmissionModelResponse(resp) diff --git a/pkg/api/oas_handlers_gen.go b/pkg/api/oas_handlers_gen.go index 7373e99..9db5b66 100644 --- a/pkg/api/oas_handlers_gen.go +++ b/pkg/api/oas_handlers_gen.go @@ -15,7 +15,7 @@ import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" - semconv "go.opentelemetry.io/otel/semconv/v1.37.0" + semconv "go.opentelemetry.io/otel/semconv/v1.39.0" "go.opentelemetry.io/otel/trace" ) @@ -46,6 +46,8 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-validating"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixAcceptedOperation, @@ -244,6 +246,8 @@ func (s *Server) handleActionMapfixRejectRequest(args [1]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reject"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRejectOperation, @@ -442,6 +446,8 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/request-changes"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRequestChangesOperation, @@ -641,6 +647,8 @@ func (s *Server) handleActionMapfixResetSubmittingRequest(args [1]string, argsEs semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-submitting"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixResetSubmittingOperation, @@ -839,6 +847,8 @@ func (s *Server) handleActionMapfixRetryValidateRequest(args [1]string, argsEsca semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/retry-validate"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRetryValidateOperation, @@ -1037,6 +1047,8 @@ func (s *Server) handleActionMapfixRevokeRequest(args [1]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/revoke"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRevokeOperation, @@ -1235,6 +1247,8 @@ func (s *Server) handleActionMapfixTriggerReleaseRequest(args [1]string, argsEsc semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-release"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerReleaseOperation, @@ -1433,6 +1447,8 @@ func (s *Server) handleActionMapfixTriggerSubmitRequest(args [1]string, argsEsca semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-submit"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerSubmitOperation, @@ -1631,6 +1647,8 @@ func (s *Server) handleActionMapfixTriggerSubmitUncheckedRequest(args [1]string, semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-submit-unchecked"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerSubmitUncheckedOperation, @@ -1829,6 +1847,8 @@ func (s *Server) handleActionMapfixTriggerUploadRequest(args [1]string, argsEsca semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-upload"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerUploadOperation, @@ -2027,6 +2047,8 @@ func (s *Server) handleActionMapfixTriggerValidateRequest(args [1]string, argsEs semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/trigger-validate"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixTriggerValidateOperation, @@ -2225,6 +2247,8 @@ func (s *Server) handleActionMapfixUploadedRequest(args [1]string, argsEscaped b semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-releasing"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixUploadedOperation, @@ -2423,6 +2447,8 @@ func (s *Server) handleActionMapfixValidatedRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/reset-uploading"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixValidatedOperation, @@ -2621,6 +2647,8 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-validating"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionAcceptedOperation, @@ -2819,6 +2847,8 @@ func (s *Server) handleActionSubmissionRejectRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reject"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRejectOperation, @@ -3017,6 +3047,8 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/request-changes"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRequestChangesOperation, @@ -3216,6 +3248,8 @@ func (s *Server) handleActionSubmissionResetSubmittingRequest(args [1]string, ar semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-submitting"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionResetSubmittingOperation, @@ -3414,6 +3448,8 @@ func (s *Server) handleActionSubmissionRetryValidateRequest(args [1]string, args semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/retry-validate"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRetryValidateOperation, @@ -3612,6 +3648,8 @@ func (s *Server) handleActionSubmissionRevokeRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/revoke"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRevokeOperation, @@ -3810,6 +3848,8 @@ func (s *Server) handleActionSubmissionTriggerSubmitRequest(args [1]string, args semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-submit"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerSubmitOperation, @@ -4008,6 +4048,8 @@ func (s *Server) handleActionSubmissionTriggerSubmitUncheckedRequest(args [1]str semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-submit-unchecked"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerSubmitUncheckedOperation, @@ -4206,6 +4248,8 @@ func (s *Server) handleActionSubmissionTriggerUploadRequest(args [1]string, args semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-upload"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerUploadOperation, @@ -4404,6 +4448,8 @@ func (s *Server) handleActionSubmissionTriggerValidateRequest(args [1]string, ar semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/trigger-validate"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionTriggerValidateOperation, @@ -4603,6 +4649,8 @@ func (s *Server) handleActionSubmissionValidatedRequest(args [1]string, argsEsca semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/reset-uploading"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionValidatedOperation, @@ -4801,6 +4849,8 @@ func (s *Server) handleBatchAssetThumbnailsRequest(args [0]string, argsEscaped b semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/thumbnails/assets"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), BatchAssetThumbnailsOperation, @@ -4953,6 +5003,8 @@ func (s *Server) handleBatchUserThumbnailsRequest(args [0]string, argsEscaped bo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/thumbnails/users"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), BatchUserThumbnailsOperation, @@ -5105,6 +5157,8 @@ func (s *Server) handleBatchUsernamesRequest(args [0]string, argsEscaped bool, w semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/usernames"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), BatchUsernamesOperation, @@ -5257,6 +5311,8 @@ func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateMapfixOperation, @@ -5455,6 +5511,8 @@ func (s *Server) handleCreateMapfixAuditCommentRequest(args [1]string, argsEscap semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/comment"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateMapfixAuditCommentOperation, @@ -5668,6 +5726,8 @@ func (s *Server) handleCreateScriptRequest(args [0]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/scripts"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateScriptOperation, @@ -5866,6 +5926,8 @@ func (s *Server) handleCreateScriptPolicyRequest(args [0]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/script-policy"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateScriptPolicyOperation, @@ -6064,6 +6126,8 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateSubmissionOperation, @@ -6262,6 +6326,8 @@ func (s *Server) handleCreateSubmissionAdminRequest(args [0]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions-admin"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateSubmissionAdminOperation, @@ -6460,6 +6526,8 @@ func (s *Server) handleCreateSubmissionAuditCommentRequest(args [1]string, argsE semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/comment"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), CreateSubmissionAuditCommentOperation, @@ -6673,6 +6741,8 @@ func (s *Server) handleDeleteScriptRequest(args [1]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("DELETE"), semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), DeleteScriptOperation, @@ -6871,6 +6941,8 @@ func (s *Server) handleDeleteScriptPolicyRequest(args [1]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("DELETE"), semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), DeleteScriptPolicyOperation, @@ -7069,6 +7141,8 @@ func (s *Server) handleDownloadMapAssetRequest(args [1]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/maps/{MapID}/download"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), DownloadMapAssetOperation, @@ -7267,6 +7341,8 @@ func (s *Server) handleGetAssetThumbnailRequest(args [1]string, argsEscaped bool semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/thumbnails/asset/{AssetID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetAssetThumbnailOperation, @@ -7423,6 +7499,8 @@ func (s *Server) handleGetMapRequest(args [1]string, argsEscaped bool, w http.Re semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/maps/{MapID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetMapOperation, @@ -7575,6 +7653,8 @@ func (s *Server) handleGetMapfixRequest(args [1]string, argsEscaped bool, w http semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetMapfixOperation, @@ -7727,6 +7807,8 @@ func (s *Server) handleGetOperationRequest(args [1]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/operations/{OperationID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetOperationOperation, @@ -7925,6 +8007,8 @@ func (s *Server) handleGetScriptRequest(args [1]string, argsEscaped bool, w http semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetScriptOperation, @@ -8077,6 +8161,8 @@ func (s *Server) handleGetScriptPolicyRequest(args [1]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetScriptPolicyOperation, @@ -8229,6 +8315,8 @@ func (s *Server) handleGetStatsRequest(args [0]string, argsEscaped bool, w http. semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/stats"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetStatsOperation, @@ -8362,6 +8450,8 @@ func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetSubmissionOperation, @@ -8514,6 +8604,8 @@ func (s *Server) handleGetUserThumbnailRequest(args [1]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/thumbnails/user/{UserID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), GetUserThumbnailOperation, @@ -8670,6 +8762,8 @@ func (s *Server) handleListMapfixAuditEventsRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/audit-events"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListMapfixAuditEventsOperation, @@ -8830,6 +8924,8 @@ func (s *Server) handleListMapfixesRequest(args [0]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/mapfixes"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListMapfixesOperation, @@ -9022,6 +9118,8 @@ func (s *Server) handleListMapsRequest(args [0]string, argsEscaped bool, w http. semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/maps"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListMapsOperation, @@ -9194,6 +9292,8 @@ func (s *Server) handleListScriptPolicyRequest(args [0]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/script-policy"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListScriptPolicyOperation, @@ -9362,6 +9462,8 @@ func (s *Server) handleListScriptsRequest(args [0]string, argsEscaped bool, w ht semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/scripts"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListScriptsOperation, @@ -9538,6 +9640,8 @@ func (s *Server) handleListSubmissionAuditEventsRequest(args [1]string, argsEsca semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/audit-events"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListSubmissionAuditEventsOperation, @@ -9698,6 +9802,8 @@ func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/submissions"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ListSubmissionsOperation, @@ -9890,6 +9996,8 @@ func (s *Server) handleReleaseSubmissionsRequest(args [0]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/release-submissions"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), ReleaseSubmissionsOperation, @@ -10075,6 +10183,191 @@ func (s *Server) handleReleaseSubmissionsRequest(args [0]string, argsEscaped boo } } +// handleSeedCombobulatorRequest handles seedCombobulator operation. +// +// Queue all maps for combobulator processing. +// +// POST /maps-admin/seed-combobulator +func (s *Server) handleSeedCombobulatorRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("seedCombobulator"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/maps-admin/seed-combobulator"), + } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), SeedCombobulatorOperation, + 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: SeedCombobulatorOperation, + ID: "seedCombobulator", + } + ) + { + type bitset = [1]uint8 + var satisfied bitset + { + sctx, ok, err := s.securityCookieAuth(ctx, SeedCombobulatorOperation, 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 + } + } + + var rawBody []byte + + var response *SeedCombobulatorNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: SeedCombobulatorOperation, + OperationSummary: "Queue all maps for combobulator processing", + OperationID: "seedCombobulator", + Body: nil, + RawBody: rawBody, + Params: middleware.Parameters{}, + Raw: r, + } + + type ( + Request = struct{} + Params = struct{} + Response = *SeedCombobulatorNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + nil, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.SeedCombobulator(ctx) + return response, err + }, + ) + } else { + err = s.h.SeedCombobulator(ctx) + } + 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 := encodeSeedCombobulatorResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleSessionRolesRequest handles sessionRoles operation. // // Get list of roles for the current session. @@ -10088,6 +10381,8 @@ func (s *Server) handleSessionRolesRequest(args [0]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/session/roles"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), SessionRolesOperation, @@ -10271,6 +10566,8 @@ func (s *Server) handleSessionUserRequest(args [0]string, argsEscaped bool, w ht semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/session/user"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), SessionUserOperation, @@ -10454,6 +10751,8 @@ func (s *Server) handleSessionValidateRequest(args [0]string, argsEscaped bool, semconv.HTTPRequestMethodKey.String("GET"), semconv.HTTPRouteKey.String("/session/validate"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), SessionValidateOperation, @@ -10637,6 +10936,8 @@ func (s *Server) handleSetMapfixCompletedRequest(args [1]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/completed"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), SetMapfixCompletedOperation, @@ -10835,6 +11136,8 @@ func (s *Server) handleSetSubmissionCompletedRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/completed"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), SetSubmissionCompletedOperation, @@ -11033,6 +11336,8 @@ func (s *Server) handleUpdateMapfixDescriptionRequest(args [1]string, argsEscape semconv.HTTPRequestMethodKey.String("PATCH"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/description"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateMapfixDescriptionOperation, @@ -11246,6 +11551,8 @@ func (s *Server) handleUpdateMapfixModelRequest(args [1]string, argsEscaped bool semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/model"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateMapfixModelOperation, @@ -11452,6 +11759,8 @@ func (s *Server) handleUpdateScriptRequest(args [1]string, argsEscaped bool, w h semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/scripts/{ScriptID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateScriptOperation, @@ -11665,6 +11974,8 @@ func (s *Server) handleUpdateScriptPolicyRequest(args [1]string, argsEscaped boo semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/script-policy/{ScriptPolicyID}"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateScriptPolicyOperation, @@ -11878,6 +12189,8 @@ func (s *Server) handleUpdateSubmissionModelRequest(args [1]string, argsEscaped semconv.HTTPRequestMethodKey.String("POST"), semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/model"), } + // Add attributes from config. + otelAttrs = append(otelAttrs, s.cfg.Attributes...) // Start a span for this request. ctx, span := s.cfg.Tracer.Start(r.Context(), UpdateSubmissionModelOperation, diff --git a/pkg/api/oas_operations_gen.go b/pkg/api/oas_operations_gen.go index 260e79e..f251574 100644 --- a/pkg/api/oas_operations_gen.go +++ b/pkg/api/oas_operations_gen.go @@ -60,6 +60,7 @@ const ( ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents" ListSubmissionsOperation OperationName = "ListSubmissions" ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions" + SeedCombobulatorOperation OperationName = "SeedCombobulator" SessionRolesOperation OperationName = "SessionRoles" SessionUserOperation OperationName = "SessionUser" SessionValidateOperation OperationName = "SessionValidate" diff --git a/pkg/api/oas_response_decoders_gen.go b/pkg/api/oas_response_decoders_gen.go index fe3a927..9134132 100644 --- a/pkg/api/oas_response_decoders_gen.go +++ b/pkg/api/oas_response_decoders_gen.go @@ -4392,6 +4392,66 @@ func decodeReleaseSubmissionsResponse(resp *http.Response) (res *OperationID, _ return res, errors.Wrap(defRes, "error") } +func decodeSeedCombobulatorResponse(resp *http.Response) (res *SeedCombobulatorNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &SeedCombobulatorNoContent{}, 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 decodeSessionRolesResponse(resp *http.Response) (res *Roles, _ error) { switch resp.StatusCode { case 200: diff --git a/pkg/api/oas_response_encoders_gen.go b/pkg/api/oas_response_encoders_gen.go index ea5dbc8..aa75e85 100644 --- a/pkg/api/oas_response_encoders_gen.go +++ b/pkg/api/oas_response_encoders_gen.go @@ -340,6 +340,7 @@ func encodeDownloadMapAssetResponse(response DownloadMapAssetOK, w http.Response } func encodeGetAssetThumbnailResponse(response *GetAssetThumbnailFound, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Access-Control-Expose-Headers", "Location") // Encoding response headers. { h := uri.NewHeaderEncoder(w.Header()) @@ -464,6 +465,7 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp } func encodeGetUserThumbnailResponse(response *GetUserThumbnailFound, w http.ResponseWriter, span trace.Span) error { + w.Header().Set("Access-Control-Expose-Headers", "Location") // Encoding response headers. { h := uri.NewHeaderEncoder(w.Header()) @@ -621,6 +623,13 @@ func encodeReleaseSubmissionsResponse(response *OperationID, w http.ResponseWrit return nil } +func encodeSeedCombobulatorResponse(response *SeedCombobulatorNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + func encodeSessionRolesResponse(response *Roles, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) diff --git a/pkg/api/oas_router_gen.go b/pkg/api/oas_router_gen.go index 23dde03..f44d473 100644 --- a/pkg/api/oas_router_gen.go +++ b/pkg/api/oas_router_gen.go @@ -10,6 +10,51 @@ import ( "github.com/ogen-go/ogen/uri" ) +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{ + "POST": "Content-Type", + } + rn48AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn56AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn46AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn54AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn49AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn50AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn52AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn38AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn40AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } + rn41AllowedHeaders = map[string]string{ + "POST": "Content-Type", + } +) + func (s *Server) cutPrefix(path string) (string, bool) { prefix := s.cfg.Prefix if prefix == "" { @@ -88,7 +133,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleCreateMapfixRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET,POST", + allowedHeaders: rn42AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -118,7 +168,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -152,7 +207,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -186,7 +246,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn44AllowedHeaders, + acceptPost: "text/plain", + acceptPatch: "", + }) } return @@ -208,7 +273,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -232,7 +302,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "PATCH") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "PATCH", + allowedHeaders: rn83AllowedHeaders, + acceptPost: "", + acceptPatch: "text/plain", + }) } return @@ -254,7 +329,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -300,7 +380,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -322,7 +407,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -356,7 +446,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -378,7 +473,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -400,7 +500,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -422,7 +527,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -446,7 +556,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -468,7 +583,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -504,7 +624,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -525,7 +650,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -547,7 +677,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -571,7 +706,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -593,7 +733,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -622,12 +767,42 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "GET": s.handleListMapsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return } switch elem[0] { + case '-': // Prefix: "-admin/seed-combobulator" + + if l := len("-admin/seed-combobulator"); len(elem) >= l && elem[0:l] == "-admin/seed-combobulator" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleSeedCombobulatorRequest([0]string{}, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) + } + + return + } + case '/': // Prefix: "/" if l := len("/"); len(elem) >= l && elem[0:l] == "/" { @@ -652,7 +827,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -674,7 +854,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -711,7 +896,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -731,7 +921,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleReleaseSubmissionsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn73AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -776,7 +971,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleCreateScriptPolicyRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET,POST", + allowedHeaders: rn48AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -815,7 +1015,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "DELETE,GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "DELETE,GET,POST", + allowedHeaders: rn56AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -838,7 +1043,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleCreateScriptRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET,POST", + allowedHeaders: rn46AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -877,7 +1087,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "DELETE,GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "DELETE,GET,POST", + allowedHeaders: rn54AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -913,7 +1128,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "GET": s.handleSessionRolesRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -933,7 +1153,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "GET": s.handleSessionUserRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -953,7 +1178,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "GET": s.handleSessionValidateRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -975,7 +1205,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "GET": s.handleGetStatsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -996,7 +1231,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleCreateSubmissionRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET,POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET,POST", + allowedHeaders: rn49AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -1016,7 +1256,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleCreateSubmissionAdminRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn50AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -1046,7 +1291,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1080,7 +1330,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1114,7 +1369,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn52AllowedHeaders, + acceptPost: "text/plain", + acceptPatch: "", + }) } return @@ -1136,7 +1396,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1160,7 +1425,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1206,7 +1476,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1228,7 +1503,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1262,7 +1542,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1284,7 +1569,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1306,7 +1596,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1330,7 +1625,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1352,7 +1652,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1387,7 +1692,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1409,7 +1719,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1433,7 +1748,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1455,7 +1775,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1522,7 +1847,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1542,7 +1872,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleBatchAssetThumbnailsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn38AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -1587,7 +1922,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { args[0], }, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "GET") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "GET", + allowedHeaders: nil, + acceptPost: "", + acceptPatch: "", + }) } return @@ -1607,7 +1947,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleBatchUserThumbnailsRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn40AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -1631,7 +1976,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { case "POST": s.handleBatchUsernamesRequest([0]string{}, elemIsEscaped, w, r) default: - s.notAllowed(w, r, "POST") + s.notAllowed(w, r, notAllowedParams{ + allowedMethods: "POST", + allowedHeaders: rn41AllowedHeaders, + acceptPost: "application/json", + acceptPatch: "", + }) } return @@ -2378,6 +2728,31 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { } } switch elem[0] { + case '-': // Prefix: "-admin/seed-combobulator" + + if l := len("-admin/seed-combobulator"); len(elem) >= l && elem[0:l] == "-admin/seed-combobulator" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = SeedCombobulatorOperation + r.summary = "Queue all maps for combobulator processing" + r.operationID = "seedCombobulator" + r.operationGroup = "" + r.pathPattern = "/maps-admin/seed-combobulator" + r.args = args + r.count = 0 + return r, true + default: + return + } + } + case '/': // Prefix: "/" if l := len("/"); len(elem) >= l && elem[0:l] == "/" { diff --git a/pkg/api/oas_schemas_gen.go b/pkg/api/oas_schemas_gen.go index a05861d..3f100e0 100644 --- a/pkg/api/oas_schemas_gen.go +++ b/pkg/api/oas_schemas_gen.go @@ -1993,6 +1993,9 @@ func (s *ScriptUpdate) SetResourceID(val OptInt64) { s.ResourceID = val } +// SeedCombobulatorNoContent is response for SeedCombobulator operation. +type SeedCombobulatorNoContent struct{} + // SetMapfixCompletedNoContent is response for SetMapfixCompleted operation. type SetMapfixCompletedNoContent struct{} diff --git a/pkg/api/oas_security_gen.go b/pkg/api/oas_security_gen.go index fe7d2cc..f299a04 100644 --- a/pkg/api/oas_security_gen.go +++ b/pkg/api/oas_security_gen.go @@ -32,6 +32,7 @@ func findAuthorization(h http.Header, prefix string) (string, bool) { return "", false } +// operationRolesCookieAuth is a private map storing roles per operation. var operationRolesCookieAuth = map[string][]string{ ActionMapfixAcceptedOperation: []string{}, ActionMapfixRejectOperation: []string{}, @@ -69,6 +70,7 @@ var operationRolesCookieAuth = map[string][]string{ DownloadMapAssetOperation: []string{}, GetOperationOperation: []string{}, ReleaseSubmissionsOperation: []string{}, + SeedCombobulatorOperation: []string{}, SessionRolesOperation: []string{}, SessionUserOperation: []string{}, SessionValidateOperation: []string{}, @@ -81,6 +83,27 @@ var operationRolesCookieAuth = map[string][]string{ UpdateSubmissionModelOperation: []string{}, } +// GetRolesForCookieAuth returns the required roles for the given operation. +// +// This is useful for authorization scenarios where you need to know which roles +// are required for an operation. +// +// Example: +// +// requiredRoles := GetRolesForCookieAuth(AddPetOperation) +// +// Returns nil if the operation has no role requirements or if the operation is unknown. +func GetRolesForCookieAuth(operation string) []string { + roles, ok := operationRolesCookieAuth[operation] + if !ok { + return nil + } + // Return a copy to prevent external modification + result := make([]string, len(roles)) + copy(result, roles) + return result +} + func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) { var t CookieAuth const parameterName = "session_id" diff --git a/pkg/api/oas_server_gen.go b/pkg/api/oas_server_gen.go index dc3be49..707c53f 100644 --- a/pkg/api/oas_server_gen.go +++ b/pkg/api/oas_server_gen.go @@ -335,6 +335,12 @@ type Handler interface { // // POST /release-submissions ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) (*OperationID, error) + // SeedCombobulator implements seedCombobulator operation. + // + // Queue all maps for combobulator processing. + // + // POST /maps-admin/seed-combobulator + SeedCombobulator(ctx context.Context) error // SessionRoles implements sessionRoles operation. // // Get list of roles for the current session. diff --git a/pkg/api/oas_unimplemented_gen.go b/pkg/api/oas_unimplemented_gen.go index bd924ef..dc5a3fa 100644 --- a/pkg/api/oas_unimplemented_gen.go +++ b/pkg/api/oas_unimplemented_gen.go @@ -502,6 +502,15 @@ func (UnimplementedHandler) ReleaseSubmissions(ctx context.Context, req []Releas return r, ht.ErrNotImplemented } +// SeedCombobulator implements seedCombobulator operation. +// +// Queue all maps for combobulator processing. +// +// POST /maps-admin/seed-combobulator +func (UnimplementedHandler) SeedCombobulator(ctx context.Context) error { + return ht.ErrNotImplemented +} + // SessionRoles implements sessionRoles operation. // // Get list of roles for the current session. diff --git a/pkg/datastore/datastore.go b/pkg/datastore/datastore.go index 0c43d1c..d8d4e49 100644 --- a/pkg/datastore/datastore.go +++ b/pkg/datastore/datastore.go @@ -47,6 +47,7 @@ type Maps interface { Create(ctx context.Context, smap model.Map) (model.Map, error) Update(ctx context.Context, id int64, values OptionalMap) error Delete(ctx context.Context, id int64) error + GetAll(ctx context.Context) ([]model.Map, error) List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Map, error) IncrementLoadCount(ctx context.Context, id int64) error } diff --git a/pkg/datastore/gormstore/maps.go b/pkg/datastore/gormstore/maps.go index a47e27f..647e4f2 100644 --- a/pkg/datastore/gormstore/maps.go +++ b/pkg/datastore/gormstore/maps.go @@ -74,6 +74,14 @@ func (env *Maps) Delete(ctx context.Context, id int64) error { return nil } +func (env *Maps) GetAll(ctx context.Context) ([]model.Map, error) { + var maps []model.Map + if err := env.db.Find(&maps).Error; err != nil { + return nil, err + } + return maps, nil +} + func (env *Maps) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.Map, error) { var events []model.Map if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil { diff --git a/pkg/model/nats.go b/pkg/model/nats.go index 081ba13..ddd86ca 100644 --- a/pkg/model/nats.go +++ b/pkg/model/nats.go @@ -91,3 +91,7 @@ type ReleaseMapfixRequest struct { ModelVersion uint64 TargetAssetID uint64 } + +type SeedCombobulatorRequest struct { + AssetID uint64 +} diff --git a/pkg/service/maps.go b/pkg/service/maps.go index 3365988..482bbcf 100644 --- a/pkg/service/maps.go +++ b/pkg/service/maps.go @@ -99,6 +99,10 @@ func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error return map_item.ID, nil } +func (svc *Service) GetAllMaps(ctx context.Context) ([]model.Map, error) { + return svc.db.Maps().GetAll(ctx) +} + func (svc *Service) ListMaps(ctx context.Context, filter MapFilter, page model.Page) ([]model.Map, error) { return svc.db.Maps().List(ctx, datastore.OptionalMap(filter), page) } diff --git a/pkg/service/nats_maps.go b/pkg/service/nats_maps.go new file mode 100644 index 0000000..6b8298f --- /dev/null +++ b/pkg/service/nats_maps.go @@ -0,0 +1,21 @@ +package service + +import ( + "encoding/json" + + "git.itzana.me/strafesnet/maps-service/pkg/model" +) + +func (svc *Service) NatsSeedCombobulator(assetID uint64) error { + request := model.SeedCombobulatorRequest{ + AssetID: assetID, + } + + j, err := json.Marshal(request) + if err != nil { + return err + } + + _, err = svc.nats.Publish("maptest.combobulator.seed", j) + return err +} diff --git a/pkg/web_api/maps.go b/pkg/web_api/maps.go index 97574b1..5764f7c 100644 --- a/pkg/web_api/maps.go +++ b/pkg/web_api/maps.go @@ -86,6 +86,39 @@ func (svc *Service) GetMap(ctx context.Context, params api.GetMapParams) (*api.M }, nil } +// SeedCombobulator implements seedCombobulator operation. +// +// Queue all maps for combobulator processing. +// +// POST /maps-admin/seed-combobulator +func (svc *Service) SeedCombobulator(ctx context.Context) 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 + } + + maps, err := svc.inner.GetAllMaps(ctx) + if err != nil { + return err + } + + for _, m := range maps { + if err := svc.inner.NatsSeedCombobulator(uint64(m.ID)); err != nil { + return err + } + } + + return nil +} + // DownloadMapAsset invokes downloadMapAsset operation. // // Download the map asset.