Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
0324a57e5c | |||
ca750669db | |||
ccf1ff6866 | |||
1f1deacc2d | |||
d8095cee83 | |||
28985bed55 | |||
a03e812e46 |
Cargo.lockREADME.mdcompose.yamlopenapi-internal.yamlopenapi.yaml
pkg
api
oas_client_gen.gooas_handlers_gen.gooas_json_gen.gooas_operations_gen.gooas_parameters_gen.gooas_request_decoders_gen.gooas_request_encoders_gen.gooas_response_decoders_gen.gooas_response_encoders_gen.gooas_router_gen.gooas_schemas_gen.gooas_security_gen.gooas_server_gen.gooas_unimplemented_gen.gooas_validators_gen.go
cmds
datastore
internal
oas_client_gen.gooas_handlers_gen.gooas_json_gen.gooas_operations_gen.gooas_parameters_gen.gooas_request_decoders_gen.gooas_response_decoders_gen.gooas_response_encoders_gen.gooas_router_gen.gooas_schemas_gen.gooas_server_gen.gooas_unimplemented_gen.gooas_validators_gen.go
model
service
service_internal
validation
web
package.json
public/errors
src/app
738
Cargo.lock
generated
738
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -26,11 +26,10 @@ Prerequisite: golang installed
|
||||
|
||||
Prerequisite: bun installed
|
||||
|
||||
The environment variables `API_HOST` and `AUTH_HOST` will need to be set for the middleware.
|
||||
The environment variable `API_HOST` will need to be set for the middleware.
|
||||
Example `.env` in web's root:
|
||||
```
|
||||
API_HOST="http://localhost:8082/"
|
||||
AUTH_HOST="http://localhost:8083/"
|
||||
API_HOST="http://localhost:8082/v1/"
|
||||
```
|
||||
|
||||
1. `cd web`
|
||||
|
@ -50,7 +50,6 @@ services:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- API_HOST=http://submissions:8082/v1
|
||||
- AUTH_HOST=http://localhost:8080/
|
||||
|
||||
validation:
|
||||
image:
|
||||
|
@ -47,14 +47,14 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: ValidatedModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
@ -73,56 +73,6 @@ paths:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: DisplayName
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: Creator
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: GameID
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/validator-request-changes:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
|
||||
operationId: actionMapfixRequestChanges
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 0
|
||||
maxLength: 4096
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@ -157,7 +107,7 @@ paths:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: ErrorMessage
|
||||
- name: StatusMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
@ -252,14 +202,14 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: ValidatedModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
@ -278,56 +228,6 @@ paths:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: DisplayName
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: Creator
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: GameID
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/validator-request-changes:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
|
||||
operationId: actionSubmissionRequestChanges
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 0
|
||||
maxLength: 4096
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@ -362,7 +262,7 @@ paths:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: ErrorMessage
|
||||
- name: StatusMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
@ -391,7 +291,7 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
@ -421,13 +321,13 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: Policy
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
@ -497,13 +397,13 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
- name: ResourceID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
@ -574,7 +474,7 @@ components:
|
||||
description: The unique identifier for a submission.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
OperationID:
|
||||
name: OperationID
|
||||
@ -583,7 +483,7 @@ components:
|
||||
description: The unique identifier for a long-running operation.
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
name: SubmissionID
|
||||
@ -592,7 +492,7 @@ components:
|
||||
description: The unique identifier for a submission.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
name: ScriptID
|
||||
@ -601,7 +501,7 @@ components:
|
||||
description: The unique identifier for a script.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Page:
|
||||
name: Page
|
||||
@ -609,7 +509,7 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
Limit:
|
||||
name: Limit
|
||||
@ -617,7 +517,7 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
schemas:
|
||||
@ -628,7 +528,7 @@ components:
|
||||
properties:
|
||||
MapfixID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
required:
|
||||
@ -637,7 +537,7 @@ components:
|
||||
properties:
|
||||
SubmissionID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
required:
|
||||
@ -646,7 +546,7 @@ components:
|
||||
properties:
|
||||
ScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
required:
|
||||
@ -655,7 +555,7 @@ components:
|
||||
properties:
|
||||
ScriptPolicyID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
MapfixCreate:
|
||||
required:
|
||||
@ -667,16 +567,15 @@ components:
|
||||
- AssetID
|
||||
- AssetVersion
|
||||
- TargetAssetID
|
||||
- Description
|
||||
type: object
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
AssetOwner:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
@ -686,23 +585,20 @@ components:
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Description:
|
||||
type: string
|
||||
maxLength: 256
|
||||
SubmissionCreate:
|
||||
required:
|
||||
- OperationID
|
||||
@ -712,17 +608,15 @@ components:
|
||||
- GameID
|
||||
- AssetID
|
||||
- AssetVersion
|
||||
- Status
|
||||
- Roles
|
||||
type: object
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
AssetOwner:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
@ -732,24 +626,16 @@ components:
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Status:
|
||||
type: integer
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 9
|
||||
Roles:
|
||||
type: integer
|
||||
format: uint32
|
||||
Script:
|
||||
required:
|
||||
- ID
|
||||
@ -762,7 +648,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
@ -776,11 +662,11 @@ components:
|
||||
maxLength: 1048576
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptCreate:
|
||||
required:
|
||||
@ -798,11 +684,11 @@ components:
|
||||
maxLength: 1048576
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptPolicy:
|
||||
required:
|
||||
@ -814,7 +700,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
FromScriptHash:
|
||||
type: string
|
||||
@ -822,11 +708,11 @@ components:
|
||||
maxLength: 16
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ScriptPolicyCreate:
|
||||
required:
|
||||
@ -837,15 +723,15 @@ components:
|
||||
properties:
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
Error:
|
||||
description: Represents error object
|
||||
@ -853,7 +739,7 @@ components:
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
message:
|
||||
type: string
|
||||
|
332
openapi.yaml
332
openapi.yaml
@ -104,23 +104,16 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
description: >
|
||||
Sort order:
|
||||
* `0` - Disabled
|
||||
* `1` - DisplayNameAscending
|
||||
* `2` - DisplayNameDescending
|
||||
* `3` - DateAscending
|
||||
* `4` - DateDescending
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@ -182,71 +175,41 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
description: >
|
||||
Game ID:
|
||||
* `1` - Bhop
|
||||
* `2` - Surf
|
||||
* `5` - FlyTrials
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
description: >
|
||||
Sort order:
|
||||
* `0` - Disabled
|
||||
* `1` - DisplayNameAscending
|
||||
* `2` - DisplayNameDescending
|
||||
* `3` - DateAscending
|
||||
* `4` - DateDescending
|
||||
- name: Submitter
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: AssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: TargetAssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: StatusID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 9
|
||||
description: >
|
||||
// Phase: Creation
|
||||
* `0` - UnderConstruction
|
||||
* `1` - ChangesRequested
|
||||
|
||||
// Phase: Review
|
||||
* `2` - Submitting
|
||||
* `3` - Submitted
|
||||
|
||||
// Phase: Testing
|
||||
* `4` - AcceptedUnvalidated // pending script review, can re-trigger validation
|
||||
* `5` - Validating
|
||||
* `6` - Validated
|
||||
* `7` - Uploading
|
||||
|
||||
// Phase: Final MapfixStatus
|
||||
* `8` - Uploaded // uploaded to the group, but pending release
|
||||
* `9` - Rejected
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@ -369,14 +332,14 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
@ -421,23 +384,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/bypass-submit:
|
||||
post:
|
||||
summary: Role Reviewer changes status from ChangesRequested -> Submitted
|
||||
operationId: actionMapfixBypassSubmit
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/reset-submitting:
|
||||
post:
|
||||
summary: Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction
|
||||
@ -636,72 +582,41 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
description: >
|
||||
Game ID:
|
||||
* `1` - Bhop
|
||||
* `2` - Surf
|
||||
* `5` - FlyTrials
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
description: >
|
||||
Sort order:
|
||||
* `0` - Disabled
|
||||
* `1` - DisplayNameAscending
|
||||
* `2` - DisplayNameDescending
|
||||
* `3` - DateAscending
|
||||
* `4` - DateDescending
|
||||
- name: Submitter
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: AssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: UploadedAssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: StatusID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 10
|
||||
description: >
|
||||
// Phase: Creation
|
||||
* `0` - UnderConstruction
|
||||
* `1` - ChangesRequested
|
||||
|
||||
// Phase: Review
|
||||
* `2` - Submitting
|
||||
* `3` - Submitted
|
||||
|
||||
// Phase: Testing
|
||||
* `4` - AcceptedUnvalidated // pending script review, can re-trigger validation
|
||||
* `5` - Validating
|
||||
* `6` - Validated
|
||||
* `7` - Uploading
|
||||
* `8` - Uploaded // uploaded to the group, but pending release
|
||||
|
||||
// Phase: Final SubmissionStatus
|
||||
* `9` - Rejected
|
||||
* `10` - Released
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@ -739,31 +654,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions-admin:
|
||||
post:
|
||||
summary: Trigger the validator to create a new submission
|
||||
operationId: createSubmissionAdmin
|
||||
tags:
|
||||
- Submissions
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SubmissionTriggerCreate'
|
||||
responses:
|
||||
"201":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/OperationID"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}:
|
||||
get:
|
||||
summary: Retrieve map with ID
|
||||
@ -849,14 +739,14 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
@ -901,23 +791,6 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/bypass-submit:
|
||||
post:
|
||||
summary: Role Reviewer changes status from ChangesRequested -> Submitted
|
||||
operationId: actionSubmissionBypassSubmit
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/reset-submitting:
|
||||
post:
|
||||
summary: Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction
|
||||
@ -1116,13 +989,13 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
- name: Policy
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
@ -1253,13 +1126,13 @@ paths:
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
- name: ResourceID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
@ -1374,7 +1247,7 @@ components:
|
||||
description: The unique identifier for a map.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
MapfixID:
|
||||
name: MapfixID
|
||||
@ -1383,7 +1256,7 @@ components:
|
||||
description: The unique identifier for a mapfix.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
OperationID:
|
||||
name: OperationID
|
||||
@ -1392,7 +1265,7 @@ components:
|
||||
description: The unique identifier for a long-running operation.
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
name: SubmissionID
|
||||
@ -1401,7 +1274,7 @@ components:
|
||||
description: The unique identifier for a submission.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
name: ScriptID
|
||||
@ -1410,7 +1283,7 @@ components:
|
||||
description: The unique identifier for a script.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
name: ScriptPolicyID
|
||||
@ -1419,7 +1292,7 @@ components:
|
||||
description: The unique identifier for a script policy.
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Page:
|
||||
name: Page
|
||||
@ -1427,7 +1300,7 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 1
|
||||
Limit:
|
||||
name: Limit
|
||||
@ -1435,7 +1308,7 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
schemas:
|
||||
@ -1445,7 +1318,6 @@ components:
|
||||
- ID
|
||||
- Date
|
||||
- User
|
||||
- Username
|
||||
- ResourceType
|
||||
- ResourceID
|
||||
- EventType
|
||||
@ -1453,26 +1325,23 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
Date:
|
||||
type: integer
|
||||
format: int64
|
||||
User:
|
||||
type: integer
|
||||
format: int64
|
||||
Username:
|
||||
type: string
|
||||
maxLength: 64
|
||||
format: uint64
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
description: Is this a submission or is it a mapfix
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
EventType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
EventData:
|
||||
type: object
|
||||
description: Arbitrary event data
|
||||
@ -1484,7 +1353,7 @@ components:
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
required:
|
||||
@ -1493,7 +1362,7 @@ components:
|
||||
properties:
|
||||
ScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
required:
|
||||
@ -1502,7 +1371,7 @@ components:
|
||||
properties:
|
||||
ScriptPolicyID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Roles:
|
||||
required:
|
||||
@ -1511,7 +1380,7 @@ components:
|
||||
properties:
|
||||
Roles:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
User:
|
||||
required:
|
||||
@ -1522,7 +1391,7 @@ components:
|
||||
properties:
|
||||
UserID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Username:
|
||||
type: string
|
||||
@ -1541,7 +1410,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
@ -1551,7 +1420,7 @@ components:
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
Date:
|
||||
type: integer
|
||||
@ -1571,12 +1440,12 @@ components:
|
||||
- Completed
|
||||
- TargetAssetID
|
||||
- StatusID
|
||||
- Description
|
||||
- StatusMessage
|
||||
type: object
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
@ -1586,7 +1455,7 @@ components:
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
CreatedAt:
|
||||
type: integer
|
||||
@ -1598,27 +1467,27 @@ components:
|
||||
minimum: 0
|
||||
Submitter:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Completed:
|
||||
type: boolean
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
StatusID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
Description:
|
||||
StatusMessage:
|
||||
type: string
|
||||
maxLength: 256
|
||||
Mapfixes:
|
||||
@ -1629,7 +1498,7 @@ components:
|
||||
properties:
|
||||
Total:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Mapfixes:
|
||||
type: array
|
||||
@ -1639,20 +1508,16 @@ components:
|
||||
required:
|
||||
- AssetID
|
||||
- TargetAssetID
|
||||
- Description
|
||||
type: object
|
||||
properties:
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Description:
|
||||
type: string
|
||||
maxLength: 256
|
||||
Operation:
|
||||
required:
|
||||
- OperationID
|
||||
@ -1665,7 +1530,7 @@ components:
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
Date:
|
||||
type: integer
|
||||
@ -1673,11 +1538,11 @@ components:
|
||||
minimum: 0
|
||||
Owner:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Status:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
StatusMessage:
|
||||
type: string
|
||||
@ -1701,11 +1566,12 @@ components:
|
||||
- Completed
|
||||
# - UploadedAssetID
|
||||
- StatusID
|
||||
- StatusMessage
|
||||
type: object
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
@ -1715,46 +1581,49 @@ components:
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
CreatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
UpdatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Submitter:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ValidatedAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ValidatedAssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Completed:
|
||||
type: boolean
|
||||
UploadedAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
StatusID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
StatusMessage:
|
||||
type: string
|
||||
maxLength: 256
|
||||
Submissions:
|
||||
required:
|
||||
- Total
|
||||
@ -1763,7 +1632,7 @@ components:
|
||||
properties:
|
||||
Total:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Submissions:
|
||||
type: array
|
||||
@ -1772,24 +1641,11 @@ components:
|
||||
SubmissionTriggerCreate:
|
||||
required:
|
||||
- AssetID
|
||||
- DisplayName
|
||||
- Creator
|
||||
- GameID
|
||||
type: object
|
||||
properties:
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
Creator:
|
||||
type: string
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ReleaseInfo:
|
||||
required:
|
||||
@ -1799,7 +1655,7 @@ components:
|
||||
properties:
|
||||
SubmissionID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Date:
|
||||
type: string
|
||||
@ -1816,7 +1672,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
@ -1830,11 +1686,11 @@ components:
|
||||
maxLength: 1048576
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptCreate:
|
||||
required:
|
||||
@ -1852,11 +1708,11 @@ components:
|
||||
maxLength: 1048576
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptUpdate:
|
||||
required:
|
||||
@ -1865,7 +1721,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
@ -1875,11 +1731,11 @@ components:
|
||||
maxLength: 1048576
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ScriptPolicy:
|
||||
required:
|
||||
@ -1891,7 +1747,7 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
FromScriptHash:
|
||||
type: string
|
||||
@ -1899,11 +1755,11 @@ components:
|
||||
maxLength: 16
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ScriptPolicyCreate:
|
||||
required:
|
||||
@ -1914,15 +1770,15 @@ components:
|
||||
properties:
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
ScriptPolicyUpdate:
|
||||
required:
|
||||
@ -1931,19 +1787,19 @@ components:
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
format: uint32
|
||||
minimum: 0
|
||||
Error:
|
||||
description: Represents error object
|
||||
@ -1951,7 +1807,7 @@ components:
|
||||
properties:
|
||||
code:
|
||||
type: integer
|
||||
format: int64
|
||||
format: uint64
|
||||
minimum: 0
|
||||
message:
|
||||
type: string
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -225,201 +225,6 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixBypassSubmitRequest handles actionMapfixBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/bypass-submit
|
||||
func (s *Server) handleActionMapfixBypassSubmitRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixBypassSubmit"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/bypass-submit"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixBypassSubmitOperation,
|
||||
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: ActionMapfixBypassSubmitOperation,
|
||||
ID: "actionMapfixBypassSubmit",
|
||||
}
|
||||
)
|
||||
{
|
||||
type bitset = [1]uint8
|
||||
var satisfied bitset
|
||||
{
|
||||
sctx, ok, err := s.securityCookieAuth(ctx, ActionMapfixBypassSubmitOperation, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.SecurityError{
|
||||
OperationContext: opErrContext,
|
||||
Security: "CookieAuth",
|
||||
Err: err,
|
||||
}
|
||||
if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
|
||||
defer recordError("Security:CookieAuth", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
satisfied[0] |= 1 << 0
|
||||
ctx = sctx
|
||||
}
|
||||
}
|
||||
|
||||
if ok := func() bool {
|
||||
nextRequirement:
|
||||
for _, requirement := range []bitset{
|
||||
{0b00000001},
|
||||
} {
|
||||
for i, mask := range requirement {
|
||||
if satisfied[i]&mask != mask {
|
||||
continue nextRequirement
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}(); !ok {
|
||||
err = &ogenerrors.SecurityError{
|
||||
OperationContext: opErrContext,
|
||||
Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied,
|
||||
}
|
||||
if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
|
||||
defer recordError("Security", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
params, err := decodeActionMapfixBypassSubmitParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionMapfixBypassSubmitNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionMapfixBypassSubmitOperation,
|
||||
OperationSummary: "Role Reviewer changes status from ChangesRequested -> Submitted",
|
||||
OperationID: "actionMapfixBypassSubmit",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "MapfixID",
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionMapfixBypassSubmitParams
|
||||
Response = *ActionMapfixBypassSubmitNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionMapfixBypassSubmitParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionMapfixBypassSubmit(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionMapfixBypassSubmit(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionMapfixBypassSubmitResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixRejectRequest handles actionMapfixReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -2371,201 +2176,6 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionBypassSubmitRequest handles actionSubmissionBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/bypass-submit
|
||||
func (s *Server) handleActionSubmissionBypassSubmitRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionBypassSubmit"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/bypass-submit"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionBypassSubmitOperation,
|
||||
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: ActionSubmissionBypassSubmitOperation,
|
||||
ID: "actionSubmissionBypassSubmit",
|
||||
}
|
||||
)
|
||||
{
|
||||
type bitset = [1]uint8
|
||||
var satisfied bitset
|
||||
{
|
||||
sctx, ok, err := s.securityCookieAuth(ctx, ActionSubmissionBypassSubmitOperation, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.SecurityError{
|
||||
OperationContext: opErrContext,
|
||||
Security: "CookieAuth",
|
||||
Err: err,
|
||||
}
|
||||
if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
|
||||
defer recordError("Security:CookieAuth", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
satisfied[0] |= 1 << 0
|
||||
ctx = sctx
|
||||
}
|
||||
}
|
||||
|
||||
if ok := func() bool {
|
||||
nextRequirement:
|
||||
for _, requirement := range []bitset{
|
||||
{0b00000001},
|
||||
} {
|
||||
for i, mask := range requirement {
|
||||
if satisfied[i]&mask != mask {
|
||||
continue nextRequirement
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}(); !ok {
|
||||
err = &ogenerrors.SecurityError{
|
||||
OperationContext: opErrContext,
|
||||
Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied,
|
||||
}
|
||||
if encodeErr := encodeErrorResponse(s.h.NewError(ctx, err), w, span); encodeErr != nil {
|
||||
defer recordError("Security", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
params, err := decodeActionSubmissionBypassSubmitParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionSubmissionBypassSubmitNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionSubmissionBypassSubmitOperation,
|
||||
OperationSummary: "Role Reviewer changes status from ChangesRequested -> Submitted",
|
||||
OperationID: "actionSubmissionBypassSubmit",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "SubmissionID",
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionSubmissionBypassSubmitParams
|
||||
Response = *ActionSubmissionBypassSubmitNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionSubmissionBypassSubmitParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionSubmissionBypassSubmit(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionSubmissionBypassSubmit(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionSubmissionBypassSubmitResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionRejectRequest handles actionSubmissionReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -5312,201 +4922,6 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool,
|
||||
}
|
||||
}
|
||||
|
||||
// handleCreateSubmissionAdminRequest handles createSubmissionAdmin operation.
|
||||
//
|
||||
// Trigger the validator to create a new submission.
|
||||
//
|
||||
// POST /submissions-admin
|
||||
func (s *Server) handleCreateSubmissionAdminRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("createSubmissionAdmin"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions-admin"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), CreateSubmissionAdminOperation,
|
||||
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: CreateSubmissionAdminOperation,
|
||||
ID: "createSubmissionAdmin",
|
||||
}
|
||||
)
|
||||
{
|
||||
type bitset = [1]uint8
|
||||
var satisfied bitset
|
||||
{
|
||||
sctx, ok, err := s.securityCookieAuth(ctx, CreateSubmissionAdminOperation, 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
|
||||
}
|
||||
}
|
||||
request, close, err := s.decodeCreateSubmissionAdminRequest(r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeRequestError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeRequest", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if err := close(); err != nil {
|
||||
recordError("CloseRequest", err)
|
||||
}
|
||||
}()
|
||||
|
||||
var response *OperationID
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: CreateSubmissionAdminOperation,
|
||||
OperationSummary: "Trigger the validator to create a new submission",
|
||||
OperationID: "createSubmissionAdmin",
|
||||
Body: request,
|
||||
Params: middleware.Parameters{},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = *SubmissionTriggerCreate
|
||||
Params = struct{}
|
||||
Response = *OperationID
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
nil,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
response, err = s.h.CreateSubmissionAdmin(ctx, request)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
response, err = s.h.CreateSubmissionAdmin(ctx, request)
|
||||
}
|
||||
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 := encodeCreateSubmissionAdminResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleCreateSubmissionAuditCommentRequest handles createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,6 @@ type OperationName = string
|
||||
|
||||
const (
|
||||
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
|
||||
ActionMapfixBypassSubmitOperation OperationName = "ActionMapfixBypassSubmit"
|
||||
ActionMapfixRejectOperation OperationName = "ActionMapfixReject"
|
||||
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
|
||||
ActionMapfixResetSubmittingOperation OperationName = "ActionMapfixResetSubmitting"
|
||||
@ -18,7 +17,6 @@ const (
|
||||
ActionMapfixTriggerValidateOperation OperationName = "ActionMapfixTriggerValidate"
|
||||
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
|
||||
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
|
||||
ActionSubmissionBypassSubmitOperation OperationName = "ActionSubmissionBypassSubmit"
|
||||
ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject"
|
||||
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
|
||||
ActionSubmissionResetSubmittingOperation OperationName = "ActionSubmissionResetSubmitting"
|
||||
@ -33,7 +31,6 @@ const (
|
||||
CreateScriptOperation OperationName = "CreateScript"
|
||||
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
|
||||
CreateSubmissionOperation OperationName = "CreateSubmission"
|
||||
CreateSubmissionAdminOperation OperationName = "CreateSubmissionAdmin"
|
||||
CreateSubmissionAuditCommentOperation OperationName = "CreateSubmissionAuditComment"
|
||||
DeleteScriptOperation OperationName = "DeleteScript"
|
||||
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/go-faster/jx"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/ogen-go/ogen/ogenerrors"
|
||||
"github.com/ogen-go/ogen/validate"
|
||||
@ -26,13 +27,13 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -97,13 +98,13 @@ func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -131,13 +132,13 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -202,13 +203,13 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -273,84 +274,13 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return req, close, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
if r.ContentLength == 0 {
|
||||
return req, close, validate.ErrBodyRequired
|
||||
}
|
||||
buf, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return req, close, err
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
return req, close, validate.ErrBodyRequired
|
||||
}
|
||||
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var request SubmissionTriggerCreate
|
||||
if err := func() error {
|
||||
if err := request.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 req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
|
||||
req *SubmissionTriggerCreate,
|
||||
close func() error,
|
||||
rerr error,
|
||||
) {
|
||||
var closers []func() error
|
||||
close = func() error {
|
||||
var merr error
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -415,13 +345,13 @@ func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -449,13 +379,13 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -553,13 +483,13 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -624,13 +554,13 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
|
@ -77,20 +77,6 @@ func encodeCreateSubmissionRequest(
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAdminRequest(
|
||||
req *SubmissionTriggerCreate,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAuditCommentRequest(
|
||||
req CreateSubmissionAuditCommentReq,
|
||||
r *http.Request,
|
||||
|
@ -75,66 +75,6 @@ func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixA
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionMapfixBypassSubmitResponse(resp *http.Response) (res *ActionMapfixBypassSubmitNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionMapfixBypassSubmitNoContent{}, 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 decodeActionMapfixRejectResponse(resp *http.Response) (res *ActionMapfixRejectNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
@ -735,66 +675,6 @@ func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSub
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionSubmissionBypassSubmitResponse(resp *http.Response) (res *ActionSubmissionBypassSubmitNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionSubmissionBypassSubmitNoContent{}, 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 decodeActionSubmissionRejectResponse(resp *http.Response) (res *ActionSubmissionRejectNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
@ -1799,107 +1679,6 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *OperationID, _ er
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeCreateSubmissionAdminResponse(resp *http.Response) (res *OperationID, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 201:
|
||||
// Code 201.
|
||||
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 OperationID
|
||||
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 &response, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
// 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 decodeCreateSubmissionAuditCommentResponse(resp *http.Response) (res *CreateSubmissionAuditCommentNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
@ -2732,23 +2511,6 @@ func decodeListMapfixAuditEventsResponse(resp *http.Response) (res []AuditEvent,
|
||||
if response == nil {
|
||||
return errors.New("nil is invalid value")
|
||||
}
|
||||
var failures []validate.FieldError
|
||||
for i, elem := range response {
|
||||
if err := func() error {
|
||||
if err := elem.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: fmt.Sprintf("[%d]", i),
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
@ -3337,23 +3099,6 @@ func decodeListSubmissionAuditEventsResponse(resp *http.Response) (res []AuditEv
|
||||
if response == nil {
|
||||
return errors.New("nil is invalid value")
|
||||
}
|
||||
var failures []validate.FieldError
|
||||
for i, elem := range response {
|
||||
if err := func() error {
|
||||
if err := elem.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: fmt.Sprintf("[%d]", i),
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
|
@ -20,13 +20,6 @@ func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent,
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixBypassSubmitResponse(response *ActionMapfixBypassSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixRejectResponse(response *ActionMapfixRejectNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@ -97,13 +90,6 @@ func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNo
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionBypassSubmitResponse(response *ActionSubmissionBypassSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionRejectResponse(response *ActionSubmissionRejectNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@ -230,20 +216,6 @@ func encodeCreateSubmissionResponse(response *OperationID, w http.ResponseWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAdminResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(201)
|
||||
span.SetStatus(codes.Ok, http.StatusText(201))
|
||||
|
||||
e := new(jx.Encoder)
|
||||
response.Encode(e)
|
||||
if _, err := e.WriteTo(w); err != nil {
|
||||
return errors.Wrap(err, "write")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAuditCommentResponse(response *CreateSubmissionAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
@ -250,28 +250,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'b': // Prefix: "bypass-submit"
|
||||
|
||||
if l := len("bypass-submit"); len(elem) >= l && elem[0:l] == "bypass-submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixBypassSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "re"
|
||||
|
||||
if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
|
||||
@ -892,26 +870,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
switch elem[0] {
|
||||
case '-': // Prefix: "-admin"
|
||||
|
||||
if l := len("-admin"); len(elem) >= l && elem[0:l] == "-admin" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleCreateSubmissionAdminRequest([0]string{}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case '/': // Prefix: "/"
|
||||
|
||||
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
|
||||
@ -1068,28 +1026,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'b': // Prefix: "bypass-submit"
|
||||
|
||||
if l := len("bypass-submit"); len(elem) >= l && elem[0:l] == "bypass-submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionBypassSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "re"
|
||||
|
||||
if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
|
||||
@ -1665,30 +1601,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'b': // Prefix: "bypass-submit"
|
||||
|
||||
if l := len("bypass-submit"); len(elem) >= l && elem[0:l] == "bypass-submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixBypassSubmitOperation
|
||||
r.summary = "Role Reviewer changes status from ChangesRequested -> Submitted"
|
||||
r.operationID = "actionMapfixBypassSubmit"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/bypass-submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "re"
|
||||
|
||||
if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
|
||||
@ -2403,30 +2315,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
switch elem[0] {
|
||||
case '-': // Prefix: "-admin"
|
||||
|
||||
if l := len("-admin"); len(elem) >= l && elem[0:l] == "-admin" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = CreateSubmissionAdminOperation
|
||||
r.summary = "Trigger the validator to create a new submission"
|
||||
r.operationID = "createSubmissionAdmin"
|
||||
r.pathPattern = "/submissions-admin"
|
||||
r.args = args
|
||||
r.count = 0
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case '/': // Prefix: "/"
|
||||
|
||||
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
|
||||
@ -2593,30 +2481,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'b': // Prefix: "bypass-submit"
|
||||
|
||||
if l := len("bypass-submit"); len(elem) >= l && elem[0:l] == "bypass-submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionBypassSubmitOperation
|
||||
r.summary = "Role Reviewer changes status from ChangesRequested -> Submitted"
|
||||
r.operationID = "actionSubmissionBypassSubmit"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/bypass-submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "re"
|
||||
|
||||
if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,51 +33,6 @@ func findAuthorization(h http.Header, prefix string) (string, bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
var operationRolesCookieAuth = map[string][]string{
|
||||
ActionMapfixAcceptedOperation: []string{},
|
||||
ActionMapfixBypassSubmitOperation: []string{},
|
||||
ActionMapfixRejectOperation: []string{},
|
||||
ActionMapfixRequestChangesOperation: []string{},
|
||||
ActionMapfixResetSubmittingOperation: []string{},
|
||||
ActionMapfixRetryValidateOperation: []string{},
|
||||
ActionMapfixRevokeOperation: []string{},
|
||||
ActionMapfixTriggerSubmitOperation: []string{},
|
||||
ActionMapfixTriggerUploadOperation: []string{},
|
||||
ActionMapfixTriggerValidateOperation: []string{},
|
||||
ActionMapfixValidatedOperation: []string{},
|
||||
ActionSubmissionAcceptedOperation: []string{},
|
||||
ActionSubmissionBypassSubmitOperation: []string{},
|
||||
ActionSubmissionRejectOperation: []string{},
|
||||
ActionSubmissionRequestChangesOperation: []string{},
|
||||
ActionSubmissionResetSubmittingOperation: []string{},
|
||||
ActionSubmissionRetryValidateOperation: []string{},
|
||||
ActionSubmissionRevokeOperation: []string{},
|
||||
ActionSubmissionTriggerSubmitOperation: []string{},
|
||||
ActionSubmissionTriggerUploadOperation: []string{},
|
||||
ActionSubmissionTriggerValidateOperation: []string{},
|
||||
ActionSubmissionValidatedOperation: []string{},
|
||||
CreateMapfixOperation: []string{},
|
||||
CreateMapfixAuditCommentOperation: []string{},
|
||||
CreateScriptOperation: []string{},
|
||||
CreateScriptPolicyOperation: []string{},
|
||||
CreateSubmissionOperation: []string{},
|
||||
CreateSubmissionAdminOperation: []string{},
|
||||
CreateSubmissionAuditCommentOperation: []string{},
|
||||
DeleteScriptOperation: []string{},
|
||||
DeleteScriptPolicyOperation: []string{},
|
||||
GetOperationOperation: []string{},
|
||||
ReleaseSubmissionsOperation: []string{},
|
||||
SessionRolesOperation: []string{},
|
||||
SessionUserOperation: []string{},
|
||||
SessionValidateOperation: []string{},
|
||||
SetMapfixCompletedOperation: []string{},
|
||||
SetSubmissionCompletedOperation: []string{},
|
||||
UpdateMapfixModelOperation: []string{},
|
||||
UpdateScriptOperation: []string{},
|
||||
UpdateScriptPolicyOperation: []string{},
|
||||
UpdateSubmissionModelOperation: []string{},
|
||||
}
|
||||
|
||||
func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {
|
||||
var t CookieAuth
|
||||
const parameterName = "session_id"
|
||||
@ -91,7 +46,6 @@ func (s *Server) securityCookieAuth(ctx context.Context, operationName Operation
|
||||
return nil, false, errors.Wrap(err, "get cookie value")
|
||||
}
|
||||
t.APIKey = value
|
||||
t.Roles = operationRolesCookieAuth[operationName]
|
||||
rctx, err := s.sec.HandleCookieAuth(ctx, operationName, t)
|
||||
if errors.Is(err, ogenerrors.ErrSkipServerSecurity) {
|
||||
return nil, false, nil
|
||||
|
@ -14,12 +14,6 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/reset-validating
|
||||
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
|
||||
// ActionMapfixBypassSubmit implements actionMapfixBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/bypass-submit
|
||||
ActionMapfixBypassSubmit(ctx context.Context, params ActionMapfixBypassSubmitParams) error
|
||||
// ActionMapfixReject implements actionMapfixReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -81,12 +75,6 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/reset-validating
|
||||
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
|
||||
// ActionSubmissionBypassSubmit implements actionSubmissionBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/bypass-submit
|
||||
ActionSubmissionBypassSubmit(ctx context.Context, params ActionSubmissionBypassSubmitParams) error
|
||||
// ActionSubmissionReject implements actionSubmissionReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -172,12 +160,6 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions
|
||||
CreateSubmission(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
|
||||
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
|
||||
//
|
||||
// Trigger the validator to create a new submission.
|
||||
//
|
||||
// POST /submissions-admin
|
||||
CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
|
||||
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
|
@ -22,15 +22,6 @@ func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params Act
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixBypassSubmit implements actionMapfixBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/bypass-submit
|
||||
func (UnimplementedHandler) ActionMapfixBypassSubmit(ctx context.Context, params ActionMapfixBypassSubmitParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixReject implements actionMapfixReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -122,15 +113,6 @@ func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionBypassSubmit implements actionSubmissionBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/bypass-submit
|
||||
func (UnimplementedHandler) ActionSubmissionBypassSubmit(ctx context.Context, params ActionSubmissionBypassSubmitParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionReject implements actionSubmissionReject operation.
|
||||
//
|
||||
// Role Reviewer changes status from Submitted -> Rejected.
|
||||
@ -258,15 +240,6 @@ func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *Submissio
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
|
||||
//
|
||||
// Trigger the validator to create a new submission.
|
||||
//
|
||||
// POST /submissions-admin
|
||||
func (UnimplementedHandler) CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (r *OperationID, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
|
@ -10,37 +10,6 @@ import (
|
||||
"github.com/ogen-go/ogen/validate"
|
||||
)
|
||||
|
||||
func (s *AuditEvent) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 64,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Username)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Username",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Error) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
@ -439,13 +408,13 @@ func (s *Mapfix) Validate() error {
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Description)); err != nil {
|
||||
}).Validate(string(s.StatusMessage)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Description",
|
||||
Name: "StatusMessage",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
@ -501,25 +470,6 @@ func (s *MapfixTriggerCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 256,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Description)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Description",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@ -1801,6 +1751,25 @@ func (s *Submission) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 256,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.StatusMessage)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "StatusMessage",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@ -1833,64 +1802,6 @@ func (s *SubmissionTriggerCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 128,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.DisplayName)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "DisplayName",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 128,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Creator)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Creator",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.GameID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "GameID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/auth"
|
||||
"git.itzana.me/strafesnet/go-grpc/maps"
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore"
|
||||
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
@ -126,8 +125,7 @@ func serve(ctx *cli.Context) error {
|
||||
svc := &service.Service{
|
||||
DB: db,
|
||||
Nats: js,
|
||||
Maps: maps.NewMapsServiceClient(conn),
|
||||
Users: users.NewUsersServiceClient(conn),
|
||||
Client: maps.NewMapsServiceClient(conn),
|
||||
}
|
||||
|
||||
conn, err = grpc.Dial(ctx.String("auth-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
@ -49,7 +49,7 @@ type Mapfixes interface {
|
||||
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) (model.Mapfix, error)
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Mapfix, error)
|
||||
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Mapfix, error)
|
||||
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (uint64, []model.Mapfix, error)
|
||||
}
|
||||
|
||||
type Operations interface {
|
||||
|
@ -10,7 +10,17 @@ func Optional() OptionalMap {
|
||||
return OptionalMap{filter: map[string]interface{}{}}
|
||||
}
|
||||
|
||||
func (q OptionalMap) Add(column string, value interface{}) OptionalMap {
|
||||
func (q OptionalMap) Add2(column string, value interface{}) OptionalMap {
|
||||
q.filter[column] = value
|
||||
return q
|
||||
}
|
||||
|
||||
func (q OptionalMap) AddPostgresInt32(column string, value uint32) OptionalMap {
|
||||
q.filter[column] = value
|
||||
return q
|
||||
}
|
||||
|
||||
func (q OptionalMap) AddPostgresInt64(column string, value uint64) OptionalMap {
|
||||
q.filter[column] = value
|
||||
return q
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ func (env *Mapfixes) List(ctx context.Context, filters datastore.OptionalMap, pa
|
||||
return maps, nil
|
||||
}
|
||||
|
||||
func (env *Mapfixes) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Mapfix, error) {
|
||||
func (env *Mapfixes) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (uint64, []model.Mapfix, error) {
|
||||
// grab page items
|
||||
maps, err := env.List(ctx, filters, page, sort)
|
||||
if err != nil{
|
||||
@ -144,5 +144,5 @@ func (env *Mapfixes) ListWithTotal(ctx context.Context, filters datastore.Option
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return total, maps, nil
|
||||
return uint64(total), maps, nil
|
||||
}
|
||||
|
@ -34,12 +34,6 @@ type Invoker interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
|
||||
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -70,12 +64,6 @@ type Invoker interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-failed
|
||||
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
|
||||
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -253,7 +241,7 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -269,15 +257,15 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
// Encode "StatusMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Name: "StatusMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
return e.EncodeValue(conv.StringToString(params.StatusMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -306,115 +294,6 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (c *Client) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
|
||||
_, err := c.sendActionMapfixRequestChanges(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) (res *ActionMapfixRequestChangesNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// 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, ActionMapfixRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/mapfixes/"
|
||||
{
|
||||
// Encode "MapfixID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "MapfixID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-request-changes"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionMapfixRequestChangesResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -471,7 +350,7 @@ func (c *Client) sendActionMapfixSubmitted(ctx context.Context, params ActionMap
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -484,66 +363,6 @@ func (c *Client) sendActionMapfixSubmitted(ctx context.Context, params ActionMap
|
||||
pathParts[2] = "/status/validator-submitted"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ModelVersion" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ModelVersion",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "DisplayName" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "DisplayName",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.DisplayName))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "Creator" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "Creator",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.Creator))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "GameID" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "GameID",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.GameID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
@ -622,7 +441,7 @@ func (c *Client) sendActionMapfixUploaded(ctx context.Context, params ActionMapf
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -713,7 +532,7 @@ func (c *Client) sendActionMapfixValidated(ctx context.Context, params ActionMap
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -804,7 +623,7 @@ func (c *Client) sendActionOperationFailed(ctx context.Context, params ActionOpe
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.OperationID))
|
||||
return e.EncodeValue(conv.Uint32ToString(params.OperationID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -913,7 +732,7 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -929,15 +748,15 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
// Encode "StatusMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Name: "StatusMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
return e.EncodeValue(conv.StringToString(params.StatusMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -966,115 +785,6 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (c *Client) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
|
||||
_, err := c.sendActionSubmissionRequestChanges(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) (res *ActionSubmissionRequestChangesNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// 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, ActionSubmissionRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/submissions/"
|
||||
{
|
||||
// Encode "SubmissionID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "SubmissionID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-request-changes"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionSubmissionRequestChangesResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -1131,7 +841,7 @@ func (c *Client) sendActionSubmissionSubmitted(ctx context.Context, params Actio
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -1144,66 +854,6 @@ func (c *Client) sendActionSubmissionSubmitted(ctx context.Context, params Actio
|
||||
pathParts[2] = "/status/validator-submitted"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ModelVersion" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ModelVersion",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "DisplayName" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "DisplayName",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.DisplayName))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "Creator" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "Creator",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.Creator))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "GameID" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "GameID",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.GameID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
@ -1282,7 +932,7 @@ func (c *Client) sendActionSubmissionUploaded(ctx context.Context, params Action
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -1306,7 +956,7 @@ func (c *Client) sendActionSubmissionUploaded(ctx context.Context, params Action
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.UploadedAssetID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.UploadedAssetID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -1391,7 +1041,7 @@ func (c *Client) sendActionSubmissionValidated(ctx context.Context, params Actio
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -1782,7 +1432,7 @@ func (c *Client) sendGetScript(ctx context.Context, params GetScriptParams) (res
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ScriptID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.ScriptID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -1877,7 +1527,7 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.Page))
|
||||
return e.EncodeValue(conv.Uint32ToString(params.Page))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -1891,7 +1541,7 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.Limit))
|
||||
return e.EncodeValue(conv.Uint32ToString(params.Limit))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -1923,7 +1573,7 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
if val, ok := params.ToScriptID.Get(); ok {
|
||||
return e.EncodeValue(conv.Int64ToString(val))
|
||||
return e.EncodeValue(conv.Uint64ToString(val))
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -1940,7 +1590,7 @@ func (c *Client) sendListScriptPolicy(ctx context.Context, params ListScriptPoli
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
if val, ok := params.Policy.Get(); ok {
|
||||
return e.EncodeValue(conv.Int32ToString(val))
|
||||
return e.EncodeValue(conv.Uint32ToString(val))
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -2032,7 +1682,7 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams)
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.Page))
|
||||
return e.EncodeValue(conv.Uint32ToString(params.Page))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -2046,7 +1696,7 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams)
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.Limit))
|
||||
return e.EncodeValue(conv.Uint32ToString(params.Limit))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -2112,7 +1762,7 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams)
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
if val, ok := params.ResourceType.Get(); ok {
|
||||
return e.EncodeValue(conv.Int32ToString(val))
|
||||
return e.EncodeValue(conv.Uint32ToString(val))
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -2129,7 +1779,7 @@ func (c *Client) sendListScripts(ctx context.Context, params ListScriptsParams)
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
if val, ok := params.ResourceID.Get(); ok {
|
||||
return e.EncodeValue(conv.Int64ToString(val))
|
||||
return e.EncodeValue(conv.Uint64ToString(val))
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
@ -2216,7 +1866,7 @@ func (c *Client) sendUpdateMapfixValidatedModel(ctx context.Context, params Upda
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -2240,7 +1890,7 @@ func (c *Client) sendUpdateMapfixValidatedModel(ctx context.Context, params Upda
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ValidatedModelID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.ValidatedModelID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -2254,7 +1904,7 @@ func (c *Client) sendUpdateMapfixValidatedModel(ctx context.Context, params Upda
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ValidatedModelVersion))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.ValidatedModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -2339,7 +1989,7 @@ func (c *Client) sendUpdateSubmissionValidatedModel(ctx context.Context, params
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
@ -2363,7 +2013,7 @@ func (c *Client) sendUpdateSubmissionValidatedModel(ctx context.Context, params
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ValidatedModelID))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.ValidatedModelID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@ -2377,7 +2027,7 @@ func (c *Client) sendUpdateSubmissionValidatedModel(ctx context.Context, params
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ValidatedModelVersion))
|
||||
return e.EncodeValue(conv.Uint64ToString(params.ValidatedModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
|
@ -129,9 +129,9 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
Name: "StatusMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
}: params.StatusMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
@ -183,159 +183,6 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixRequestChangesRequest handles actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRequestChangesOperation,
|
||||
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: ActionMapfixRequestChangesOperation,
|
||||
ID: "actionMapfixRequestChanges",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionMapfixRequestChangesParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionMapfixRequestChangesNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionMapfixRequestChangesOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
|
||||
OperationID: "actionMapfixRequestChanges",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "MapfixID",
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionMapfixRequestChangesParams
|
||||
Response = *ActionMapfixRequestChangesNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionMapfixRequestChangesParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionMapfixRequestChanges(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionMapfixRequestChanges(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionMapfixRequestChangesResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixSubmittedRequest handles actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -434,22 +281,6 @@ func (s *Server) handleActionMapfixSubmittedRequest(args [1]string, argsEscaped
|
||||
Name: "MapfixID",
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "ModelVersion",
|
||||
In: "query",
|
||||
}: params.ModelVersion,
|
||||
{
|
||||
Name: "DisplayName",
|
||||
In: "query",
|
||||
}: params.DisplayName,
|
||||
{
|
||||
Name: "Creator",
|
||||
In: "query",
|
||||
}: params.Creator,
|
||||
{
|
||||
Name: "GameID",
|
||||
In: "query",
|
||||
}: params.GameID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
@ -1051,9 +882,9 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
Name: "StatusMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
}: params.StatusMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
@ -1105,159 +936,6 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionRequestChangesRequest handles actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRequestChangesOperation,
|
||||
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: ActionSubmissionRequestChangesOperation,
|
||||
ID: "actionSubmissionRequestChanges",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionSubmissionRequestChangesParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionSubmissionRequestChangesNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionSubmissionRequestChangesOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
|
||||
OperationID: "actionSubmissionRequestChanges",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "SubmissionID",
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionSubmissionRequestChangesParams
|
||||
Response = *ActionSubmissionRequestChangesNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionSubmissionRequestChangesParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionSubmissionRequestChanges(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionSubmissionRequestChanges(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionSubmissionRequestChangesResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionSubmittedRequest handles actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -1356,22 +1034,6 @@ func (s *Server) handleActionSubmissionSubmittedRequest(args [1]string, argsEsca
|
||||
Name: "SubmissionID",
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "ModelVersion",
|
||||
In: "query",
|
||||
}: params.ModelVersion,
|
||||
{
|
||||
Name: "DisplayName",
|
||||
In: "query",
|
||||
}: params.DisplayName,
|
||||
{
|
||||
Name: "Creator",
|
||||
In: "query",
|
||||
}: params.Creator,
|
||||
{
|
||||
Name: "GameID",
|
||||
In: "query",
|
||||
}: params.GameID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ func (s *Error) Encode(e *jx.Encoder) {
|
||||
func (s *Error) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("code")
|
||||
e.Int64(s.Code)
|
||||
e.UInt64(s.Code)
|
||||
}
|
||||
{
|
||||
e.FieldStart("message")
|
||||
@ -48,8 +48,8 @@ func (s *Error) Decode(d *jx.Decoder) error {
|
||||
case "code":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.Code = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.Code = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -136,11 +136,11 @@ func (s *MapfixCreate) Encode(e *jx.Encoder) {
|
||||
func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("OperationID")
|
||||
e.Int32(s.OperationID)
|
||||
e.UInt32(s.OperationID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetOwner")
|
||||
e.Int64(s.AssetOwner)
|
||||
e.UInt64(s.AssetOwner)
|
||||
}
|
||||
{
|
||||
e.FieldStart("DisplayName")
|
||||
@ -152,27 +152,23 @@ func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
|
||||
}
|
||||
{
|
||||
e.FieldStart("GameID")
|
||||
e.Int32(s.GameID)
|
||||
e.UInt32(s.GameID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetID")
|
||||
e.Int64(s.AssetID)
|
||||
e.UInt64(s.AssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetVersion")
|
||||
e.Int64(s.AssetVersion)
|
||||
e.UInt64(s.AssetVersion)
|
||||
}
|
||||
{
|
||||
e.FieldStart("TargetAssetID")
|
||||
e.Int64(s.TargetAssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Description")
|
||||
e.Str(s.Description)
|
||||
e.UInt64(s.TargetAssetID)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfMapfixCreate = [9]string{
|
||||
var jsonFieldsNameOfMapfixCreate = [8]string{
|
||||
0: "OperationID",
|
||||
1: "AssetOwner",
|
||||
2: "DisplayName",
|
||||
@ -181,7 +177,6 @@ var jsonFieldsNameOfMapfixCreate = [9]string{
|
||||
5: "AssetID",
|
||||
6: "AssetVersion",
|
||||
7: "TargetAssetID",
|
||||
8: "Description",
|
||||
}
|
||||
|
||||
// Decode decodes MapfixCreate from json.
|
||||
@ -189,15 +184,15 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode MapfixCreate to nil")
|
||||
}
|
||||
var requiredBitSet [2]uint8
|
||||
var requiredBitSet [1]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "OperationID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.OperationID = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.OperationID = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -208,8 +203,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetOwner":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetOwner = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetOwner = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -244,8 +239,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
case "GameID":
|
||||
requiredBitSet[0] |= 1 << 4
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.GameID = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.GameID = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -256,8 +251,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetID":
|
||||
requiredBitSet[0] |= 1 << 5
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -268,8 +263,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetVersion":
|
||||
requiredBitSet[0] |= 1 << 6
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetVersion = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetVersion = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -280,8 +275,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
case "TargetAssetID":
|
||||
requiredBitSet[0] |= 1 << 7
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.TargetAssetID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.TargetAssetID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -289,18 +284,6 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"TargetAssetID\"")
|
||||
}
|
||||
case "Description":
|
||||
requiredBitSet[1] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Description = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Description\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@ -310,9 +293,8 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [2]uint8{
|
||||
for i, mask := range [1]uint8{
|
||||
0b11111111,
|
||||
0b00000001,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@ -369,7 +351,7 @@ func (s *MapfixID) Encode(e *jx.Encoder) {
|
||||
func (s *MapfixID) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("MapfixID")
|
||||
e.Int64(s.MapfixID)
|
||||
e.UInt64(s.MapfixID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,8 +371,8 @@ func (s *MapfixID) Decode(d *jx.Decoder) error {
|
||||
case "MapfixID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.MapfixID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.MapfixID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -454,37 +436,37 @@ func (s *MapfixID) UnmarshalJSON(data []byte) error {
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode encodes int64 as json.
|
||||
func (o OptInt64) Encode(e *jx.Encoder) {
|
||||
// Encode encodes uint64 as json.
|
||||
func (o OptUint64) Encode(e *jx.Encoder) {
|
||||
if !o.Set {
|
||||
return
|
||||
}
|
||||
e.Int64(int64(o.Value))
|
||||
e.UInt64(uint64(o.Value))
|
||||
}
|
||||
|
||||
// Decode decodes int64 from json.
|
||||
func (o *OptInt64) Decode(d *jx.Decoder) error {
|
||||
// Decode decodes uint64 from json.
|
||||
func (o *OptUint64) Decode(d *jx.Decoder) error {
|
||||
if o == nil {
|
||||
return errors.New("invalid: unable to decode OptInt64 to nil")
|
||||
return errors.New("invalid: unable to decode OptUint64 to nil")
|
||||
}
|
||||
o.Set = true
|
||||
v, err := d.Int64()
|
||||
v, err := d.UInt64()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.Value = int64(v)
|
||||
o.Value = uint64(v)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s OptInt64) MarshalJSON() ([]byte, error) {
|
||||
func (s OptUint64) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *OptInt64) UnmarshalJSON(data []byte) error {
|
||||
func (s *OptUint64) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
@ -500,7 +482,7 @@ func (s *Script) Encode(e *jx.Encoder) {
|
||||
func (s *Script) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("ID")
|
||||
e.Int64(s.ID)
|
||||
e.UInt64(s.ID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Name")
|
||||
@ -516,11 +498,11 @@ func (s *Script) encodeFields(e *jx.Encoder) {
|
||||
}
|
||||
{
|
||||
e.FieldStart("ResourceType")
|
||||
e.Int32(s.ResourceType)
|
||||
e.UInt32(s.ResourceType)
|
||||
}
|
||||
{
|
||||
e.FieldStart("ResourceID")
|
||||
e.Int64(s.ResourceID)
|
||||
e.UInt64(s.ResourceID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -545,8 +527,8 @@ func (s *Script) Decode(d *jx.Decoder) error {
|
||||
case "ID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -593,8 +575,8 @@ func (s *Script) Decode(d *jx.Decoder) error {
|
||||
case "ResourceType":
|
||||
requiredBitSet[0] |= 1 << 4
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.ResourceType = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.ResourceType = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -605,8 +587,8 @@ func (s *Script) Decode(d *jx.Decoder) error {
|
||||
case "ResourceID":
|
||||
requiredBitSet[0] |= 1 << 5
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ResourceID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ResourceID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -689,7 +671,7 @@ func (s *ScriptCreate) encodeFields(e *jx.Encoder) {
|
||||
}
|
||||
{
|
||||
e.FieldStart("ResourceType")
|
||||
e.Int32(s.ResourceType)
|
||||
e.UInt32(s.ResourceType)
|
||||
}
|
||||
{
|
||||
if s.ResourceID.Set {
|
||||
@ -742,8 +724,8 @@ func (s *ScriptCreate) Decode(d *jx.Decoder) error {
|
||||
case "ResourceType":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.ResourceType = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.ResourceType = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -828,7 +810,7 @@ func (s *ScriptID) Encode(e *jx.Encoder) {
|
||||
func (s *ScriptID) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("ScriptID")
|
||||
e.Int64(s.ScriptID)
|
||||
e.UInt64(s.ScriptID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -848,8 +830,8 @@ func (s *ScriptID) Decode(d *jx.Decoder) error {
|
||||
case "ScriptID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ScriptID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ScriptID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -924,7 +906,7 @@ func (s *ScriptPolicy) Encode(e *jx.Encoder) {
|
||||
func (s *ScriptPolicy) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("ID")
|
||||
e.Int64(s.ID)
|
||||
e.UInt64(s.ID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("FromScriptHash")
|
||||
@ -932,11 +914,11 @@ func (s *ScriptPolicy) encodeFields(e *jx.Encoder) {
|
||||
}
|
||||
{
|
||||
e.FieldStart("ToScriptID")
|
||||
e.Int64(s.ToScriptID)
|
||||
e.UInt64(s.ToScriptID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Policy")
|
||||
e.Int32(s.Policy)
|
||||
e.UInt32(s.Policy)
|
||||
}
|
||||
}
|
||||
|
||||
@ -959,8 +941,8 @@ func (s *ScriptPolicy) Decode(d *jx.Decoder) error {
|
||||
case "ID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -983,8 +965,8 @@ func (s *ScriptPolicy) Decode(d *jx.Decoder) error {
|
||||
case "ToScriptID":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ToScriptID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ToScriptID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -995,8 +977,8 @@ func (s *ScriptPolicy) Decode(d *jx.Decoder) error {
|
||||
case "Policy":
|
||||
requiredBitSet[0] |= 1 << 3
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.Policy = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.Policy = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1071,15 +1053,15 @@ func (s *ScriptPolicyCreate) Encode(e *jx.Encoder) {
|
||||
func (s *ScriptPolicyCreate) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("FromScriptID")
|
||||
e.Int64(s.FromScriptID)
|
||||
e.UInt64(s.FromScriptID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("ToScriptID")
|
||||
e.Int64(s.ToScriptID)
|
||||
e.UInt64(s.ToScriptID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Policy")
|
||||
e.Int32(s.Policy)
|
||||
e.UInt32(s.Policy)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1101,8 +1083,8 @@ func (s *ScriptPolicyCreate) Decode(d *jx.Decoder) error {
|
||||
case "FromScriptID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.FromScriptID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.FromScriptID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1113,8 +1095,8 @@ func (s *ScriptPolicyCreate) Decode(d *jx.Decoder) error {
|
||||
case "ToScriptID":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ToScriptID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ToScriptID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1125,8 +1107,8 @@ func (s *ScriptPolicyCreate) Decode(d *jx.Decoder) error {
|
||||
case "Policy":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.Policy = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.Policy = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1201,7 +1183,7 @@ func (s *ScriptPolicyID) Encode(e *jx.Encoder) {
|
||||
func (s *ScriptPolicyID) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("ScriptPolicyID")
|
||||
e.Int64(s.ScriptPolicyID)
|
||||
e.UInt64(s.ScriptPolicyID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1221,8 +1203,8 @@ func (s *ScriptPolicyID) Decode(d *jx.Decoder) error {
|
||||
case "ScriptPolicyID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ScriptPolicyID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.ScriptPolicyID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1297,11 +1279,11 @@ func (s *SubmissionCreate) Encode(e *jx.Encoder) {
|
||||
func (s *SubmissionCreate) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("OperationID")
|
||||
e.Int32(s.OperationID)
|
||||
e.UInt32(s.OperationID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetOwner")
|
||||
e.Int64(s.AssetOwner)
|
||||
e.UInt64(s.AssetOwner)
|
||||
}
|
||||
{
|
||||
e.FieldStart("DisplayName")
|
||||
@ -1313,27 +1295,19 @@ func (s *SubmissionCreate) encodeFields(e *jx.Encoder) {
|
||||
}
|
||||
{
|
||||
e.FieldStart("GameID")
|
||||
e.Int32(s.GameID)
|
||||
e.UInt32(s.GameID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetID")
|
||||
e.Int64(s.AssetID)
|
||||
e.UInt64(s.AssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("AssetVersion")
|
||||
e.Int64(s.AssetVersion)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Status")
|
||||
e.UInt32(s.Status)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Roles")
|
||||
e.UInt32(s.Roles)
|
||||
e.UInt64(s.AssetVersion)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfSubmissionCreate = [9]string{
|
||||
var jsonFieldsNameOfSubmissionCreate = [7]string{
|
||||
0: "OperationID",
|
||||
1: "AssetOwner",
|
||||
2: "DisplayName",
|
||||
@ -1341,8 +1315,6 @@ var jsonFieldsNameOfSubmissionCreate = [9]string{
|
||||
4: "GameID",
|
||||
5: "AssetID",
|
||||
6: "AssetVersion",
|
||||
7: "Status",
|
||||
8: "Roles",
|
||||
}
|
||||
|
||||
// Decode decodes SubmissionCreate from json.
|
||||
@ -1350,15 +1322,15 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode SubmissionCreate to nil")
|
||||
}
|
||||
var requiredBitSet [2]uint8
|
||||
var requiredBitSet [1]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "OperationID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.OperationID = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.OperationID = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1369,8 +1341,8 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetOwner":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetOwner = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetOwner = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1405,8 +1377,8 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
case "GameID":
|
||||
requiredBitSet[0] |= 1 << 4
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.GameID = int32(v)
|
||||
v, err := d.UInt32()
|
||||
s.GameID = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1417,8 +1389,8 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetID":
|
||||
requiredBitSet[0] |= 1 << 5
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1429,8 +1401,8 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
case "AssetVersion":
|
||||
requiredBitSet[0] |= 1 << 6
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.AssetVersion = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.AssetVersion = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1438,30 +1410,6 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"AssetVersion\"")
|
||||
}
|
||||
case "Status":
|
||||
requiredBitSet[0] |= 1 << 7
|
||||
if err := func() error {
|
||||
v, err := d.UInt32()
|
||||
s.Status = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Status\"")
|
||||
}
|
||||
case "Roles":
|
||||
requiredBitSet[1] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.UInt32()
|
||||
s.Roles = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Roles\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@ -1471,9 +1419,8 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [2]uint8{
|
||||
0b11111111,
|
||||
0b00000001,
|
||||
for i, mask := range [1]uint8{
|
||||
0b01111111,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@ -1530,7 +1477,7 @@ func (s *SubmissionID) Encode(e *jx.Encoder) {
|
||||
func (s *SubmissionID) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("SubmissionID")
|
||||
e.Int64(s.SubmissionID)
|
||||
e.UInt64(s.SubmissionID)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1550,8 +1497,8 @@ func (s *SubmissionID) Decode(d *jx.Decoder) error {
|
||||
case "SubmissionID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.SubmissionID = int64(v)
|
||||
v, err := d.UInt64()
|
||||
s.SubmissionID = uint64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -7,13 +7,11 @@ type OperationName = string
|
||||
|
||||
const (
|
||||
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
|
||||
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
|
||||
ActionMapfixSubmittedOperation OperationName = "ActionMapfixSubmitted"
|
||||
ActionMapfixUploadedOperation OperationName = "ActionMapfixUploaded"
|
||||
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
|
||||
ActionOperationFailedOperation OperationName = "ActionOperationFailed"
|
||||
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
|
||||
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
|
||||
ActionSubmissionSubmittedOperation OperationName = "ActionSubmissionSubmitted"
|
||||
ActionSubmissionUploadedOperation OperationName = "ActionSubmissionUploaded"
|
||||
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/go-faster/jx"
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"github.com/ogen-go/ogen/ogenerrors"
|
||||
"github.com/ogen-go/ogen/validate"
|
||||
@ -25,13 +26,13 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -96,13 +97,13 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -167,13 +168,13 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
@ -238,13 +239,13 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = errors.Join(merr, c())
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = errors.Join(rerr, close())
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
|
@ -75,66 +75,6 @@ func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixA
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionMapfixRequestChangesResponse(resp *http.Response) (res *ActionMapfixRequestChangesNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionMapfixRequestChangesNoContent{}, 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 decodeActionMapfixSubmittedResponse(resp *http.Response) (res *ActionMapfixSubmittedNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
@ -435,66 +375,6 @@ func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSub
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionSubmissionRequestChangesResponse(resp *http.Response) (res *ActionSubmissionRequestChangesNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionSubmissionRequestChangesNoContent{}, 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 decodeActionSubmissionSubmittedResponse(resp *http.Response) (res *ActionSubmissionSubmittedNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
|
@ -20,13 +20,6 @@ func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent,
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixSubmittedResponse(response *ActionMapfixSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@ -62,13 +55,6 @@ func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNo
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionSubmittedResponse(response *ActionSubmissionSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
@ -147,28 +147,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixRequestChangesRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
@ -498,28 +476,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionRequestChangesRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
@ -804,30 +760,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixRequestChangesOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested"
|
||||
r.operationID = "actionMapfixRequestChanges"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/validator-request-changes"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
@ -1195,30 +1127,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionRequestChangesOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested"
|
||||
r.operationID = "actionSubmissionRequestChanges"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/validator-request-changes"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
|
@ -13,9 +13,6 @@ func (s *ErrorStatusCode) Error() string {
|
||||
// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
|
||||
type ActionMapfixAcceptedNoContent struct{}
|
||||
|
||||
// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
|
||||
type ActionMapfixRequestChangesNoContent struct{}
|
||||
|
||||
// ActionMapfixSubmittedNoContent is response for ActionMapfixSubmitted operation.
|
||||
type ActionMapfixSubmittedNoContent struct{}
|
||||
|
||||
@ -31,9 +28,6 @@ type ActionOperationFailedNoContent struct{}
|
||||
// ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
|
||||
type ActionSubmissionAcceptedNoContent struct{}
|
||||
|
||||
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation.
|
||||
type ActionSubmissionRequestChangesNoContent struct{}
|
||||
|
||||
// ActionSubmissionSubmittedNoContent is response for ActionSubmissionSubmitted operation.
|
||||
type ActionSubmissionSubmittedNoContent struct{}
|
||||
|
||||
@ -46,12 +40,12 @@ type ActionSubmissionValidatedNoContent struct{}
|
||||
// Represents error object.
|
||||
// Ref: #/components/schemas/Error
|
||||
type Error struct {
|
||||
Code int64 `json:"code"`
|
||||
Code uint64 `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// GetCode returns the value of Code.
|
||||
func (s *Error) GetCode() int64 {
|
||||
func (s *Error) GetCode() uint64 {
|
||||
return s.Code
|
||||
}
|
||||
|
||||
@ -61,7 +55,7 @@ func (s *Error) GetMessage() string {
|
||||
}
|
||||
|
||||
// SetCode sets the value of Code.
|
||||
func (s *Error) SetCode(val int64) {
|
||||
func (s *Error) SetCode(val uint64) {
|
||||
s.Code = val
|
||||
}
|
||||
|
||||
@ -98,24 +92,23 @@ func (s *ErrorStatusCode) SetResponse(val Error) {
|
||||
|
||||
// Ref: #/components/schemas/MapfixCreate
|
||||
type MapfixCreate struct {
|
||||
OperationID int32 `json:"OperationID"`
|
||||
AssetOwner int64 `json:"AssetOwner"`
|
||||
OperationID uint32 `json:"OperationID"`
|
||||
AssetOwner uint64 `json:"AssetOwner"`
|
||||
DisplayName string `json:"DisplayName"`
|
||||
Creator string `json:"Creator"`
|
||||
GameID int32 `json:"GameID"`
|
||||
AssetID int64 `json:"AssetID"`
|
||||
AssetVersion int64 `json:"AssetVersion"`
|
||||
TargetAssetID int64 `json:"TargetAssetID"`
|
||||
Description string `json:"Description"`
|
||||
GameID uint32 `json:"GameID"`
|
||||
AssetID uint64 `json:"AssetID"`
|
||||
AssetVersion uint64 `json:"AssetVersion"`
|
||||
TargetAssetID uint64 `json:"TargetAssetID"`
|
||||
}
|
||||
|
||||
// GetOperationID returns the value of OperationID.
|
||||
func (s *MapfixCreate) GetOperationID() int32 {
|
||||
func (s *MapfixCreate) GetOperationID() uint32 {
|
||||
return s.OperationID
|
||||
}
|
||||
|
||||
// GetAssetOwner returns the value of AssetOwner.
|
||||
func (s *MapfixCreate) GetAssetOwner() int64 {
|
||||
func (s *MapfixCreate) GetAssetOwner() uint64 {
|
||||
return s.AssetOwner
|
||||
}
|
||||
|
||||
@ -130,37 +123,32 @@ func (s *MapfixCreate) GetCreator() string {
|
||||
}
|
||||
|
||||
// GetGameID returns the value of GameID.
|
||||
func (s *MapfixCreate) GetGameID() int32 {
|
||||
func (s *MapfixCreate) GetGameID() uint32 {
|
||||
return s.GameID
|
||||
}
|
||||
|
||||
// GetAssetID returns the value of AssetID.
|
||||
func (s *MapfixCreate) GetAssetID() int64 {
|
||||
func (s *MapfixCreate) GetAssetID() uint64 {
|
||||
return s.AssetID
|
||||
}
|
||||
|
||||
// GetAssetVersion returns the value of AssetVersion.
|
||||
func (s *MapfixCreate) GetAssetVersion() int64 {
|
||||
func (s *MapfixCreate) GetAssetVersion() uint64 {
|
||||
return s.AssetVersion
|
||||
}
|
||||
|
||||
// GetTargetAssetID returns the value of TargetAssetID.
|
||||
func (s *MapfixCreate) GetTargetAssetID() int64 {
|
||||
func (s *MapfixCreate) GetTargetAssetID() uint64 {
|
||||
return s.TargetAssetID
|
||||
}
|
||||
|
||||
// GetDescription returns the value of Description.
|
||||
func (s *MapfixCreate) GetDescription() string {
|
||||
return s.Description
|
||||
}
|
||||
|
||||
// SetOperationID sets the value of OperationID.
|
||||
func (s *MapfixCreate) SetOperationID(val int32) {
|
||||
func (s *MapfixCreate) SetOperationID(val uint32) {
|
||||
s.OperationID = val
|
||||
}
|
||||
|
||||
// SetAssetOwner sets the value of AssetOwner.
|
||||
func (s *MapfixCreate) SetAssetOwner(val int64) {
|
||||
func (s *MapfixCreate) SetAssetOwner(val uint64) {
|
||||
s.AssetOwner = val
|
||||
}
|
||||
|
||||
@ -175,137 +163,40 @@ func (s *MapfixCreate) SetCreator(val string) {
|
||||
}
|
||||
|
||||
// SetGameID sets the value of GameID.
|
||||
func (s *MapfixCreate) SetGameID(val int32) {
|
||||
func (s *MapfixCreate) SetGameID(val uint32) {
|
||||
s.GameID = val
|
||||
}
|
||||
|
||||
// SetAssetID sets the value of AssetID.
|
||||
func (s *MapfixCreate) SetAssetID(val int64) {
|
||||
func (s *MapfixCreate) SetAssetID(val uint64) {
|
||||
s.AssetID = val
|
||||
}
|
||||
|
||||
// SetAssetVersion sets the value of AssetVersion.
|
||||
func (s *MapfixCreate) SetAssetVersion(val int64) {
|
||||
func (s *MapfixCreate) SetAssetVersion(val uint64) {
|
||||
s.AssetVersion = val
|
||||
}
|
||||
|
||||
// SetTargetAssetID sets the value of TargetAssetID.
|
||||
func (s *MapfixCreate) SetTargetAssetID(val int64) {
|
||||
func (s *MapfixCreate) SetTargetAssetID(val uint64) {
|
||||
s.TargetAssetID = val
|
||||
}
|
||||
|
||||
// SetDescription sets the value of Description.
|
||||
func (s *MapfixCreate) SetDescription(val string) {
|
||||
s.Description = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/MapfixID
|
||||
type MapfixID struct {
|
||||
MapfixID int64 `json:"MapfixID"`
|
||||
MapfixID uint64 `json:"MapfixID"`
|
||||
}
|
||||
|
||||
// GetMapfixID returns the value of MapfixID.
|
||||
func (s *MapfixID) GetMapfixID() int64 {
|
||||
func (s *MapfixID) GetMapfixID() uint64 {
|
||||
return s.MapfixID
|
||||
}
|
||||
|
||||
// SetMapfixID sets the value of MapfixID.
|
||||
func (s *MapfixID) SetMapfixID(val int64) {
|
||||
func (s *MapfixID) SetMapfixID(val uint64) {
|
||||
s.MapfixID = val
|
||||
}
|
||||
|
||||
// NewOptInt32 returns new OptInt32 with value set to v.
|
||||
func NewOptInt32(v int32) OptInt32 {
|
||||
return OptInt32{
|
||||
Value: v,
|
||||
Set: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OptInt32 is optional int32.
|
||||
type OptInt32 struct {
|
||||
Value int32
|
||||
Set bool
|
||||
}
|
||||
|
||||
// IsSet returns true if OptInt32 was set.
|
||||
func (o OptInt32) IsSet() bool { return o.Set }
|
||||
|
||||
// Reset unsets value.
|
||||
func (o *OptInt32) Reset() {
|
||||
var v int32
|
||||
o.Value = v
|
||||
o.Set = false
|
||||
}
|
||||
|
||||
// SetTo sets value to v.
|
||||
func (o *OptInt32) SetTo(v int32) {
|
||||
o.Set = true
|
||||
o.Value = v
|
||||
}
|
||||
|
||||
// Get returns value and boolean that denotes whether value was set.
|
||||
func (o OptInt32) Get() (v int32, ok bool) {
|
||||
if !o.Set {
|
||||
return v, false
|
||||
}
|
||||
return o.Value, true
|
||||
}
|
||||
|
||||
// Or returns value if set, or given parameter if does not.
|
||||
func (o OptInt32) Or(d int32) int32 {
|
||||
if v, ok := o.Get(); ok {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NewOptInt64 returns new OptInt64 with value set to v.
|
||||
func NewOptInt64(v int64) OptInt64 {
|
||||
return OptInt64{
|
||||
Value: v,
|
||||
Set: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OptInt64 is optional int64.
|
||||
type OptInt64 struct {
|
||||
Value int64
|
||||
Set bool
|
||||
}
|
||||
|
||||
// IsSet returns true if OptInt64 was set.
|
||||
func (o OptInt64) IsSet() bool { return o.Set }
|
||||
|
||||
// Reset unsets value.
|
||||
func (o *OptInt64) Reset() {
|
||||
var v int64
|
||||
o.Value = v
|
||||
o.Set = false
|
||||
}
|
||||
|
||||
// SetTo sets value to v.
|
||||
func (o *OptInt64) SetTo(v int64) {
|
||||
o.Set = true
|
||||
o.Value = v
|
||||
}
|
||||
|
||||
// Get returns value and boolean that denotes whether value was set.
|
||||
func (o OptInt64) Get() (v int64, ok bool) {
|
||||
if !o.Set {
|
||||
return v, false
|
||||
}
|
||||
return o.Value, true
|
||||
}
|
||||
|
||||
// Or returns value if set, or given parameter if does not.
|
||||
func (o OptInt64) Or(d int64) int64 {
|
||||
if v, ok := o.Get(); ok {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NewOptString returns new OptString with value set to v.
|
||||
func NewOptString(v string) OptString {
|
||||
return OptString{
|
||||
@ -352,18 +243,110 @@ func (o OptString) Or(d string) string {
|
||||
return d
|
||||
}
|
||||
|
||||
// NewOptUint32 returns new OptUint32 with value set to v.
|
||||
func NewOptUint32(v uint32) OptUint32 {
|
||||
return OptUint32{
|
||||
Value: v,
|
||||
Set: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OptUint32 is optional uint32.
|
||||
type OptUint32 struct {
|
||||
Value uint32
|
||||
Set bool
|
||||
}
|
||||
|
||||
// IsSet returns true if OptUint32 was set.
|
||||
func (o OptUint32) IsSet() bool { return o.Set }
|
||||
|
||||
// Reset unsets value.
|
||||
func (o *OptUint32) Reset() {
|
||||
var v uint32
|
||||
o.Value = v
|
||||
o.Set = false
|
||||
}
|
||||
|
||||
// SetTo sets value to v.
|
||||
func (o *OptUint32) SetTo(v uint32) {
|
||||
o.Set = true
|
||||
o.Value = v
|
||||
}
|
||||
|
||||
// Get returns value and boolean that denotes whether value was set.
|
||||
func (o OptUint32) Get() (v uint32, ok bool) {
|
||||
if !o.Set {
|
||||
return v, false
|
||||
}
|
||||
return o.Value, true
|
||||
}
|
||||
|
||||
// Or returns value if set, or given parameter if does not.
|
||||
func (o OptUint32) Or(d uint32) uint32 {
|
||||
if v, ok := o.Get(); ok {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// NewOptUint64 returns new OptUint64 with value set to v.
|
||||
func NewOptUint64(v uint64) OptUint64 {
|
||||
return OptUint64{
|
||||
Value: v,
|
||||
Set: true,
|
||||
}
|
||||
}
|
||||
|
||||
// OptUint64 is optional uint64.
|
||||
type OptUint64 struct {
|
||||
Value uint64
|
||||
Set bool
|
||||
}
|
||||
|
||||
// IsSet returns true if OptUint64 was set.
|
||||
func (o OptUint64) IsSet() bool { return o.Set }
|
||||
|
||||
// Reset unsets value.
|
||||
func (o *OptUint64) Reset() {
|
||||
var v uint64
|
||||
o.Value = v
|
||||
o.Set = false
|
||||
}
|
||||
|
||||
// SetTo sets value to v.
|
||||
func (o *OptUint64) SetTo(v uint64) {
|
||||
o.Set = true
|
||||
o.Value = v
|
||||
}
|
||||
|
||||
// Get returns value and boolean that denotes whether value was set.
|
||||
func (o OptUint64) Get() (v uint64, ok bool) {
|
||||
if !o.Set {
|
||||
return v, false
|
||||
}
|
||||
return o.Value, true
|
||||
}
|
||||
|
||||
// Or returns value if set, or given parameter if does not.
|
||||
func (o OptUint64) Or(d uint64) uint64 {
|
||||
if v, ok := o.Get(); ok {
|
||||
return v
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/Script
|
||||
type Script struct {
|
||||
ID int64 `json:"ID"`
|
||||
ID uint64 `json:"ID"`
|
||||
Name string `json:"Name"`
|
||||
Hash string `json:"Hash"`
|
||||
Source string `json:"Source"`
|
||||
ResourceType int32 `json:"ResourceType"`
|
||||
ResourceID int64 `json:"ResourceID"`
|
||||
ResourceType uint32 `json:"ResourceType"`
|
||||
ResourceID uint64 `json:"ResourceID"`
|
||||
}
|
||||
|
||||
// GetID returns the value of ID.
|
||||
func (s *Script) GetID() int64 {
|
||||
func (s *Script) GetID() uint64 {
|
||||
return s.ID
|
||||
}
|
||||
|
||||
@ -383,17 +366,17 @@ func (s *Script) GetSource() string {
|
||||
}
|
||||
|
||||
// GetResourceType returns the value of ResourceType.
|
||||
func (s *Script) GetResourceType() int32 {
|
||||
func (s *Script) GetResourceType() uint32 {
|
||||
return s.ResourceType
|
||||
}
|
||||
|
||||
// GetResourceID returns the value of ResourceID.
|
||||
func (s *Script) GetResourceID() int64 {
|
||||
func (s *Script) GetResourceID() uint64 {
|
||||
return s.ResourceID
|
||||
}
|
||||
|
||||
// SetID sets the value of ID.
|
||||
func (s *Script) SetID(val int64) {
|
||||
func (s *Script) SetID(val uint64) {
|
||||
s.ID = val
|
||||
}
|
||||
|
||||
@ -413,12 +396,12 @@ func (s *Script) SetSource(val string) {
|
||||
}
|
||||
|
||||
// SetResourceType sets the value of ResourceType.
|
||||
func (s *Script) SetResourceType(val int32) {
|
||||
func (s *Script) SetResourceType(val uint32) {
|
||||
s.ResourceType = val
|
||||
}
|
||||
|
||||
// SetResourceID sets the value of ResourceID.
|
||||
func (s *Script) SetResourceID(val int64) {
|
||||
func (s *Script) SetResourceID(val uint64) {
|
||||
s.ResourceID = val
|
||||
}
|
||||
|
||||
@ -426,8 +409,8 @@ func (s *Script) SetResourceID(val int64) {
|
||||
type ScriptCreate struct {
|
||||
Name string `json:"Name"`
|
||||
Source string `json:"Source"`
|
||||
ResourceType int32 `json:"ResourceType"`
|
||||
ResourceID OptInt64 `json:"ResourceID"`
|
||||
ResourceType uint32 `json:"ResourceType"`
|
||||
ResourceID OptUint64 `json:"ResourceID"`
|
||||
}
|
||||
|
||||
// GetName returns the value of Name.
|
||||
@ -441,12 +424,12 @@ func (s *ScriptCreate) GetSource() string {
|
||||
}
|
||||
|
||||
// GetResourceType returns the value of ResourceType.
|
||||
func (s *ScriptCreate) GetResourceType() int32 {
|
||||
func (s *ScriptCreate) GetResourceType() uint32 {
|
||||
return s.ResourceType
|
||||
}
|
||||
|
||||
// GetResourceID returns the value of ResourceID.
|
||||
func (s *ScriptCreate) GetResourceID() OptInt64 {
|
||||
func (s *ScriptCreate) GetResourceID() OptUint64 {
|
||||
return s.ResourceID
|
||||
}
|
||||
|
||||
@ -461,40 +444,40 @@ func (s *ScriptCreate) SetSource(val string) {
|
||||
}
|
||||
|
||||
// SetResourceType sets the value of ResourceType.
|
||||
func (s *ScriptCreate) SetResourceType(val int32) {
|
||||
func (s *ScriptCreate) SetResourceType(val uint32) {
|
||||
s.ResourceType = val
|
||||
}
|
||||
|
||||
// SetResourceID sets the value of ResourceID.
|
||||
func (s *ScriptCreate) SetResourceID(val OptInt64) {
|
||||
func (s *ScriptCreate) SetResourceID(val OptUint64) {
|
||||
s.ResourceID = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/ScriptID
|
||||
type ScriptID struct {
|
||||
ScriptID int64 `json:"ScriptID"`
|
||||
ScriptID uint64 `json:"ScriptID"`
|
||||
}
|
||||
|
||||
// GetScriptID returns the value of ScriptID.
|
||||
func (s *ScriptID) GetScriptID() int64 {
|
||||
func (s *ScriptID) GetScriptID() uint64 {
|
||||
return s.ScriptID
|
||||
}
|
||||
|
||||
// SetScriptID sets the value of ScriptID.
|
||||
func (s *ScriptID) SetScriptID(val int64) {
|
||||
func (s *ScriptID) SetScriptID(val uint64) {
|
||||
s.ScriptID = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/ScriptPolicy
|
||||
type ScriptPolicy struct {
|
||||
ID int64 `json:"ID"`
|
||||
ID uint64 `json:"ID"`
|
||||
FromScriptHash string `json:"FromScriptHash"`
|
||||
ToScriptID int64 `json:"ToScriptID"`
|
||||
Policy int32 `json:"Policy"`
|
||||
ToScriptID uint64 `json:"ToScriptID"`
|
||||
Policy uint32 `json:"Policy"`
|
||||
}
|
||||
|
||||
// GetID returns the value of ID.
|
||||
func (s *ScriptPolicy) GetID() int64 {
|
||||
func (s *ScriptPolicy) GetID() uint64 {
|
||||
return s.ID
|
||||
}
|
||||
|
||||
@ -504,17 +487,17 @@ func (s *ScriptPolicy) GetFromScriptHash() string {
|
||||
}
|
||||
|
||||
// GetToScriptID returns the value of ToScriptID.
|
||||
func (s *ScriptPolicy) GetToScriptID() int64 {
|
||||
func (s *ScriptPolicy) GetToScriptID() uint64 {
|
||||
return s.ToScriptID
|
||||
}
|
||||
|
||||
// GetPolicy returns the value of Policy.
|
||||
func (s *ScriptPolicy) GetPolicy() int32 {
|
||||
func (s *ScriptPolicy) GetPolicy() uint32 {
|
||||
return s.Policy
|
||||
}
|
||||
|
||||
// SetID sets the value of ID.
|
||||
func (s *ScriptPolicy) SetID(val int64) {
|
||||
func (s *ScriptPolicy) SetID(val uint64) {
|
||||
s.ID = val
|
||||
}
|
||||
|
||||
@ -524,87 +507,85 @@ func (s *ScriptPolicy) SetFromScriptHash(val string) {
|
||||
}
|
||||
|
||||
// SetToScriptID sets the value of ToScriptID.
|
||||
func (s *ScriptPolicy) SetToScriptID(val int64) {
|
||||
func (s *ScriptPolicy) SetToScriptID(val uint64) {
|
||||
s.ToScriptID = val
|
||||
}
|
||||
|
||||
// SetPolicy sets the value of Policy.
|
||||
func (s *ScriptPolicy) SetPolicy(val int32) {
|
||||
func (s *ScriptPolicy) SetPolicy(val uint32) {
|
||||
s.Policy = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/ScriptPolicyCreate
|
||||
type ScriptPolicyCreate struct {
|
||||
FromScriptID int64 `json:"FromScriptID"`
|
||||
ToScriptID int64 `json:"ToScriptID"`
|
||||
Policy int32 `json:"Policy"`
|
||||
FromScriptID uint64 `json:"FromScriptID"`
|
||||
ToScriptID uint64 `json:"ToScriptID"`
|
||||
Policy uint32 `json:"Policy"`
|
||||
}
|
||||
|
||||
// GetFromScriptID returns the value of FromScriptID.
|
||||
func (s *ScriptPolicyCreate) GetFromScriptID() int64 {
|
||||
func (s *ScriptPolicyCreate) GetFromScriptID() uint64 {
|
||||
return s.FromScriptID
|
||||
}
|
||||
|
||||
// GetToScriptID returns the value of ToScriptID.
|
||||
func (s *ScriptPolicyCreate) GetToScriptID() int64 {
|
||||
func (s *ScriptPolicyCreate) GetToScriptID() uint64 {
|
||||
return s.ToScriptID
|
||||
}
|
||||
|
||||
// GetPolicy returns the value of Policy.
|
||||
func (s *ScriptPolicyCreate) GetPolicy() int32 {
|
||||
func (s *ScriptPolicyCreate) GetPolicy() uint32 {
|
||||
return s.Policy
|
||||
}
|
||||
|
||||
// SetFromScriptID sets the value of FromScriptID.
|
||||
func (s *ScriptPolicyCreate) SetFromScriptID(val int64) {
|
||||
func (s *ScriptPolicyCreate) SetFromScriptID(val uint64) {
|
||||
s.FromScriptID = val
|
||||
}
|
||||
|
||||
// SetToScriptID sets the value of ToScriptID.
|
||||
func (s *ScriptPolicyCreate) SetToScriptID(val int64) {
|
||||
func (s *ScriptPolicyCreate) SetToScriptID(val uint64) {
|
||||
s.ToScriptID = val
|
||||
}
|
||||
|
||||
// SetPolicy sets the value of Policy.
|
||||
func (s *ScriptPolicyCreate) SetPolicy(val int32) {
|
||||
func (s *ScriptPolicyCreate) SetPolicy(val uint32) {
|
||||
s.Policy = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/ScriptPolicyID
|
||||
type ScriptPolicyID struct {
|
||||
ScriptPolicyID int64 `json:"ScriptPolicyID"`
|
||||
ScriptPolicyID uint64 `json:"ScriptPolicyID"`
|
||||
}
|
||||
|
||||
// GetScriptPolicyID returns the value of ScriptPolicyID.
|
||||
func (s *ScriptPolicyID) GetScriptPolicyID() int64 {
|
||||
func (s *ScriptPolicyID) GetScriptPolicyID() uint64 {
|
||||
return s.ScriptPolicyID
|
||||
}
|
||||
|
||||
// SetScriptPolicyID sets the value of ScriptPolicyID.
|
||||
func (s *ScriptPolicyID) SetScriptPolicyID(val int64) {
|
||||
func (s *ScriptPolicyID) SetScriptPolicyID(val uint64) {
|
||||
s.ScriptPolicyID = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/SubmissionCreate
|
||||
type SubmissionCreate struct {
|
||||
OperationID int32 `json:"OperationID"`
|
||||
AssetOwner int64 `json:"AssetOwner"`
|
||||
OperationID uint32 `json:"OperationID"`
|
||||
AssetOwner uint64 `json:"AssetOwner"`
|
||||
DisplayName string `json:"DisplayName"`
|
||||
Creator string `json:"Creator"`
|
||||
GameID int32 `json:"GameID"`
|
||||
AssetID int64 `json:"AssetID"`
|
||||
AssetVersion int64 `json:"AssetVersion"`
|
||||
Status uint32 `json:"Status"`
|
||||
Roles uint32 `json:"Roles"`
|
||||
GameID uint32 `json:"GameID"`
|
||||
AssetID uint64 `json:"AssetID"`
|
||||
AssetVersion uint64 `json:"AssetVersion"`
|
||||
}
|
||||
|
||||
// GetOperationID returns the value of OperationID.
|
||||
func (s *SubmissionCreate) GetOperationID() int32 {
|
||||
func (s *SubmissionCreate) GetOperationID() uint32 {
|
||||
return s.OperationID
|
||||
}
|
||||
|
||||
// GetAssetOwner returns the value of AssetOwner.
|
||||
func (s *SubmissionCreate) GetAssetOwner() int64 {
|
||||
func (s *SubmissionCreate) GetAssetOwner() uint64 {
|
||||
return s.AssetOwner
|
||||
}
|
||||
|
||||
@ -619,37 +600,27 @@ func (s *SubmissionCreate) GetCreator() string {
|
||||
}
|
||||
|
||||
// GetGameID returns the value of GameID.
|
||||
func (s *SubmissionCreate) GetGameID() int32 {
|
||||
func (s *SubmissionCreate) GetGameID() uint32 {
|
||||
return s.GameID
|
||||
}
|
||||
|
||||
// GetAssetID returns the value of AssetID.
|
||||
func (s *SubmissionCreate) GetAssetID() int64 {
|
||||
func (s *SubmissionCreate) GetAssetID() uint64 {
|
||||
return s.AssetID
|
||||
}
|
||||
|
||||
// GetAssetVersion returns the value of AssetVersion.
|
||||
func (s *SubmissionCreate) GetAssetVersion() int64 {
|
||||
func (s *SubmissionCreate) GetAssetVersion() uint64 {
|
||||
return s.AssetVersion
|
||||
}
|
||||
|
||||
// GetStatus returns the value of Status.
|
||||
func (s *SubmissionCreate) GetStatus() uint32 {
|
||||
return s.Status
|
||||
}
|
||||
|
||||
// GetRoles returns the value of Roles.
|
||||
func (s *SubmissionCreate) GetRoles() uint32 {
|
||||
return s.Roles
|
||||
}
|
||||
|
||||
// SetOperationID sets the value of OperationID.
|
||||
func (s *SubmissionCreate) SetOperationID(val int32) {
|
||||
func (s *SubmissionCreate) SetOperationID(val uint32) {
|
||||
s.OperationID = val
|
||||
}
|
||||
|
||||
// SetAssetOwner sets the value of AssetOwner.
|
||||
func (s *SubmissionCreate) SetAssetOwner(val int64) {
|
||||
func (s *SubmissionCreate) SetAssetOwner(val uint64) {
|
||||
s.AssetOwner = val
|
||||
}
|
||||
|
||||
@ -664,42 +635,32 @@ func (s *SubmissionCreate) SetCreator(val string) {
|
||||
}
|
||||
|
||||
// SetGameID sets the value of GameID.
|
||||
func (s *SubmissionCreate) SetGameID(val int32) {
|
||||
func (s *SubmissionCreate) SetGameID(val uint32) {
|
||||
s.GameID = val
|
||||
}
|
||||
|
||||
// SetAssetID sets the value of AssetID.
|
||||
func (s *SubmissionCreate) SetAssetID(val int64) {
|
||||
func (s *SubmissionCreate) SetAssetID(val uint64) {
|
||||
s.AssetID = val
|
||||
}
|
||||
|
||||
// SetAssetVersion sets the value of AssetVersion.
|
||||
func (s *SubmissionCreate) SetAssetVersion(val int64) {
|
||||
func (s *SubmissionCreate) SetAssetVersion(val uint64) {
|
||||
s.AssetVersion = val
|
||||
}
|
||||
|
||||
// SetStatus sets the value of Status.
|
||||
func (s *SubmissionCreate) SetStatus(val uint32) {
|
||||
s.Status = val
|
||||
}
|
||||
|
||||
// SetRoles sets the value of Roles.
|
||||
func (s *SubmissionCreate) SetRoles(val uint32) {
|
||||
s.Roles = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/SubmissionID
|
||||
type SubmissionID struct {
|
||||
SubmissionID int64 `json:"SubmissionID"`
|
||||
SubmissionID uint64 `json:"SubmissionID"`
|
||||
}
|
||||
|
||||
// GetSubmissionID returns the value of SubmissionID.
|
||||
func (s *SubmissionID) GetSubmissionID() int64 {
|
||||
func (s *SubmissionID) GetSubmissionID() uint64 {
|
||||
return s.SubmissionID
|
||||
}
|
||||
|
||||
// SetSubmissionID sets the value of SubmissionID.
|
||||
func (s *SubmissionID) SetSubmissionID(val int64) {
|
||||
func (s *SubmissionID) SetSubmissionID(val uint64) {
|
||||
s.SubmissionID = val
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,6 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
|
||||
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -50,12 +44,6 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-failed
|
||||
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
|
||||
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
|
@ -22,15 +22,6 @@ func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params Act
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
@ -76,15 +67,6 @@ func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
|
@ -227,25 +227,6 @@ func (s *MapfixCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 256,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Description)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Description",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@ -881,26 +862,6 @@ func (s *SubmissionCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: true,
|
||||
Max: 9,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.Status)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Status",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type AuditEventType int32
|
||||
type AuditEventType uint32
|
||||
|
||||
// User clicked "Submit", "Accept" etc
|
||||
const AuditEventTypeAction AuditEventType = 0
|
||||
@ -42,18 +42,12 @@ type AuditEventDataChangeName struct {
|
||||
NewName string `json:"new_name"`
|
||||
}
|
||||
|
||||
// Validator had an error
|
||||
const AuditEventTypeError AuditEventType = 6
|
||||
type AuditEventDataError struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type AuditEvent struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
User uint64
|
||||
ResourceType ResourceType // is this a submission or is it a mapfix
|
||||
ResourceID int64 // submission / mapfix / map ID
|
||||
ResourceID uint64 // submission / mapfix / map ID
|
||||
EventType AuditEventType
|
||||
EventData json.RawMessage `gorm:"type:jsonb"`
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
type MapfixStatus int32
|
||||
type MapfixStatus uint32
|
||||
|
||||
const (
|
||||
// Phase: Creation
|
||||
@ -25,7 +25,7 @@ const (
|
||||
)
|
||||
|
||||
type Mapfix struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID uint32
|
||||
@ -39,5 +39,5 @@ type Mapfix struct {
|
||||
Completed bool // Has this version of the map been completed at least once on maptest
|
||||
TargetAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
StatusID MapfixStatus
|
||||
Description string // mapfix description
|
||||
StatusMessage string
|
||||
}
|
||||
|
@ -7,43 +7,26 @@ package model
|
||||
|
||||
type CreateSubmissionRequest struct {
|
||||
// operation_id is passed back in the response message
|
||||
OperationID int32
|
||||
OperationID uint32
|
||||
ModelID uint64
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID uint32
|
||||
Status uint32
|
||||
Roles uint32
|
||||
}
|
||||
|
||||
type CreateMapfixRequest struct {
|
||||
OperationID int32
|
||||
OperationID uint32
|
||||
ModelID uint64
|
||||
TargetAssetID uint64
|
||||
Description string
|
||||
}
|
||||
|
||||
|
||||
type CheckSubmissionRequest struct{
|
||||
SubmissionID int64
|
||||
ModelID uint64
|
||||
}
|
||||
|
||||
type CheckMapfixRequest struct{
|
||||
MapfixID int64
|
||||
ModelID uint64
|
||||
}
|
||||
|
||||
type ValidateSubmissionRequest struct {
|
||||
// submission_id is passed back in the response message
|
||||
SubmissionID int64
|
||||
SubmissionID uint64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ValidatedModelID *uint64 // optional value
|
||||
}
|
||||
|
||||
type ValidateMapfixRequest struct {
|
||||
MapfixID int64
|
||||
MapfixID uint64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ValidatedModelID *uint64 // optional value
|
||||
@ -51,14 +34,14 @@ type ValidateMapfixRequest struct {
|
||||
|
||||
// Create a new map
|
||||
type UploadSubmissionRequest struct {
|
||||
SubmissionID int64
|
||||
SubmissionID uint64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ModelName string
|
||||
}
|
||||
|
||||
type UploadMapfixRequest struct {
|
||||
MapfixID int64
|
||||
MapfixID uint64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
TargetAssetID uint64
|
||||
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
type OperationStatus int32
|
||||
type OperationStatus uint32
|
||||
const (
|
||||
OperationStatusCreated OperationStatus = 0
|
||||
OperationStatusCompleted OperationStatus = 1
|
||||
@ -10,7 +10,7 @@ const (
|
||||
)
|
||||
|
||||
type Operation struct {
|
||||
ID int32 `gorm:"primaryKey"`
|
||||
ID uint32 `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
Owner uint64 // UserID
|
||||
StatusID OperationStatus
|
||||
|
@ -1,6 +1,6 @@
|
||||
package model
|
||||
|
||||
type Page struct {
|
||||
Number int32
|
||||
Size int32
|
||||
Number uint32
|
||||
Size uint32
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Policy int32
|
||||
type Policy uint32
|
||||
|
||||
const (
|
||||
ScriptPolicyNone Policy = 0 // not yet reviewed
|
||||
@ -13,7 +13,7 @@ const (
|
||||
)
|
||||
|
||||
type ScriptPolicy struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
// Hash of the source code that leads to this policy.
|
||||
// If this is a replacement mapping, the original source may not be pointed to by any policy.
|
||||
// The original source should still exist in the scripts table, which can be located by the same hash.
|
||||
@ -21,7 +21,7 @@ type ScriptPolicy struct {
|
||||
// The ID of the replacement source (ScriptPolicyReplace)
|
||||
// or verbatim source (ScriptPolicyAllowed)
|
||||
// or 0 (other)
|
||||
ToScriptID int64
|
||||
ToScriptID uint64
|
||||
Policy Policy
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
|
@ -23,7 +23,7 @@ func HashParse(hash string) (uint64, error){
|
||||
return strconv.ParseUint(hash, 16, 64)
|
||||
}
|
||||
|
||||
type ResourceType int32
|
||||
type ResourceType uint32
|
||||
const (
|
||||
ResourceUnknown ResourceType = 0
|
||||
ResourceMapfix ResourceType = 1
|
||||
@ -31,12 +31,17 @@ const (
|
||||
)
|
||||
|
||||
type Script struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
Name string
|
||||
Hash int64 // postgres does not support unsigned integers, so we have to pretend
|
||||
hash uint64
|
||||
Source string
|
||||
ResourceType ResourceType // is this a submission or is it a mapfix
|
||||
ResourceID int64 // which submission / mapfix did this script first appear in
|
||||
ResourceID uint64 // which submission / mapfix did this script first appear in
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
// postgres does not support unsigned integers, so we have to pretend
|
||||
func (script *Script) GetPostgresInt64() (int64) {
|
||||
return int64(script.hash)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package model
|
||||
|
||||
import "time"
|
||||
|
||||
type SubmissionStatus int32
|
||||
type SubmissionStatus uint32
|
||||
|
||||
const (
|
||||
// Phase: Creation
|
||||
@ -26,7 +26,7 @@ const (
|
||||
)
|
||||
|
||||
type Submission struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
ID uint64 `gorm:"primaryKey"`
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID uint32
|
||||
@ -40,4 +40,5 @@ type Submission struct {
|
||||
Completed bool // Has this version of the map been completed at least once on maptest
|
||||
UploadedAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
StatusID SubmissionStatus
|
||||
StatusMessage string
|
||||
}
|
||||
|
@ -3,9 +3,7 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
@ -26,34 +24,27 @@ func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.Create
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has_role {
|
||||
// Submitter has special permission to comment on their mapfix
|
||||
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if mapfix.Submitter != userId {
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(req)
|
||||
data := []byte{}
|
||||
_, err = req.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Comment := string(data)
|
||||
|
||||
event_data := model.AuditEventDataComment{
|
||||
Comment: string(data),
|
||||
Comment: Comment,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(&event_data)
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -81,8 +72,8 @@ func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.Create
|
||||
func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMapfixAuditEventsParams) ([]api.AuditEvent, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
filter.Add("resource_type", model.ResourceMapfix)
|
||||
filter.Add("resource_id", params.MapfixID)
|
||||
filter.AddPostgresInt32("resource_type", uint32(model.ResourceMapfix))
|
||||
filter.AddPostgresInt64("resource_id", params.MapfixID)
|
||||
|
||||
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
@ -92,27 +83,6 @@ func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMa
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idMap := make(map[int64]bool)
|
||||
for _, item := range items {
|
||||
idMap[int64(item.User)] = true
|
||||
}
|
||||
|
||||
var idList users.IdList
|
||||
idList.ID = make([]int64,len(idMap))
|
||||
for userId := range idMap {
|
||||
idList.ID = append(idList.ID, userId)
|
||||
}
|
||||
|
||||
userList, err := svc.Users.GetList(ctx, &idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*users.UserResponse)
|
||||
for _,user := range userList.Users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
|
||||
var resp []api.AuditEvent
|
||||
for _, item := range items {
|
||||
EventData := api.AuditEventEventData{}
|
||||
@ -120,18 +90,13 @@ func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMa
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
username := ""
|
||||
if userMap[int64(item.User)] != nil {
|
||||
username = userMap[int64(item.User)].Username
|
||||
}
|
||||
resp = append(resp, api.AuditEvent{
|
||||
ID: item.ID,
|
||||
Date: item.CreatedAt.Unix(),
|
||||
User: int64(item.User),
|
||||
Username: username,
|
||||
ResourceType: int32(item.ResourceType),
|
||||
User: item.User,
|
||||
ResourceType: uint32(item.ResourceType),
|
||||
ResourceID: item.ResourceID,
|
||||
EventType: int32(item.EventType),
|
||||
EventType: uint32(item.EventType),
|
||||
EventData: EventData,
|
||||
})
|
||||
}
|
||||
@ -154,34 +119,27 @@ func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.Cr
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has_role {
|
||||
// Submitter has special permission to comment on their submission
|
||||
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if submission.Submitter != userId {
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
}
|
||||
|
||||
data, err := io.ReadAll(req)
|
||||
data := []byte{}
|
||||
_, err = req.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Comment := string(data)
|
||||
|
||||
event_data := model.AuditEventDataComment{
|
||||
Comment: string(data),
|
||||
Comment: Comment,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(&event_data)
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -209,8 +167,8 @@ func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.Cr
|
||||
func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.ListSubmissionAuditEventsParams) ([]api.AuditEvent, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
filter.Add("resource_type", model.ResourceSubmission)
|
||||
filter.Add("resource_id", params.SubmissionID)
|
||||
filter.AddPostgresInt32("resource_type", uint32(model.ResourceSubmission))
|
||||
filter.AddPostgresInt64("resource_id", params.SubmissionID)
|
||||
|
||||
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
@ -220,27 +178,6 @@ func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.Li
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idMap := make(map[int64]bool)
|
||||
for _, item := range items {
|
||||
idMap[int64(item.User)] = true
|
||||
}
|
||||
|
||||
var idList users.IdList
|
||||
idList.ID = make([]int64,len(idMap))
|
||||
for userId := range idMap {
|
||||
idList.ID = append(idList.ID, userId)
|
||||
}
|
||||
|
||||
userList, err := svc.Users.GetList(ctx, &idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*users.UserResponse)
|
||||
for _,user := range userList.Users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
|
||||
var resp []api.AuditEvent
|
||||
for _, item := range items {
|
||||
EventData := api.AuditEventEventData{}
|
||||
@ -248,18 +185,13 @@ func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.Li
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
username := ""
|
||||
if userMap[int64(item.User)] != nil {
|
||||
username = userMap[int64(item.User)].Username
|
||||
}
|
||||
resp = append(resp, api.AuditEvent{
|
||||
ID: item.ID,
|
||||
Date: item.CreatedAt.Unix(),
|
||||
User: int64(item.User),
|
||||
Username: username,
|
||||
ResourceType: int32(item.ResourceType),
|
||||
User: item.User,
|
||||
ResourceType: uint32(item.ResourceType),
|
||||
ResourceID: item.ResourceID,
|
||||
EventType: int32(item.EventType),
|
||||
EventType: uint32(item.EventType),
|
||||
EventData: EventData,
|
||||
})
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
filter.Add("status_id", CreationPhaseMapfixStatuses)
|
||||
creation_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||
Number: 1,
|
||||
Size: int32(CreationPhaseMapfixesLimit),
|
||||
Size: uint32(CreationPhaseMapfixesLimit),
|
||||
},datastore.ListSortDisabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -78,7 +78,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
|
||||
// Check if TargetAssetID actually exists
|
||||
{
|
||||
_, err := svc.Maps.Get(ctx, &maps.IdMessage{
|
||||
_, err := svc.Client.Get(ctx, &maps.IdMessage{
|
||||
ID: request.TargetAssetID,
|
||||
})
|
||||
if err != nil {
|
||||
@ -114,7 +114,6 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
OperationID: operation.ID,
|
||||
ModelID: ModelID,
|
||||
TargetAssetID: TargetAssetID,
|
||||
Description: request.Description,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
@ -138,7 +137,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
//
|
||||
// GET /mapfixes/{MapfixID}
|
||||
func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (*api.Mapfix, error) {
|
||||
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||
mapfix, err := svc.DB.Mapfixes().Get(ctx, int64(params.MapfixID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -146,16 +145,16 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
|
||||
ID: mapfix.ID,
|
||||
DisplayName: mapfix.DisplayName,
|
||||
Creator: mapfix.Creator,
|
||||
GameID: int32(mapfix.GameID),
|
||||
GameID: uint32(mapfix.GameID),
|
||||
CreatedAt: mapfix.CreatedAt.Unix(),
|
||||
UpdatedAt: mapfix.UpdatedAt.Unix(),
|
||||
Submitter: int64(mapfix.Submitter),
|
||||
AssetID: int64(mapfix.AssetID),
|
||||
AssetVersion: int64(mapfix.AssetVersion),
|
||||
Submitter: mapfix.Submitter,
|
||||
AssetID: mapfix.AssetID,
|
||||
AssetVersion: mapfix.AssetVersion,
|
||||
Completed: mapfix.Completed,
|
||||
TargetAssetID: int64(mapfix.TargetAssetID),
|
||||
StatusID: int32(mapfix.StatusID),
|
||||
Description: mapfix.Description,
|
||||
TargetAssetID: mapfix.TargetAssetID,
|
||||
StatusID: uint32(mapfix.StatusID),
|
||||
StatusMessage: mapfix.StatusMessage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -168,28 +167,28 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
|
||||
filter := datastore.Optional()
|
||||
|
||||
if params.DisplayName.IsSet(){
|
||||
filter.Add("display_name", params.DisplayName.Value)
|
||||
filter.Add2("display_name", params.DisplayName.Value)
|
||||
}
|
||||
if params.Creator.IsSet(){
|
||||
filter.Add("creator", params.Creator.Value)
|
||||
filter.Add2("creator", params.Creator.Value)
|
||||
}
|
||||
if params.GameID.IsSet(){
|
||||
filter.Add("game_id", params.GameID.Value)
|
||||
filter.AddPostgresInt32("game_id", params.GameID.Value)
|
||||
}
|
||||
if params.Submitter.IsSet(){
|
||||
filter.Add("submitter", params.Submitter.Value)
|
||||
filter.AddPostgresInt64("submitter", params.Submitter.Value)
|
||||
}
|
||||
if params.AssetID.IsSet(){
|
||||
filter.Add("asset_id", params.AssetID.Value)
|
||||
filter.AddPostgresInt64("asset_id", params.AssetID.Value)
|
||||
}
|
||||
if params.TargetAssetID.IsSet(){
|
||||
filter.Add("target_asset_id", params.TargetAssetID.Value)
|
||||
filter.AddPostgresInt64("target_asset_id", params.TargetAssetID.Value)
|
||||
}
|
||||
if params.StatusID.IsSet(){
|
||||
filter.Add("status_id", params.StatusID.Value)
|
||||
filter.AddPostgresInt32("status_id", params.StatusID.Value)
|
||||
}
|
||||
|
||||
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
|
||||
sort := datastore.ListSort(params.Sort.Or(uint32(datastore.ListSortDisabled)))
|
||||
|
||||
total, items, err := svc.DB.Mapfixes().ListWithTotal(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
@ -206,16 +205,15 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
|
||||
ID: item.ID,
|
||||
DisplayName: item.DisplayName,
|
||||
Creator: item.Creator,
|
||||
GameID: int32(item.GameID),
|
||||
GameID: item.GameID,
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
Submitter: int64(item.Submitter),
|
||||
AssetID: int64(item.AssetID),
|
||||
AssetVersion: int64(item.AssetVersion),
|
||||
Submitter: item.Submitter,
|
||||
AssetID: item.AssetID,
|
||||
AssetVersion: item.AssetVersion,
|
||||
Completed: item.Completed,
|
||||
TargetAssetID: int64(item.TargetAssetID),
|
||||
StatusID: int32(item.StatusID),
|
||||
Description: item.Description,
|
||||
TargetAssetID: item.TargetAssetID,
|
||||
StatusID: uint32(item.StatusID),
|
||||
})
|
||||
}
|
||||
|
||||
@ -396,42 +394,10 @@ func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params api.A
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAcceptedUnvalidated, model.MapfixStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
smap.Add("status_id", model.MapfixStatusChangesRequested)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAcceptedUnvalidated, model.MapfixStatusSubmitted}, smap)
|
||||
}
|
||||
|
||||
// ActionMapfixRevoke invokes actionMapfixRevoke operation.
|
||||
@ -523,96 +489,11 @@ func (svc *Service) ActionMapfixTriggerSubmit(ctx context.Context, params api.Ac
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusSubmitting
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validate_request := model.CheckMapfixRequest{
|
||||
MapfixID: mapfix.ID,
|
||||
ModelID: mapfix.AssetID,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(validate_request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.check", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixBypassSubmit invokes actionMapfixBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/bypass-submit
|
||||
func (svc *Service) ActionMapfixBypassSubmit(ctx context.Context, params api.ActionMapfixBypassSubmitParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
// read mapfix (this could be done with a transaction WHERE clause)
|
||||
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
is_submitter := userId == mapfix.Submitter
|
||||
if is_submitter {
|
||||
return ErrAcceptOwnMapfix
|
||||
}
|
||||
|
||||
has_mapfix_review, err := userInfo.HasRoleMapfixReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has_mapfix_review {
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested}, smap)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -677,6 +558,7 @@ func (svc *Service) ActionMapfixResetSubmitting(ctx context.Context, params api.
|
||||
target_status := model.MapfixStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1078,6 +960,7 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM
|
||||
target_status := model.MapfixStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -25,7 +25,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]
|
||||
filter.GameID = ¶ms.GameID.Value
|
||||
}
|
||||
|
||||
mapList, err := svc.Maps.List(ctx, &maps.ListRequest{
|
||||
mapList, err := svc.Client.List(ctx, &maps.ListRequest{
|
||||
Filter: &filter,
|
||||
Page: &maps.Pagination{
|
||||
Size: params.Limit,
|
||||
@ -56,7 +56,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]
|
||||
//
|
||||
// GET /maps/{MapID}
|
||||
func (svc *Service) GetMap(ctx context.Context, params api.GetMapParams) (*api.Map, error) {
|
||||
mapResponse, err := svc.Maps.Get(ctx, &maps.IdMessage{
|
||||
mapResponse, err := svc.Client.Get(ctx, &maps.IdMessage{
|
||||
ID: params.MapID,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/maps"
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"github.com/nats-io/nats.go"
|
||||
@ -33,8 +32,7 @@ var (
|
||||
type Service struct {
|
||||
DB datastore.Datastore
|
||||
Nats nats.JetStreamContext
|
||||
Maps maps.MapsServiceClient
|
||||
Users users.UsersServiceClient
|
||||
Client maps.MapsServiceClient
|
||||
}
|
||||
|
||||
// NewError creates *ErrorStatusCode from error returned by handler.
|
||||
|
@ -20,7 +20,7 @@ var(
|
||||
model.SubmissionStatusSubmitted,
|
||||
model.SubmissionStatusUnderConstruction,
|
||||
}
|
||||
// limit submissions in the pipeline to one per target map
|
||||
// limit mapfixes in the pipeline to one per target map
|
||||
ActiveAcceptedSubmissionStatuses = []model.SubmissionStatus{
|
||||
model.SubmissionStatusUploading,
|
||||
model.SubmissionStatusValidated,
|
||||
@ -103,87 +103,6 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
|
||||
create_request := model.CreateSubmissionRequest{
|
||||
OperationID: operation.ID,
|
||||
ModelID: ModelID,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: uint32(request.GameID),
|
||||
Status: uint32(model.SubmissionStatusUnderConstruction),
|
||||
Roles: uint32(RolesEmpty),
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.submissions.create", []byte(j))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.OperationID{
|
||||
OperationID: operation.ID,
|
||||
}, nil
|
||||
}
|
||||
// POST /submissions-admin
|
||||
func (svc *Service) CreateSubmissionAdmin(ctx context.Context, request *api.SubmissionTriggerCreate) (*api.OperationID, error) {
|
||||
// sanitization
|
||||
if request.AssetID<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var ModelID=uint64(request.AssetID);
|
||||
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles, err := userInfo.GetRoles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check if caller has required role
|
||||
has_role := roles & RolesSubmissionReview == RolesSubmissionReview
|
||||
if !has_role {
|
||||
return nil, ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
// Check if too many operations have been created recently
|
||||
{
|
||||
count, err := svc.DB.Operations().CountSince(ctx,
|
||||
int64(userId),
|
||||
time.Now().Add(-CreateSubmissionRecencyWindow),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if CreateSubmissionRateLimit < count {
|
||||
return nil, ErrCreateSubmissionRateLimit
|
||||
}
|
||||
}
|
||||
|
||||
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
|
||||
Owner: userId,
|
||||
StatusID: model.OperationStatusCreated,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
create_request := model.CreateSubmissionRequest{
|
||||
OperationID: operation.ID,
|
||||
ModelID: ModelID,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: uint32(request.GameID),
|
||||
Status: uint32(model.SubmissionStatusChangesRequested),
|
||||
Roles: uint32(roles),
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
@ -224,6 +143,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
|
||||
Completed: submission.Completed,
|
||||
UploadedAssetID: api.NewOptInt64(int64(submission.UploadedAssetID)),
|
||||
StatusID: int32(submission.StatusID),
|
||||
StatusMessage: submission.StatusMessage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -585,109 +505,16 @@ func (svc *Service) ActionSubmissionTriggerSubmit(ctx context.Context, params ap
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
is_submitter := userId == submission.Submitter
|
||||
// neither = deny
|
||||
if !is_submitter {
|
||||
has_submission_review, err := userInfo.HasRoleSubmissionReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has_submission_review {
|
||||
has_role := userId == submission.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusSubmitting
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validate_request := model.CheckSubmissionRequest{
|
||||
SubmissionID: submission.ID,
|
||||
ModelID: submission.AssetID,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(validate_request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.submissions.check", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionBypassSubmit invokes actionSubmissionBypassSubmit operation.
|
||||
//
|
||||
// Role Reviewer changes status from ChangesRequested -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/bypass-submit
|
||||
func (svc *Service) ActionSubmissionBypassSubmit(ctx context.Context, params api.ActionSubmissionBypassSubmitParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
// read submission (this could be done with a transaction WHERE clause)
|
||||
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
is_submitter := userId == submission.Submitter
|
||||
if is_submitter {
|
||||
return ErrAcceptOwnSubmission
|
||||
}
|
||||
|
||||
has_submission_review, err := userInfo.HasRoleSubmissionReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !has_submission_review {
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested}, smap)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -752,6 +579,7 @@ func (svc *Service) ActionSubmissionResetSubmitting(ctx context.Context, params
|
||||
target_status := model.SubmissionStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1143,6 +971,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
|
||||
target_status := model.SubmissionStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1217,7 +1046,7 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
|
||||
date := request[i].Date.Unix()
|
||||
var GameID = int32(submission.GameID)
|
||||
// create each map with go-grpc
|
||||
_, err := svc.Maps.Create(ctx, &maps.MapRequest{
|
||||
_, err := svc.Client.Create(ctx, &maps.MapRequest{
|
||||
ID: int64(submission.UploadedAssetID),
|
||||
DisplayName: &submission.DisplayName,
|
||||
Creator: &submission.Creator,
|
||||
|
@ -74,7 +74,7 @@ func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params inter
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
// ActionMapfixValidate invokes actionMapfixValidate operation.
|
||||
//
|
||||
// Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
@ -84,10 +84,6 @@ func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.A
|
||||
target_status := model.MapfixStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("asset_version", params.ModelVersion)
|
||||
smap.Add("display_name", params.DisplayName)
|
||||
smap.Add("creator", params.Creator)
|
||||
smap.Add("game_id", params.GameID)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -117,68 +113,6 @@ func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.A
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params internal.ActionMapfixRequestChangesParams) error {
|
||||
// transaction
|
||||
target_status := model.MapfixStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixValidate invokes actionMapfixValidate operation.
|
||||
//
|
||||
// Role Validator changes status from Validating -> Validated.
|
||||
@ -201,36 +135,12 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.Ac
|
||||
target_status := model.MapfixStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", params.StatusMessage)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
@ -350,7 +260,6 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
|
||||
Completed: false,
|
||||
TargetAssetID: TargetAssetID,
|
||||
StatusID: model.MapfixStatusUnderConstruction,
|
||||
Description: request.Description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/service"
|
||||
)
|
||||
|
||||
var(
|
||||
@ -74,7 +73,7 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
// ActionSubmissionValidate invokes actionSubmissionValidate operation.
|
||||
//
|
||||
// Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
@ -84,10 +83,6 @@ func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params intern
|
||||
target_status := model.SubmissionStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("asset_version", params.ModelVersion)
|
||||
smap.Add("display_name", params.DisplayName)
|
||||
smap.Add("creator", params.Creator)
|
||||
smap.Add("game_id", params.GameID)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -117,70 +112,6 @@ func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params intern
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params internal.ActionSubmissionRequestChangesParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionValidate invokes actionSubmissionValidate operation.
|
||||
//
|
||||
// Role Validator changes status from Validating -> Validated.
|
||||
@ -230,37 +161,12 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna
|
||||
target_status := model.SubmissionStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("status_message", params.StatusMessage)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
@ -338,8 +244,6 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
|
||||
var Submitter=uint64(request.AssetOwner);
|
||||
var AssetID=uint64(request.AssetID);
|
||||
var AssetVersion=uint64(request.AssetVersion);
|
||||
var Status=model.SubmissionStatus(request.Status);
|
||||
var roles=service.Roles(request.Roles);
|
||||
|
||||
// Check if an active submission with the same asset id exists
|
||||
{
|
||||
@ -365,11 +269,8 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
|
||||
}
|
||||
|
||||
// check if user owns asset
|
||||
is_submitter := operation.Owner == Submitter
|
||||
// check if user is map admin
|
||||
has_submission_review := roles & service.RolesSubmissionReview == service.RolesSubmissionReview
|
||||
// if neither, u not allowed
|
||||
if !is_submitter && !has_submission_review {
|
||||
// TODO: allow bypass by admin
|
||||
if operation.Owner != Submitter {
|
||||
return nil, ErrNotAssetOwner
|
||||
}
|
||||
|
||||
@ -382,7 +283,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
|
||||
AssetID: AssetID,
|
||||
AssetVersion: AssetVersion,
|
||||
Completed: false,
|
||||
StatusID: Status,
|
||||
StatusID: model.SubmissionStatusUnderConstruction,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -5,16 +5,14 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
submissions-api = { path = "api", features = ["internal"], default-features = false, registry = "strafesnet" }
|
||||
async-nats = "0.41.0"
|
||||
async-nats = "0.40.0"
|
||||
futures = "0.3.31"
|
||||
rbx_asset = { version = "0.4.5", registry = "strafesnet" }
|
||||
rbx_binary = "1.0.0"
|
||||
rbx_dom_weak = "3.0.0"
|
||||
rbx_reflection_database = "1.0.3"
|
||||
rbx_xml = "1.0.0"
|
||||
rbx_asset = { version = "0.4.3", registry = "strafesnet" }
|
||||
rbx_binary = { version = "0.7.4", registry = "strafesnet"}
|
||||
rbx_dom_weak = { version = "2.9.0", registry = "strafesnet"}
|
||||
rbx_reflection_database = { version = "0.2.12", registry = "strafesnet"}
|
||||
rbx_xml = { version = "0.13.3", registry = "strafesnet"}
|
||||
serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.133"
|
||||
siphasher = "1.0.1"
|
||||
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread", "signal"] }
|
||||
heck = "0.5.0"
|
||||
lazy-regex = "3.4.1"
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "submissions-api"
|
||||
version = "0.7.2"
|
||||
version = "0.7.0"
|
||||
edition = "2021"
|
||||
publish = ["strafesnet"]
|
||||
repository = "https://git.itzana.me/StrafesNET/maps-service"
|
||||
|
@ -44,8 +44,4 @@ impl Context{
|
||||
.body(body)
|
||||
.send().await
|
||||
}
|
||||
pub async fn delete(&self,url:impl reqwest::IntoUrl)->Result<reqwest::Response,reqwest::Error>{
|
||||
self.client.delete(url)
|
||||
.send().await
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_scripts(&self,config:GetScriptsRequest<'_>)->Result<Vec<ScriptResponse>,Error>{
|
||||
pub async fn get_scripts<'a>(&self,config:GetScriptsRequest<'a>)->Result<Vec<ScriptResponse>,Error>{
|
||||
let url_raw=format!("{}/scripts",self.0.base_url);
|
||||
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -46,7 +46,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_script_from_hash(&self,config:HashRequest<'_>)->Result<Option<ScriptResponse>,ScriptSingleItemError>{
|
||||
pub async fn get_script_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptResponse>,SingleItemError>{
|
||||
let scripts=self.get_scripts(GetScriptsRequest{
|
||||
Page:1,
|
||||
Limit:2,
|
||||
@ -57,11 +57,11 @@ impl Context{
|
||||
ResourceID:None,
|
||||
}).await.map_err(SingleItemError::Other)?;
|
||||
if 1<scripts.len(){
|
||||
return Err(SingleItemError::DuplicateItems(scripts));
|
||||
return Err(SingleItemError::DuplicateItems);
|
||||
}
|
||||
Ok(scripts.into_iter().next())
|
||||
}
|
||||
pub async fn create_script(&self,config:CreateScriptRequest<'_>)->Result<ScriptIDResponse,Error>{
|
||||
pub async fn create_script<'a>(&self,config:CreateScriptRequest<'a>)->Result<ScriptIDResponse,Error>{
|
||||
let url_raw=format!("{}/scripts",self.0.base_url);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -72,17 +72,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn delete_script(&self,config:GetScriptRequest)->Result<(),Error>{
|
||||
let url_raw=format!("{}/scripts/{}",self.0.base_url,config.ScriptID.0);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
response_ok(
|
||||
self.0.delete(url).await.map_err(Error::Reqwest)?
|
||||
).await.map_err(Error::Response)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub async fn get_script_policies(&self,config:GetScriptPoliciesRequest<'_>)->Result<Vec<ScriptPolicyResponse>,Error>{
|
||||
pub async fn get_script_policies<'a>(&self,config:GetScriptPoliciesRequest<'a>)->Result<Vec<ScriptPolicyResponse>,Error>{
|
||||
let url_raw=format!("{}/script-policy",self.0.base_url);
|
||||
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -106,7 +96,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_script_policy_from_hash(&self,config:HashRequest<'_>)->Result<Option<ScriptPolicyResponse>,ScriptPolicySingleItemError>{
|
||||
pub async fn get_script_policy_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptPolicyResponse>,SingleItemError>{
|
||||
let policies=self.get_script_policies(GetScriptPoliciesRequest{
|
||||
Page:1,
|
||||
Limit:2,
|
||||
@ -115,7 +105,7 @@ impl Context{
|
||||
Policy:None,
|
||||
}).await.map_err(SingleItemError::Other)?;
|
||||
if 1<policies.len(){
|
||||
return Err(SingleItemError::DuplicateItems(policies));
|
||||
return Err(SingleItemError::DuplicateItems);
|
||||
}
|
||||
Ok(policies.into_iter().next())
|
||||
}
|
||||
@ -140,16 +130,6 @@ impl Context{
|
||||
self.0.post(url,body).await.map_err(Error::Reqwest)?
|
||||
).await.map_err(Error::Response)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub async fn delete_script_policy(&self,config:GetScriptPolicyRequest)->Result<(),Error>{
|
||||
let url_raw=format!("{}/script-policy/{}",self.0.base_url,config.ScriptPolicyID.0);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
response_ok(
|
||||
self.0.delete(url).await.map_err(Error::Reqwest)?
|
||||
).await.map_err(Error::Response)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_scripts(&self,config:GetScriptsRequest<'_>)->Result<Vec<ScriptResponse>,Error>{
|
||||
pub async fn get_scripts<'a>(&self,config:GetScriptsRequest<'a>)->Result<Vec<ScriptResponse>,Error>{
|
||||
let url_raw=format!("{}/scripts",self.0.base_url);
|
||||
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -76,7 +76,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_script_from_hash(&self,config:HashRequest<'_>)->Result<Option<ScriptResponse>,ScriptSingleItemError>{
|
||||
pub async fn get_script_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptResponse>,SingleItemError>{
|
||||
let scripts=self.get_scripts(GetScriptsRequest{
|
||||
Page:1,
|
||||
Limit:2,
|
||||
@ -87,11 +87,11 @@ impl Context{
|
||||
ResourceID:None,
|
||||
}).await.map_err(SingleItemError::Other)?;
|
||||
if 1<scripts.len(){
|
||||
return Err(SingleItemError::DuplicateItems(scripts));
|
||||
return Err(SingleItemError::DuplicateItems);
|
||||
}
|
||||
Ok(scripts.into_iter().next())
|
||||
}
|
||||
pub async fn create_script(&self,config:CreateScriptRequest<'_>)->Result<ScriptIDResponse,Error>{
|
||||
pub async fn create_script<'a>(&self,config:CreateScriptRequest<'a>)->Result<ScriptIDResponse,Error>{
|
||||
let url_raw=format!("{}/scripts",self.0.base_url);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -102,7 +102,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_script_policies(&self,config:GetScriptPoliciesRequest<'_>)->Result<Vec<ScriptPolicyResponse>,Error>{
|
||||
pub async fn get_script_policies<'a>(&self,config:GetScriptPoliciesRequest<'a>)->Result<Vec<ScriptPolicyResponse>,Error>{
|
||||
let url_raw=format!("{}/script-policy",self.0.base_url);
|
||||
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -126,7 +126,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn get_script_policy_from_hash(&self,config:HashRequest<'_>)->Result<Option<ScriptPolicyResponse>,ScriptPolicySingleItemError>{
|
||||
pub async fn get_script_policy_from_hash<'a>(&self,config:HashRequest<'a>)->Result<Option<ScriptPolicyResponse>,SingleItemError>{
|
||||
let policies=self.get_script_policies(GetScriptPoliciesRequest{
|
||||
Page:1,
|
||||
Limit:2,
|
||||
@ -135,7 +135,7 @@ impl Context{
|
||||
Policy:None,
|
||||
}).await.map_err(SingleItemError::Other)?;
|
||||
if 1<policies.len(){
|
||||
return Err(SingleItemError::DuplicateItems(policies));
|
||||
return Err(SingleItemError::DuplicateItems);
|
||||
}
|
||||
Ok(policies.into_iter().next())
|
||||
}
|
||||
@ -150,7 +150,7 @@ impl Context{
|
||||
).await.map_err(Error::Response)?
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
pub async fn create_submission(&self,config:CreateSubmissionRequest<'_>)->Result<SubmissionIDResponse,Error>{
|
||||
pub async fn create_submission<'a>(&self,config:CreateSubmissionRequest<'a>)->Result<SubmissionIDResponse,Error>{
|
||||
let url_raw=format!("{}/submissions",self.0.base_url);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -162,15 +162,6 @@ impl Context{
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
// simple submission endpoints
|
||||
action!("submissions",action_submission_request_changes,config,ActionSubmissionRequestChangesRequest,"status/validator-request-changes",config.SubmissionID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
action!("submissions",action_submission_submitted,config,ActionSubmissionSubmittedRequest,"status/validator-submitted",config.SubmissionID,
|
||||
("ModelVersion",config.ModelVersion.to_string().as_str())
|
||||
("DisplayName",config.DisplayName.as_str())
|
||||
("Creator",config.Creator.as_str())
|
||||
("GameID",config.GameID.to_string().as_str())
|
||||
);
|
||||
action!("submissions",action_submission_validated,config,SubmissionID,"status/validator-validated",config.0,);
|
||||
action!("submissions",update_submission_validated_model,config,UpdateSubmissionModelRequest,"validated-model",config.SubmissionID,
|
||||
("ValidatedModelID",config.ModelID.to_string().as_str())
|
||||
@ -180,9 +171,9 @@ impl Context{
|
||||
("UploadedAssetID",config.UploadedAssetID.to_string().as_str())
|
||||
);
|
||||
action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"status/validator-failed",config.SubmissionID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
("StatusMessage",config.StatusMessage.as_str())
|
||||
);
|
||||
pub async fn create_mapfix(&self,config:CreateMapfixRequest<'_>)->Result<MapfixIDResponse,Error>{
|
||||
pub async fn create_mapfix<'a>(&self,config:CreateMapfixRequest<'a>)->Result<MapfixIDResponse,Error>{
|
||||
let url_raw=format!("{}/mapfixes",self.0.base_url);
|
||||
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?;
|
||||
|
||||
@ -194,15 +185,6 @@ impl Context{
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
// simple mapfixes endpoints
|
||||
action!("mapfixes",action_mapfix_request_changes,config,ActionMapfixRequestChangesRequest,"status/validator-request-changes",config.MapfixID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
action!("mapfixes",action_mapfix_submitted,config,ActionMapfixSubmittedRequest,"status/validator-submitted",config.MapfixID,
|
||||
("ModelVersion",config.ModelVersion.to_string().as_str())
|
||||
("DisplayName",config.DisplayName.as_str())
|
||||
("Creator",config.Creator.as_str())
|
||||
("GameID",config.GameID.to_string().as_str())
|
||||
);
|
||||
action!("mapfixes",action_mapfix_validated,config,MapfixID,"status/validator-validated",config.0,);
|
||||
action!("mapfixes",update_mapfix_validated_model,config,UpdateMapfixModelRequest,"validated-model",config.MapfixID,
|
||||
("ValidatedModelID",config.ModelID.to_string().as_str())
|
||||
@ -210,7 +192,7 @@ impl Context{
|
||||
);
|
||||
action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"status/validator-uploaded",config.MapfixID,);
|
||||
action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"status/validator-failed",config.MapfixID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
("StatusMessage",config.StatusMessage.as_str())
|
||||
);
|
||||
// simple operation endpoint
|
||||
action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"status/operation-failed",config.OperationID,
|
||||
|
@ -14,25 +14,21 @@ impl std::fmt::Display for Error{
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SingleItemError<Items>{
|
||||
DuplicateItems(Items),
|
||||
pub enum SingleItemError{
|
||||
DuplicateItems,
|
||||
Other(Error),
|
||||
}
|
||||
impl<Items> std::fmt::Display for SingleItemError<Items>
|
||||
where
|
||||
Items:std::fmt::Debug
|
||||
{
|
||||
impl std::fmt::Display for SingleItemError{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl<Items> std::error::Error for SingleItemError<Items> where Items:std::fmt::Debug{}
|
||||
pub type ScriptSingleItemError=SingleItemError<Vec<ScriptResponse>>;
|
||||
pub type ScriptPolicySingleItemError=SingleItemError<Vec<ScriptPolicyResponse>>;
|
||||
impl std::error::Error for SingleItemError{}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct UrlAndBody{
|
||||
pub struct StatusCodeWithUrlAndBody{
|
||||
pub status_code:reqwest::StatusCode,
|
||||
pub url:url::Url,
|
||||
pub body:String,
|
||||
}
|
||||
@ -40,10 +36,7 @@ pub struct UrlAndBody{
|
||||
#[derive(Debug)]
|
||||
pub enum ResponseError{
|
||||
Reqwest(reqwest::Error),
|
||||
Details{
|
||||
status_code:reqwest::StatusCode,
|
||||
url_and_body:Box<UrlAndBody>,
|
||||
},
|
||||
StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody),
|
||||
}
|
||||
impl std::fmt::Display for ResponseError{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@ -60,10 +53,11 @@ pub async fn response_ok(response:reqwest::Response)->Result<reqwest::Response,R
|
||||
let url=response.url().to_owned();
|
||||
let bytes=response.bytes().await.map_err(ResponseError::Reqwest)?;
|
||||
let body=String::from_utf8_lossy(&bytes).to_string();
|
||||
Err(ResponseError::Details{
|
||||
Err(ResponseError::StatusCodeWithUrlAndBody(StatusCodeWithUrlAndBody{
|
||||
status_code,
|
||||
url_and_body:Box::new(UrlAndBody{url,body})
|
||||
})
|
||||
url,
|
||||
body,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +73,6 @@ pub struct CreateMapfixRequest<'a>{
|
||||
pub AssetID:u64,
|
||||
pub AssetVersion:u64,
|
||||
pub TargetAssetID:u64,
|
||||
pub Description:&'a str,
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug,serde::Deserialize)]
|
||||
@ -97,8 +90,6 @@ pub struct CreateSubmissionRequest<'a>{
|
||||
pub GameID:i32,
|
||||
pub AssetID:u64,
|
||||
pub AssetVersion:u64,
|
||||
pub Status:u32,
|
||||
pub Roles:u32,
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug,serde::Deserialize)]
|
||||
@ -178,10 +169,6 @@ pub enum Policy{
|
||||
Replace=4,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct GetScriptPolicyRequest{
|
||||
pub ScriptPolicyID:ScriptPolicyID,
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug,serde::Serialize)]
|
||||
pub struct GetScriptPoliciesRequest<'a>{
|
||||
@ -235,23 +222,6 @@ pub struct UpdateSubmissionModelRequest{
|
||||
pub ModelVersion:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionSubmittedRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ModelVersion:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionRequestChangesRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionUploadedRequest{
|
||||
@ -263,7 +233,7 @@ pub struct ActionSubmissionUploadedRequest{
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionAcceptedRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ErrorMessage:String,
|
||||
pub StatusMessage:String,
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,serde::Deserialize)]
|
||||
@ -277,23 +247,6 @@ pub struct UpdateMapfixModelRequest{
|
||||
pub ModelVersion:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixSubmittedRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ModelVersion:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixRequestChangesRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixUploadedRequest{
|
||||
@ -304,7 +257,7 @@ pub struct ActionMapfixUploadedRequest{
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixAcceptedRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ErrorMessage:String,
|
||||
pub StatusMessage:String,
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,serde::Deserialize)]
|
||||
|
@ -1,854 +0,0 @@
|
||||
use std::collections::{HashSet,HashMap};
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{get_mapinfo,get_root_instance,read_dom,ReadDomError,GameID,ParseGameIDError,MapInfo,GetRootInstanceError,StringValueError};
|
||||
|
||||
use heck::{ToSnakeCase,ToTitleCase};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
ModelInfoDownload(rbx_asset::cloud::GetError),
|
||||
CreatorTypeMustBeUser,
|
||||
Download(crate::download::Error),
|
||||
ModelFileDecode(ReadDomError),
|
||||
GetRootInstance(GetRootInstanceError),
|
||||
ToJsonValue(serde_json::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct CheckRequest{
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
impl From<crate::nats_types::CheckMapfixRequest> for CheckRequest{
|
||||
fn from(value:crate::nats_types::CheckMapfixRequest)->Self{
|
||||
Self{
|
||||
ModelID:value.ModelID,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::nats_types::CheckSubmissionRequest> for CheckRequest{
|
||||
fn from(value:crate::nats_types::CheckSubmissionRequest)->Self{
|
||||
Self{
|
||||
ModelID:value.ModelID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct ModeID(u64);
|
||||
impl ModeID{
|
||||
const MAIN:Self=Self(0);
|
||||
const BONUS:Self=Self(1);
|
||||
}
|
||||
enum Zone{
|
||||
Start,
|
||||
Finish,
|
||||
Anticheat,
|
||||
}
|
||||
struct ModeElement{
|
||||
zone:Zone,
|
||||
mode_id:ModeID,
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub enum IDParseError{
|
||||
NoCaptures,
|
||||
ParseInt(core::num::ParseIntError),
|
||||
}
|
||||
// Parse a Zone from a part name
|
||||
impl std::str::FromStr for ModeElement{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
match s{
|
||||
"MapStart"=>Ok(Self{zone:Zone::Start,mode_id:ModeID::MAIN}),
|
||||
"MapFinish"=>Ok(Self{zone:Zone::Finish,mode_id:ModeID::MAIN}),
|
||||
"MapAnticheat"=>Ok(Self{zone:Zone::Anticheat,mode_id:ModeID::MAIN}),
|
||||
"BonusStart"=>Ok(Self{zone:Zone::Start,mode_id:ModeID::BONUS}),
|
||||
"BonusFinish"=>Ok(Self{zone:Zone::Finish,mode_id:ModeID::BONUS}),
|
||||
"BonusAnticheat"=>Ok(Self{zone:Zone::Anticheat,mode_id:ModeID::BONUS}),
|
||||
other=>{
|
||||
let everything_pattern=lazy_regex::lazy_regex!(r"^Bonus(\d+)Start$|^BonusStart(\d+)$|^Bonus(\d+)Finish$|^BonusFinish(\d+)$|^Bonus(\d+)Anticheat$|^BonusAnticheat(\d+)$");
|
||||
if let Some(captures)=everything_pattern.captures(other){
|
||||
if let Some(mode_id)=captures.get(1).or(captures.get(2)){
|
||||
return Ok(Self{
|
||||
zone:Zone::Start,
|
||||
mode_id:ModeID(mode_id.as_str().parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
if let Some(mode_id)=captures.get(3).or(captures.get(4)){
|
||||
return Ok(Self{
|
||||
zone:Zone::Finish,
|
||||
mode_id:ModeID(mode_id.as_str().parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
if let Some(mode_id)=captures.get(5).or(captures.get(6)){
|
||||
return Ok(Self{
|
||||
zone:Zone::Anticheat,
|
||||
mode_id:ModeID(mode_id.as_str().parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for ModeElement{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
match self{
|
||||
ModeElement{zone:Zone::Start,mode_id:ModeID::MAIN}=>write!(f,"MapStart"),
|
||||
ModeElement{zone:Zone::Start,mode_id:ModeID::BONUS}=>write!(f,"BonusStart"),
|
||||
ModeElement{zone:Zone::Start,mode_id:ModeID(mode_id)}=>write!(f,"Bonus{mode_id}Start"),
|
||||
ModeElement{zone:Zone::Finish,mode_id:ModeID::MAIN}=>write!(f,"MapFinish"),
|
||||
ModeElement{zone:Zone::Finish,mode_id:ModeID::BONUS}=>write!(f,"BonusFinish"),
|
||||
ModeElement{zone:Zone::Finish,mode_id:ModeID(mode_id)}=>write!(f,"Bonus{mode_id}Finish"),
|
||||
ModeElement{zone:Zone::Anticheat,mode_id:ModeID::MAIN}=>write!(f,"MapAnticheat"),
|
||||
ModeElement{zone:Zone::Anticheat,mode_id:ModeID::BONUS}=>write!(f,"BonusAnticheat"),
|
||||
ModeElement{zone:Zone::Anticheat,mode_id:ModeID(mode_id)}=>write!(f,"Bonus{mode_id}Anticheat"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct StageID(u64);
|
||||
impl StageID{
|
||||
const FIRST:Self=Self(1);
|
||||
}
|
||||
enum StageElementBehaviour{
|
||||
Teleport,
|
||||
Spawn,
|
||||
}
|
||||
struct StageElement{
|
||||
stage_id:StageID,
|
||||
behaviour:StageElementBehaviour,
|
||||
}
|
||||
// Parse a SpawnTeleport from a part name
|
||||
impl std::str::FromStr for StageElement{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
// Trigger ForceTrigger Teleport ForceTeleport SpawnAt ForceSpawnAt
|
||||
let bonus_start_pattern=lazy_regex::lazy_regex!(r"^(?:Force)?(Teleport|SpawnAt|Trigger)(\d+)$");
|
||||
if let Some(captures)=bonus_start_pattern.captures(s){
|
||||
return Ok(StageElement{
|
||||
behaviour:StageElementBehaviour::Teleport,
|
||||
stage_id:StageID(captures[1].parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
// Spawn
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^Spawn(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(s){
|
||||
return Ok(StageElement{
|
||||
behaviour:StageElementBehaviour::Spawn,
|
||||
stage_id:StageID(captures[1].parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for StageElement{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
match self{
|
||||
StageElement{behaviour:StageElementBehaviour::Spawn,stage_id:StageID(stage_id)}=>write!(f,"Spawn{stage_id}"),
|
||||
StageElement{behaviour:StageElementBehaviour::Teleport,stage_id:StageID(stage_id)}=>write!(f,"Teleport{stage_id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct WormholeID(u64);
|
||||
enum WormholeBehaviour{
|
||||
In,
|
||||
Out,
|
||||
}
|
||||
struct WormholeElement{
|
||||
behaviour:WormholeBehaviour,
|
||||
wormhole_id:WormholeID,
|
||||
}
|
||||
// Parse a Wormhole from a part name
|
||||
impl std::str::FromStr for WormholeElement{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
let bonus_start_pattern=lazy_regex::lazy_regex!(r"^WormholeIn(\d+)$");
|
||||
if let Some(captures)=bonus_start_pattern.captures(s){
|
||||
return Ok(Self{
|
||||
behaviour:WormholeBehaviour::In,
|
||||
wormhole_id:WormholeID(captures[1].parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^WormholeOut(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(s){
|
||||
return Ok(Self{
|
||||
behaviour:WormholeBehaviour::Out,
|
||||
wormhole_id:WormholeID(captures[1].parse().map_err(IDParseError::ParseInt)?),
|
||||
});
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for WormholeElement{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
match self{
|
||||
WormholeElement{behaviour:WormholeBehaviour::In,wormhole_id:WormholeID(wormhole_id)}=>write!(f,"WormholeIn{wormhole_id}"),
|
||||
WormholeElement{behaviour:WormholeBehaviour::Out,wormhole_id:WormholeID(wormhole_id)}=>write!(f,"WormholeOut{wormhole_id}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Count various map elements
|
||||
#[derive(Default)]
|
||||
struct Counts<'a>{
|
||||
mode_start_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
mode_finish_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
mode_anticheat_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
teleport_counts:HashMap<StageID,Vec<&'a str>>,
|
||||
spawn_counts:HashMap<StageID,u64>,
|
||||
wormhole_in_counts:HashMap<WormholeID,u64>,
|
||||
wormhole_out_counts:HashMap<WormholeID,u64>,
|
||||
}
|
||||
|
||||
pub struct ModelInfo<'a>{
|
||||
model_class:&'a str,
|
||||
model_name:&'a str,
|
||||
map_info:MapInfo<'a>,
|
||||
counts:Counts<'a>,
|
||||
}
|
||||
|
||||
pub fn get_model_info<'a>(dom:&'a rbx_dom_weak::WeakDom,model_instance:&'a rbx_dom_weak::Instance)->ModelInfo<'a>{
|
||||
// extract model info
|
||||
let map_info=get_mapinfo(dom,model_instance);
|
||||
|
||||
// count objects (default count is 0)
|
||||
let mut counts=Counts::default();
|
||||
|
||||
let db=rbx_reflection_database::get();
|
||||
let base_part=&db.classes["BasePart"];
|
||||
let base_parts=dom.descendants_of(model_instance.referent()).filter(|&instance|
|
||||
db.classes.get(instance.class.as_str()).is_some_and(|class|
|
||||
db.has_superclass(class,base_part)
|
||||
)
|
||||
);
|
||||
for instance in base_parts{
|
||||
// Zones
|
||||
match instance.name.parse(){
|
||||
Ok(ModeElement{zone:Zone::Start,mode_id})=>counts.mode_start_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Ok(ModeElement{zone:Zone::Finish,mode_id})=>counts.mode_finish_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Ok(ModeElement{zone:Zone::Anticheat,mode_id})=>counts.mode_anticheat_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Err(_)=>(),
|
||||
}
|
||||
// Spawns & Teleports
|
||||
match instance.name.parse(){
|
||||
Ok(StageElement{behaviour:StageElementBehaviour::Teleport,stage_id})=>counts.teleport_counts.entry(stage_id).or_default().push(instance.name.as_str()),
|
||||
Ok(StageElement{behaviour:StageElementBehaviour::Spawn,stage_id})=>*counts.spawn_counts.entry(stage_id).or_insert(0)+=1,
|
||||
Err(_)=>(),
|
||||
}
|
||||
// Wormholes
|
||||
match instance.name.parse(){
|
||||
Ok(WormholeElement{behaviour:WormholeBehaviour::In,wormhole_id})=>*counts.wormhole_in_counts.entry(wormhole_id).or_insert(0)+=1,
|
||||
Ok(WormholeElement{behaviour:WormholeBehaviour::Out,wormhole_id})=>*counts.wormhole_out_counts.entry(wormhole_id).or_insert(0)+=1,
|
||||
Err(_)=>(),
|
||||
}
|
||||
}
|
||||
|
||||
ModelInfo{
|
||||
model_class:model_instance.class.as_str(),
|
||||
model_name:model_instance.name.as_str(),
|
||||
map_info,
|
||||
counts,
|
||||
}
|
||||
}
|
||||
|
||||
// check if an observed string matches an expected string
|
||||
pub struct StringCheck<'a,T,Str>(Result<T,StringCheckContext<'a,Str>>);
|
||||
pub struct StringCheckContext<'a,Str>{
|
||||
observed:&'a str,
|
||||
expected:Str,
|
||||
}
|
||||
impl<'a,Str> StringCheckContext<'a,Str>
|
||||
where
|
||||
&'a str:PartialEq<Str>,
|
||||
{
|
||||
/// Compute the StringCheck, passing through the provided value on success.
|
||||
fn check<T>(self,value:T)->StringCheck<'a,T,Str>{
|
||||
if self.observed==self.expected{
|
||||
StringCheck(Ok(value))
|
||||
}else{
|
||||
StringCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<Str:std::fmt::Display> std::fmt::Display for StringCheckContext<'_,Str>{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"expected: {}, observed: {}",self.expected,self.observed)
|
||||
}
|
||||
}
|
||||
|
||||
// check if a string is empty
|
||||
pub struct StringEmpty;
|
||||
impl std::fmt::Display for StringEmpty{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"Empty string")
|
||||
}
|
||||
}
|
||||
fn check_empty(value:&str)->Result<&str,StringEmpty>{
|
||||
(!value.is_empty()).then_some(value).ok_or(StringEmpty)
|
||||
}
|
||||
|
||||
// check for duplicate objects
|
||||
pub struct DuplicateCheckContext<ID,T>(HashMap<ID,T>);
|
||||
pub struct DuplicateCheck<ID,T>(Result<(),DuplicateCheckContext<ID,T>>);
|
||||
impl<ID,T> DuplicateCheckContext<ID,T>{
|
||||
/// Compute the DuplicateCheck using the contents predicate.
|
||||
fn check(self,f:impl Fn(&T)->bool)->DuplicateCheck<ID,T>{
|
||||
let Self(mut set)=self;
|
||||
// remove correct entries
|
||||
set.retain(|_,c|f(c));
|
||||
// if any entries remain, they are incorrect
|
||||
if set.is_empty(){
|
||||
DuplicateCheck(Ok(()))
|
||||
}else{
|
||||
DuplicateCheck(Err(Self(set)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that there are no items which do not have a matching item in a reference set
|
||||
pub struct SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
extra:HashMap<ID,T>,
|
||||
}
|
||||
// Check that there is at least one matching item for each item in a reference set, and no extra items
|
||||
pub struct SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
extra:HashMap<ID,T>,
|
||||
missing:HashSet<ID>,
|
||||
}
|
||||
pub struct SetDifferenceCheck<Context>(Result<(),Context>);
|
||||
impl<ID,T> SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
fn new(initial_set:HashMap<ID,T>)->Self{
|
||||
Self{
|
||||
extra:initial_set,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID:Eq+std::hash::Hash,T> SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
/// Compute the SetDifferenceCheck result for the specified reference set.
|
||||
fn check<U>(mut self,reference_set:&HashMap<ID,U>)->SetDifferenceCheck<Self>{
|
||||
// remove correct entries
|
||||
for id in reference_set.keys(){
|
||||
self.extra.remove(id);
|
||||
}
|
||||
// if any entries remain, they are incorrect
|
||||
if self.extra.is_empty(){
|
||||
SetDifferenceCheck(Ok(()))
|
||||
}else{
|
||||
SetDifferenceCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID,T> SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
fn new(initial_set:HashMap<ID,T>)->Self{
|
||||
Self{
|
||||
extra:initial_set,
|
||||
missing:HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID:Copy+Eq+std::hash::Hash,T> SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
/// Compute the SetDifferenceCheck result for the specified reference set.
|
||||
fn check<U>(mut self,reference_set:&HashMap<ID,U>)->SetDifferenceCheck<Self>{
|
||||
// remove correct entries
|
||||
for id in reference_set.keys(){
|
||||
if self.extra.remove(id).is_none(){
|
||||
// the set did not contain a required item. This is a fail
|
||||
self.missing.insert(*id);
|
||||
}
|
||||
}
|
||||
// if any entries remain, they are incorrect
|
||||
if self.extra.is_empty()&&self.missing.is_empty(){
|
||||
SetDifferenceCheck(Ok(()))
|
||||
}else{
|
||||
SetDifferenceCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Info lifted out of a fully compliant map
|
||||
pub struct MapInfoOwned{
|
||||
pub display_name:String,
|
||||
pub creator:String,
|
||||
pub game_id:GameID,
|
||||
}
|
||||
|
||||
// Named dummy types for readability
|
||||
struct Exists;
|
||||
struct Absent;
|
||||
|
||||
/// The result of every map check.
|
||||
struct MapCheck<'a>{
|
||||
// === METADATA CHECKS ===
|
||||
// The root must be of class Model
|
||||
model_class:StringCheck<'a,(),&'static str>,
|
||||
// Model's name must be in snake case
|
||||
model_name:StringCheck<'a,(),String>,
|
||||
// Map must have a StringValue named DisplayName.
|
||||
// Value must not be empty, must be in title case.
|
||||
display_name:Result<Result<StringCheck<'a,&'a str,String>,StringEmpty>,StringValueError>,
|
||||
// Map must have a StringValue named Creator.
|
||||
// Value must not be empty.
|
||||
creator:Result<Result<&'a str,StringEmpty>,StringValueError>,
|
||||
// The prefix of the model's name must match the game it was submitted for.
|
||||
// bhop_ for bhop, and surf_ for surf
|
||||
game_id:Result<GameID,ParseGameIDError>,
|
||||
|
||||
// === MODE CHECKS ===
|
||||
// MapStart must exist
|
||||
mapstart:Result<Exists,Absent>,
|
||||
// No duplicate map starts (including bonuses)
|
||||
mode_start_counts:DuplicateCheck<ModeID,Vec<&'a str>>,
|
||||
// At least one finish zone for each start zone, and no finishes with no start
|
||||
mode_finish_counts:SetDifferenceCheck<SetDifferenceCheckContextAtLeastOne<ModeID,Vec<&'a str>>>,
|
||||
// Check for dangling MapAnticheat zones (no associated MapStart)
|
||||
mode_anticheat_counts:SetDifferenceCheck<SetDifferenceCheckContextAllowNone<ModeID,Vec<&'a str>>>,
|
||||
// Spawn1 must exist
|
||||
spawn1:Result<Exists,Absent>,
|
||||
// Check for dangling Teleport# (no associated Spawn#)
|
||||
teleport_counts:SetDifferenceCheck<SetDifferenceCheckContextAllowNone<StageID,Vec<&'a str>>>,
|
||||
// No duplicate Spawn#
|
||||
spawn_counts:DuplicateCheck<StageID,u64>,
|
||||
// Check for dangling WormholeIn# (no associated WormholeOut#)
|
||||
wormhole_in_counts:SetDifferenceCheck<SetDifferenceCheckContextAtLeastOne<WormholeID,u64>>,
|
||||
// No duplicate WormholeOut# (duplicate WormholeIn# ok)
|
||||
// No dangling WormholeOut#
|
||||
wormhole_out_counts:DuplicateCheck<WormholeID,u64>,
|
||||
}
|
||||
|
||||
impl<'a> ModelInfo<'a>{
|
||||
fn check(self)->MapCheck<'a>{
|
||||
// Check class is exactly "Model"
|
||||
let model_class=StringCheckContext{
|
||||
observed:self.model_class,
|
||||
expected:"Model",
|
||||
}.check(());
|
||||
|
||||
// Check model name is snake case
|
||||
let model_name=StringCheckContext{
|
||||
observed:self.model_name,
|
||||
expected:self.model_name.to_snake_case(),
|
||||
}.check(());
|
||||
|
||||
// Check display name is not empty and has title case
|
||||
let display_name=self.map_info.display_name.map(|display_name|{
|
||||
check_empty(display_name).map(|display_name|StringCheckContext{
|
||||
observed:display_name,
|
||||
expected:display_name.to_title_case(),
|
||||
}.check(display_name))
|
||||
});
|
||||
|
||||
// Check Creator is not empty
|
||||
let creator=self.map_info.creator.map(check_empty);
|
||||
|
||||
// Check GameID (model name was prefixed with bhop_ surf_ etc)
|
||||
let game_id=self.map_info.game_id;
|
||||
|
||||
// MapStart must exist
|
||||
let mapstart=if self.counts.mode_start_counts.contains_key(&ModeID::MAIN){
|
||||
Ok(Exists)
|
||||
}else{
|
||||
Err(Absent)
|
||||
};
|
||||
|
||||
// Spawn1 must exist
|
||||
let spawn1=if self.counts.spawn_counts.contains_key(&StageID::FIRST){
|
||||
Ok(Exists)
|
||||
}else{
|
||||
Err(Absent)
|
||||
};
|
||||
|
||||
// Check that at least one finish zone exists for each start zone.
|
||||
// This also checks that there are no finish zones without a corresponding start zone.
|
||||
let mode_finish_counts=SetDifferenceCheckContextAtLeastOne::new(self.counts.mode_finish_counts)
|
||||
.check(&self.counts.mode_start_counts);
|
||||
|
||||
// Check that there are no anticheat zones without a corresponding start zone.
|
||||
// Modes are allowed to have 0 anticheat zones.
|
||||
let mode_anticheat_counts=SetDifferenceCheckContextAllowNone::new(self.counts.mode_anticheat_counts)
|
||||
.check(&self.counts.mode_start_counts);
|
||||
|
||||
// There must be exactly one start zone for every mode in the map.
|
||||
let mode_start_counts=DuplicateCheckContext(self.counts.mode_start_counts).check(|c|1<c.len());
|
||||
|
||||
// Check that there are no Teleports without a corresponding Spawn.
|
||||
// Spawns are allowed to have 0 Teleports.
|
||||
let teleport_counts=SetDifferenceCheckContextAllowNone::new(self.counts.teleport_counts)
|
||||
.check(&self.counts.spawn_counts);
|
||||
|
||||
// There must be exactly one of any perticular spawn id in the map.
|
||||
let spawn_counts=DuplicateCheckContext(self.counts.spawn_counts).check(|&c|1<c);
|
||||
|
||||
// Check that at least one WormholeIn exists for each WormholeOut.
|
||||
// This also checks that there are no WormholeIn without a corresponding WormholeOut.
|
||||
let wormhole_in_counts=SetDifferenceCheckContextAtLeastOne::new(self.counts.wormhole_in_counts)
|
||||
.check(&self.counts.wormhole_out_counts);
|
||||
|
||||
// There must be exactly one of any perticular wormhole out id in the map.
|
||||
let wormhole_out_counts=DuplicateCheckContext(self.counts.wormhole_out_counts).check(|&c|1<c);
|
||||
|
||||
MapCheck{
|
||||
model_class,
|
||||
model_name,
|
||||
display_name,
|
||||
creator,
|
||||
game_id,
|
||||
mapstart,
|
||||
mode_start_counts,
|
||||
mode_finish_counts,
|
||||
mode_anticheat_counts,
|
||||
spawn1,
|
||||
teleport_counts,
|
||||
spawn_counts,
|
||||
wormhole_in_counts,
|
||||
wormhole_out_counts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MapCheck<'_>{
|
||||
fn result(self)->Result<MapInfoOwned,Result<MapCheckList,serde_json::Error>>{
|
||||
match self{
|
||||
MapCheck{
|
||||
model_class:StringCheck(Ok(())),
|
||||
model_name:StringCheck(Ok(())),
|
||||
display_name:Ok(Ok(StringCheck(Ok(display_name)))),
|
||||
creator:Ok(Ok(creator)),
|
||||
game_id:Ok(game_id),
|
||||
mapstart:Ok(Exists),
|
||||
mode_start_counts:DuplicateCheck(Ok(())),
|
||||
mode_finish_counts:SetDifferenceCheck(Ok(())),
|
||||
mode_anticheat_counts:SetDifferenceCheck(Ok(())),
|
||||
spawn1:Ok(Exists),
|
||||
teleport_counts:SetDifferenceCheck(Ok(())),
|
||||
spawn_counts:DuplicateCheck(Ok(())),
|
||||
wormhole_in_counts:SetDifferenceCheck(Ok(())),
|
||||
wormhole_out_counts:DuplicateCheck(Ok(())),
|
||||
}=>{
|
||||
Ok(MapInfoOwned{
|
||||
display_name:display_name.to_owned(),
|
||||
creator:creator.to_owned(),
|
||||
game_id,
|
||||
})
|
||||
},
|
||||
other=>Err(other.itemize()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Separated<F>{
|
||||
f:F,
|
||||
separator:&'static str,
|
||||
}
|
||||
impl<F> Separated<F>{
|
||||
fn new(separator:&'static str,f:F)->Self{
|
||||
Self{separator,f}
|
||||
}
|
||||
}
|
||||
impl<F,I,D> std::fmt::Display for Separated<F>
|
||||
where
|
||||
D:std::fmt::Display,
|
||||
I:IntoIterator<Item=D>,
|
||||
F:Fn()->I,
|
||||
{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
let mut it=(self.f)().into_iter();
|
||||
if let Some(first)=it.next(){
|
||||
write!(f,"{first}")?;
|
||||
for item in it{
|
||||
write!(f,"{}{item}",self.separator)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct Duplicates<D>{
|
||||
display:D,
|
||||
duplicates:usize,
|
||||
}
|
||||
impl<D> Duplicates<D>{
|
||||
fn new(display:D,duplicates:usize)->Self{
|
||||
Self{
|
||||
display,
|
||||
duplicates,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<D:std::fmt::Display> std::fmt::Display for Duplicates<D>{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{} ({} duplicates)",self.display,self.duplicates)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct CheckSummary{
|
||||
name:&'static str,
|
||||
summary:String,
|
||||
passed:bool,
|
||||
details:serde_json::Value,
|
||||
}
|
||||
impl CheckSummary{
|
||||
const fn passed(name:&'static str)->Self{
|
||||
Self{
|
||||
name,
|
||||
summary:String::new(),
|
||||
passed:true,
|
||||
details:serde_json::Value::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
macro_rules! summary{
|
||||
($name:literal,$summary:expr,$details:expr)=>{
|
||||
CheckSummary{
|
||||
name:$name,
|
||||
summary:$summary,
|
||||
passed:false,
|
||||
details:serde_json::to_value($details)?,
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! summary_format{
|
||||
($name:literal,$fmt:literal,$details:expr)=>{
|
||||
CheckSummary{
|
||||
name:$name,
|
||||
summary:format!($fmt),
|
||||
passed:false,
|
||||
details:serde_json::to_value($details)?,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Generate an error message for each observed issue separated by newlines.
|
||||
// This defines MapCheck.to_string() which is used in MapCheck.result()
|
||||
impl MapCheck<'_>{
|
||||
fn itemize(&self)->Result<MapCheckList,serde_json::Error>{
|
||||
let model_class=match &self.model_class{
|
||||
StringCheck(Ok(()))=>CheckSummary::passed("ModelClass"),
|
||||
StringCheck(Err(context))=>summary_format!("ModelClass","Invalid model class: {context}",()),
|
||||
};
|
||||
let model_name=match &self.model_name{
|
||||
StringCheck(Ok(()))=>CheckSummary::passed("ModelName"),
|
||||
StringCheck(Err(context))=>summary_format!("ModelName","Model name must have snake_case: {context}",()),
|
||||
};
|
||||
let display_name=match &self.display_name{
|
||||
Ok(Ok(StringCheck(Ok(_))))=>CheckSummary::passed("DisplayName"),
|
||||
Ok(Ok(StringCheck(Err(context))))=>summary_format!("DisplayName","DisplayName must have Title Case: {context}",()),
|
||||
Ok(Err(context))=>summary_format!("DisplayName","Invalid DisplayName: {context}",()),
|
||||
Err(StringValueError::ObjectNotFound)=>summary!("DisplayName","Missing DisplayName StringValue".to_owned(),()),
|
||||
Err(StringValueError::ValueNotSet)=>summary!("DisplayName","DisplayName Value not set".to_owned(),()),
|
||||
Err(StringValueError::NonStringValue)=>summary!("DisplayName","DisplayName Value is not a String".to_owned(),()),
|
||||
};
|
||||
let creator=match &self.creator{
|
||||
Ok(Ok(_))=>CheckSummary::passed("Creator"),
|
||||
Ok(Err(context))=>summary_format!("Creator","Invalid Creator: {context}",()),
|
||||
Err(StringValueError::ObjectNotFound)=>summary!("Creator","Missing Creator StringValue".to_owned(),()),
|
||||
Err(StringValueError::ValueNotSet)=>summary!("Creator","Creator Value not set".to_owned(),()),
|
||||
Err(StringValueError::NonStringValue)=>summary!("Creator","Creator Value is not a String".to_owned(),()),
|
||||
};
|
||||
let game_id=match &self.game_id{
|
||||
Ok(_)=>CheckSummary::passed("GameID"),
|
||||
Err(ParseGameIDError)=>summary!("GameID","Model name must be prefixed with bhop_ surf_ or flytrials_".to_owned(),()),
|
||||
};
|
||||
let mapstart=match &self.mapstart{
|
||||
Ok(Exists)=>CheckSummary::passed("MapStart"),
|
||||
Err(Absent)=>summary_format!("MapStart","Model has no MapStart",()),
|
||||
};
|
||||
let duplicate_start=match &self.mode_start_counts{
|
||||
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateStart"),
|
||||
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
|
||||
let context=Separated::new(", ",||context.iter().map(|(&mode_id,names)|
|
||||
Duplicates::new(ModeElement{zone:Zone::Start,mode_id},names.len())
|
||||
));
|
||||
summary_format!("DuplicateStart","Duplicate start zones: {context}",())
|
||||
}
|
||||
};
|
||||
let (extra_finish,missing_finish)=match &self.mode_finish_counts{
|
||||
SetDifferenceCheck(Ok(()))=>(CheckSummary::passed("ExtraFinish"),CheckSummary::passed("MissingFinish")),
|
||||
SetDifferenceCheck(Err(context))=>(
|
||||
if context.extra.is_empty(){
|
||||
CheckSummary::passed("ExtraFinish")
|
||||
}else{
|
||||
let plural=if context.extra.len()==1{"zone"}else{"zones"};
|
||||
let context=Separated::new(", ",||context.extra.iter().map(|(&mode_id,_names)|
|
||||
ModeElement{zone:Zone::Finish,mode_id}
|
||||
));
|
||||
summary_format!("ExtraFinish","No matching start zone for finish {plural}: {context}",())
|
||||
},
|
||||
if context.missing.is_empty(){
|
||||
CheckSummary::passed("MissingFinish")
|
||||
}else{
|
||||
let plural=if context.missing.len()==1{"zone"}else{"zones"};
|
||||
let context=Separated::new(", ",||context.missing.iter().map(|&mode_id|
|
||||
ModeElement{zone:Zone::Finish,mode_id}
|
||||
));
|
||||
summary_format!("MissingFinish","Missing finish {plural}: {context}",())
|
||||
}
|
||||
),
|
||||
};
|
||||
let dangling_anticheat=match &self.mode_anticheat_counts{
|
||||
SetDifferenceCheck(Ok(()))=>CheckSummary::passed("DanglingAnticheat"),
|
||||
SetDifferenceCheck(Err(context))=>{
|
||||
if context.extra.is_empty(){
|
||||
CheckSummary::passed("DanglingAnticheat")
|
||||
}else{
|
||||
let plural=if context.extra.len()==1{"zone"}else{"zones"};
|
||||
let context=Separated::new(", ",||context.extra.iter().map(|(&mode_id,_names)|
|
||||
ModeElement{zone:Zone::Anticheat,mode_id}
|
||||
));
|
||||
summary_format!("DanglingAnticheat","No matching start zone for anticheat {plural}: {context}",())
|
||||
}
|
||||
}
|
||||
};
|
||||
let spawn1=match &self.spawn1{
|
||||
Ok(Exists)=>CheckSummary::passed("Spawn1"),
|
||||
Err(Absent)=>summary_format!("Spawn1","Model has no Spawn1",()),
|
||||
};
|
||||
let dangling_teleport=match &self.teleport_counts{
|
||||
SetDifferenceCheck(Ok(()))=>CheckSummary::passed("DanglingTeleport"),
|
||||
SetDifferenceCheck(Err(context))=>{
|
||||
let unique_names:HashSet<_>=context.extra.values().flat_map(|names|names.iter().copied()).collect();
|
||||
let plural=if unique_names.len()==1{"object"}else{"objects"};
|
||||
let context=Separated::new(", ",||&unique_names);
|
||||
summary_format!("DanglingTeleport","No matching Spawn for {plural}: {context}",())
|
||||
}
|
||||
};
|
||||
let duplicate_spawns=match &self.spawn_counts{
|
||||
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateSpawn"),
|
||||
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
|
||||
let context=Separated::new(", ",||context.iter().map(|(&stage_id,&names)|
|
||||
Duplicates::new(StageElement{behaviour:StageElementBehaviour::Spawn,stage_id},names as usize)
|
||||
));
|
||||
summary_format!("DuplicateSpawn","Duplicate Spawn: {context}",())
|
||||
}
|
||||
};
|
||||
let (extra_wormhole_in,missing_wormhole_in)=match &self.wormhole_in_counts{
|
||||
SetDifferenceCheck(Ok(()))=>(CheckSummary::passed("ExtraWormholeIn"),CheckSummary::passed("MissingWormholeIn")),
|
||||
SetDifferenceCheck(Err(context))=>(
|
||||
if context.extra.is_empty(){
|
||||
CheckSummary::passed("ExtraWormholeIn")
|
||||
}else{
|
||||
let context=Separated::new(", ",||context.extra.iter().map(|(&wormhole_id,_names)|
|
||||
WormholeElement{behaviour:WormholeBehaviour::In,wormhole_id}
|
||||
));
|
||||
summary_format!("ExtraWormholeIn","WormholeIn with no matching WormholeOut: {context}",())
|
||||
},
|
||||
if context.missing.is_empty(){
|
||||
CheckSummary::passed("MissingWormholeIn")
|
||||
}else{
|
||||
// This counts WormholeIn objects, but
|
||||
// flipped logic is easier to understand
|
||||
let context=Separated::new(", ",||context.missing.iter().map(|&wormhole_id|
|
||||
WormholeElement{behaviour:WormholeBehaviour::Out,wormhole_id}
|
||||
));
|
||||
summary_format!("MissingWormholeIn","WormholeOut with no matching WormholeIn: {context}",())
|
||||
}
|
||||
)
|
||||
};
|
||||
let duplicate_wormhole_out=match &self.wormhole_out_counts{
|
||||
DuplicateCheck(Ok(()))=>CheckSummary::passed("DuplicateWormholeOut"),
|
||||
DuplicateCheck(Err(DuplicateCheckContext(context)))=>{
|
||||
let context=Separated::new(", ",||context.iter().map(|(&wormhole_id,&names)|
|
||||
Duplicates::new(WormholeElement{behaviour:WormholeBehaviour::Out,wormhole_id},names as usize)
|
||||
));
|
||||
summary_format!("DuplicateWormholeOut","Duplicate WormholeOut: {context}",())
|
||||
}
|
||||
};
|
||||
Ok(MapCheckList{checks:Box::new([
|
||||
model_class,
|
||||
model_name,
|
||||
display_name,
|
||||
creator,
|
||||
game_id,
|
||||
mapstart,
|
||||
duplicate_start,
|
||||
extra_finish,
|
||||
missing_finish,
|
||||
dangling_anticheat,
|
||||
spawn1,
|
||||
dangling_teleport,
|
||||
duplicate_spawns,
|
||||
extra_wormhole_in,
|
||||
missing_wormhole_in,
|
||||
duplicate_wormhole_out,
|
||||
])})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(serde::Serialize)]
|
||||
struct MapCheckList{
|
||||
checks:Box<[CheckSummary;16]>,
|
||||
}
|
||||
impl MapCheckList{
|
||||
fn summary(&self)->String{
|
||||
Separated::new("; ",||self.checks.iter().filter_map(|check|
|
||||
(!check.passed).then_some(check.summary.as_str())
|
||||
)).to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Summary{
|
||||
pub summary:String,
|
||||
pub json:serde_json::Value,
|
||||
}
|
||||
|
||||
pub struct CheckReportAndVersion{
|
||||
pub status:Result<MapInfoOwned,Summary>,
|
||||
pub version:u64,
|
||||
}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_inner(&self,check_info:CheckRequest)->Result<CheckReportAndVersion,Error>{
|
||||
// discover asset creator and latest version
|
||||
let info=self.cloud_context.get_asset_info(
|
||||
rbx_asset::cloud::GetAssetLatestRequest{asset_id:check_info.ModelID}
|
||||
).await.map_err(Error::ModelInfoDownload)?;
|
||||
|
||||
// reject models created by a group
|
||||
let rbx_asset::cloud::Creator::userId(_user_id)=info.creationContext.creator else{
|
||||
return Err(Error::CreatorTypeMustBeUser);
|
||||
};
|
||||
|
||||
// parse model version string
|
||||
let version=info.revisionId;
|
||||
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:check_info.ModelID,
|
||||
version,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
// extract the root instance
|
||||
let model_instance=get_root_instance(&dom).map_err(Error::GetRootInstance)?;
|
||||
|
||||
// extract information from the model
|
||||
let model_info=get_model_info(&dom,model_instance);
|
||||
|
||||
// convert the model information into a structured report
|
||||
let map_check=model_info.check();
|
||||
|
||||
// check the report, generate an error message if it fails the check
|
||||
let status=match map_check.result(){
|
||||
Ok(map_info)=>Ok(map_info),
|
||||
Err(Ok(summary))=>Err(Summary{
|
||||
summary:summary.summary(),
|
||||
json:serde_json::to_value(&summary).map_err(Error::ToJsonValue)?,
|
||||
}),
|
||||
Err(Err(e))=>return Err(Error::ToJsonValue(e)),
|
||||
};
|
||||
|
||||
Ok(CheckReportAndVersion{status,version})
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
use crate::check::CheckReportAndVersion;
|
||||
use crate::nats_types::CheckMapfixRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Check(crate::check::Error),
|
||||
ApiActionMapfixCheck(submissions_api::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_mapfix(&self,check_info:CheckMapfixRequest)->Result<(),Error>{
|
||||
let mapfix_id=check_info.MapfixID;
|
||||
let check_result=self.check_inner(check_info.into()).await;
|
||||
|
||||
// update the mapfix depending on the result
|
||||
match check_result{
|
||||
Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_mapfix_submitted(
|
||||
submissions_api::types::ActionMapfixSubmittedRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ModelVersion:version,
|
||||
DisplayName:map_info.display_name,
|
||||
Creator:map_info.creator,
|
||||
GameID:map_info.game_id as u32,
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?,
|
||||
// update the mapfix model status to request changes
|
||||
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_mapfix_request_changes(
|
||||
submissions_api::types::ActionMapfixRequestChangesRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ErrorMessage:report.summary,
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?,
|
||||
// update the mapfix model status to request changes
|
||||
Err(e)=>{
|
||||
// log error
|
||||
println!("[check_mapfix] Error: {e}");
|
||||
|
||||
self.api.action_mapfix_request_changes(
|
||||
submissions_api::types::ActionMapfixRequestChangesRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
use crate::check::CheckReportAndVersion;
|
||||
use crate::nats_types::CheckSubmissionRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Check(crate::check::Error),
|
||||
ApiActionSubmissionCheck(submissions_api::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_submission(&self,check_info:CheckSubmissionRequest)->Result<(),Error>{
|
||||
let submission_id=check_info.SubmissionID;
|
||||
let check_result=self.check_inner(check_info.into()).await;
|
||||
|
||||
// update the submission depending on the result
|
||||
match check_result{
|
||||
// update the submission model status to submitted
|
||||
Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_submission_submitted(
|
||||
submissions_api::types::ActionSubmissionSubmittedRequest{
|
||||
SubmissionID:submission_id,
|
||||
ModelVersion:version,
|
||||
DisplayName:map_info.display_name,
|
||||
Creator:map_info.creator,
|
||||
GameID:map_info.game_id as u32,
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?,
|
||||
// update the submission model status to request changes
|
||||
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_submission_request_changes(
|
||||
submissions_api::types::ActionSubmissionRequestChangesRequest{
|
||||
SubmissionID:submission_id,
|
||||
ErrorMessage:report.summary,
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?,
|
||||
// update the submission model status to request changes
|
||||
Err(e)=>{
|
||||
// log error
|
||||
println!("[check_submission] Error: {e}");
|
||||
|
||||
self.api.action_submission_request_changes(
|
||||
submissions_api::types::ActionSubmissionRequestChangesRequest{
|
||||
SubmissionID:submission_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,14 +1,18 @@
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{get_root_instance,get_mapinfo,read_dom,MapInfo,ReadDomError,GetRootInstanceError,GameID};
|
||||
use crate::rbx_util::{get_mapinfo,read_dom,MapInfo,ReadDomError,GetMapInfoError,ParseGameIDError};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
CreatorTypeMustBeUser,
|
||||
ModelInfoDownload(rbx_asset::cloud::GetError),
|
||||
Download(crate::download::Error),
|
||||
ModelLocationDownload(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
ModelFileDownload(rbx_asset::cloud::GetError),
|
||||
ParseUserID(core::num::ParseIntError),
|
||||
ParseModelVersion(core::num::ParseIntError),
|
||||
ModelFileDecode(ReadDomError),
|
||||
GetRootInstance(GetRootInstanceError),
|
||||
GetMapInfo(GetMapInfoError),
|
||||
ParseGameID(ParseGameIDError),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
@ -23,10 +27,10 @@ pub struct CreateRequest{
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct CreateResult{
|
||||
pub AssetOwner:u64,
|
||||
pub DisplayName:Option<String>,
|
||||
pub Creator:Option<String>,
|
||||
pub GameID:Option<GameID>,
|
||||
pub AssetOwner:i64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:i32,
|
||||
pub AssetVersion:u64,
|
||||
}
|
||||
impl crate::message_handler::MessageHandler{
|
||||
@ -37,36 +41,45 @@ impl crate::message_handler::MessageHandler{
|
||||
).await.map_err(Error::ModelInfoDownload)?;
|
||||
|
||||
// reject models created by a group
|
||||
let rbx_asset::cloud::Creator::userId(user_id)=info.creationContext.creator else{
|
||||
let rbx_asset::cloud::Creator::userId(user_id_string)=info.creationContext.creator else{
|
||||
return Err(Error::CreatorTypeMustBeUser);
|
||||
};
|
||||
|
||||
let asset_version=info.revisionId;
|
||||
// parse user string and model version string
|
||||
let user_id:u64=user_id_string.parse().map_err(Error::ParseUserID)?;
|
||||
let asset_version=info.revisionId.parse().map_err(Error::ParseModelVersion)?;
|
||||
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
// download the location of the map model
|
||||
let location=self.cloud_context.get_asset_version_location(rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:create_info.ModelID,
|
||||
version:asset_version,
|
||||
}).await.map_err(Error::Download)?;
|
||||
}).await.map_err(Error::ModelLocationDownload)?;
|
||||
|
||||
// if the location does not exist, you are not allowed to donwload it
|
||||
let Some(location)=location.location else{
|
||||
return Err(Error::NonFreeModel);
|
||||
};
|
||||
|
||||
// download the map model
|
||||
let model_data=self.cloud_context.get_asset(&location).await.map_err(Error::ModelFileDownload)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
// extract the root instance
|
||||
let model_instance=get_root_instance(&dom).map_err(Error::GetRootInstance)?;
|
||||
let dom=read_dom(std::io::Cursor::new(model_data)).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
// parse create fields out of asset
|
||||
let MapInfo{
|
||||
display_name,
|
||||
creator,
|
||||
game_id,
|
||||
}=get_mapinfo(&dom,model_instance);
|
||||
}=get_mapinfo(&dom).map_err(Error::GetMapInfo)?;
|
||||
|
||||
let game_id=game_id.map_err(Error::ParseGameID)?;
|
||||
|
||||
Ok(CreateResult{
|
||||
AssetOwner:user_id,
|
||||
DisplayName:display_name.ok().map(ToOwned::to_owned),
|
||||
Creator:creator.ok().map(ToOwned::to_owned),
|
||||
GameID:game_id.ok(),
|
||||
AssetOwner:user_id as i64,
|
||||
DisplayName:display_name.unwrap_or_default().to_owned(),
|
||||
Creator:creator.unwrap_or_default().to_owned(),
|
||||
GameID:game_id as i32,
|
||||
AssetVersion:asset_version,
|
||||
})
|
||||
}
|
||||
|
@ -24,15 +24,13 @@ impl crate::message_handler::MessageHandler{
|
||||
// call create on api
|
||||
self.api.create_mapfix(submissions_api::types::CreateMapfixRequest{
|
||||
OperationID:create_info.OperationID,
|
||||
AssetOwner:create_request.AssetOwner as i64,
|
||||
DisplayName:create_request.DisplayName.as_deref().unwrap_or_default(),
|
||||
Creator:create_request.Creator.as_deref().unwrap_or_default(),
|
||||
// not great TODO: make this great
|
||||
GameID:create_request.GameID.unwrap_or(crate::rbx_util::GameID::Bhop) as i32,
|
||||
AssetOwner:create_request.AssetOwner,
|
||||
DisplayName:create_request.DisplayName.as_str(),
|
||||
Creator:create_request.Creator.as_str(),
|
||||
GameID:create_request.GameID,
|
||||
AssetID:create_info.ModelID,
|
||||
AssetVersion:create_request.AssetVersion,
|
||||
TargetAssetID:create_info.TargetAssetID,
|
||||
Description:create_info.Description.as_str(),
|
||||
}).await.map_err(Error::ApiActionMapfixCreate)?;
|
||||
|
||||
Ok(())
|
||||
@ -43,12 +41,9 @@ impl crate::message_handler::MessageHandler{
|
||||
let create_result=self.create_mapfix_inner(create_info).await;
|
||||
|
||||
if let Err(e)=create_result{
|
||||
// log error
|
||||
println!("[create_mapfix] Error: {e}");
|
||||
|
||||
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
|
||||
OperationID:operation_id,
|
||||
StatusMessage:e.to_string(),
|
||||
StatusMessage:format!("{e}"),
|
||||
}).await?;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
use crate::nats_types::CreateSubmissionRequest;
|
||||
use crate::create::CreateRequest;
|
||||
use crate::rbx_util::GameID;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
@ -20,33 +19,15 @@ impl crate::message_handler::MessageHandler{
|
||||
let create_request=self.create_inner(CreateRequest{
|
||||
ModelID:create_info.ModelID,
|
||||
}).await.map_err(Error::Create)?;
|
||||
|
||||
// grab values from submission form, otherwise try to fill blanks from map data
|
||||
let display_name=if create_info.DisplayName.is_empty(){
|
||||
create_request.DisplayName.as_deref().unwrap_or_default()
|
||||
}else{
|
||||
create_info.DisplayName.as_str()
|
||||
};
|
||||
|
||||
let creator=if create_info.Creator.is_empty(){
|
||||
create_request.Creator.as_deref().unwrap_or_default()
|
||||
}else{
|
||||
create_info.Creator.as_str()
|
||||
};
|
||||
|
||||
let game_id=create_info.GameID.try_into().ok().or(create_request.GameID).unwrap_or(GameID::Bhop);
|
||||
|
||||
// call create on api
|
||||
self.api.create_submission(submissions_api::types::CreateSubmissionRequest{
|
||||
OperationID:create_info.OperationID,
|
||||
AssetOwner:create_request.AssetOwner as i64,
|
||||
DisplayName:display_name,
|
||||
Creator:creator,
|
||||
GameID:game_id as i32,
|
||||
AssetOwner:create_request.AssetOwner,
|
||||
DisplayName:create_request.DisplayName.as_str(),
|
||||
Creator:create_request.Creator.as_str(),
|
||||
GameID:create_request.GameID,
|
||||
AssetID:create_info.ModelID,
|
||||
AssetVersion:create_request.AssetVersion,
|
||||
Status:create_info.Status,
|
||||
Roles:create_info.Roles,
|
||||
}).await.map_err(Error::ApiActionSubmissionCreate)?;
|
||||
|
||||
Ok(())
|
||||
@ -57,12 +38,9 @@ impl crate::message_handler::MessageHandler{
|
||||
let create_result=self.create_submission_inner(create_info).await;
|
||||
|
||||
if let Err(e)=create_result{
|
||||
// log error
|
||||
println!("[create_submission] Error: {e}");
|
||||
|
||||
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
|
||||
OperationID:operation_id,
|
||||
StatusMessage:e.to_string(),
|
||||
StatusMessage:format!("{e}"),
|
||||
}).await?;
|
||||
}
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
ModelLocationDownload(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
ModelFileDownload(rbx_asset::cloud::GetError),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
pub async fn download_asset_version(cloud_context:&rbx_asset::cloud::Context,request:rbx_asset::cloud::GetAssetVersionRequest)->Result<rbx_asset::types::MaybeGzippedBytes,Error>{
|
||||
// download the location of the map model
|
||||
let location=cloud_context.get_asset_version_location(request).await.map_err(Error::ModelLocationDownload)?;
|
||||
|
||||
// if the location does not exist, you are not allowed to download it
|
||||
let location=location.location.ok_or(Error::NonFreeModel)?;
|
||||
|
||||
// download the map model
|
||||
let maybe_gzip=cloud_context.get_asset(&location).await.map_err(Error::ModelFileDownload)?;
|
||||
|
||||
Ok(maybe_gzip)
|
||||
}
|
@ -4,10 +4,6 @@ mod rbx_util;
|
||||
mod message_handler;
|
||||
mod nats_types;
|
||||
mod types;
|
||||
mod download;
|
||||
mod check;
|
||||
mod check_mapfix;
|
||||
mod check_submission;
|
||||
mod create;
|
||||
mod create_mapfix;
|
||||
mod create_submission;
|
||||
@ -43,7 +39,7 @@ async fn main()->Result<(),StartupError>{
|
||||
"None"=>None,
|
||||
_=>Some(s.parse().expect("ROBLOX_GROUP_ID int parse")),
|
||||
},
|
||||
Err(e)=>panic!("{e}: ROBLOX_GROUP_ID env required"),
|
||||
Err(e)=>Err(e).expect("ROBLOX_GROUP_ID env required"),
|
||||
};
|
||||
|
||||
// create / upload models through STRAFESNET_CI2 account
|
||||
|
@ -7,8 +7,6 @@ pub enum HandleMessageError{
|
||||
UnknownSubject(String),
|
||||
CreateMapfix(submissions_api::Error),
|
||||
CreateSubmission(submissions_api::Error),
|
||||
CheckMapfix(crate::check_mapfix::Error),
|
||||
CheckSubmission(crate::check_submission::Error),
|
||||
UploadMapfix(crate::upload_mapfix::Error),
|
||||
UploadSubmission(crate::upload_submission::Error),
|
||||
ValidateMapfix(crate::validate_mapfix::Error),
|
||||
@ -54,8 +52,6 @@ impl MessageHandler{
|
||||
match message.subject.as_str(){
|
||||
"maptest.mapfixes.create"=>self.create_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::CreateMapfix),
|
||||
"maptest.submissions.create"=>self.create_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::CreateSubmission),
|
||||
"maptest.mapfixes.check"=>self.check_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::CheckMapfix),
|
||||
"maptest.submissions.check"=>self.check_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::CheckSubmission),
|
||||
"maptest.mapfixes.upload"=>self.upload_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadMapfix),
|
||||
"maptest.submissions.upload"=>self.upload_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadSubmission),
|
||||
"maptest.mapfixes.validate"=>self.validate_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::ValidateMapfix),
|
||||
|
@ -10,12 +10,6 @@ pub struct CreateSubmissionRequest{
|
||||
// operation_id is passed back in the response message
|
||||
pub OperationID:i32,
|
||||
pub ModelID:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
// initial status is passed back on create
|
||||
pub Status:u32,
|
||||
pub Roles:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
@ -24,21 +18,6 @@ pub struct CreateMapfixRequest{
|
||||
pub OperationID:i32,
|
||||
pub ModelID:u64,
|
||||
pub TargetAssetID:u64,
|
||||
pub Description:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CheckSubmissionRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CheckMapfixRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
|
@ -5,7 +5,8 @@ pub enum ReadDomError{
|
||||
Binary(rbx_binary::DecodeError),
|
||||
Xml(rbx_xml::DecodeError),
|
||||
Read(std::io::Error),
|
||||
UnknownFormat(Vec<u8>),
|
||||
Seek(std::io::Error),
|
||||
UnknownFormat([u8;8]),
|
||||
}
|
||||
impl std::fmt::Display for ReadDomError{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
@ -14,22 +15,44 @@ impl std::fmt::Display for ReadDomError{
|
||||
}
|
||||
impl std::error::Error for ReadDomError{}
|
||||
|
||||
pub fn read_dom<R:std::io::Read>(input:R)->Result<rbx_dom_weak::WeakDom,ReadDomError>{
|
||||
let mut buf=std::io::BufReader::new(input);
|
||||
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadDomError::Read)?;
|
||||
match peek.get(0..8){
|
||||
Some(b"<roblox!")=>rbx_binary::from_reader(buf).map_err(ReadDomError::Binary),
|
||||
Some(b"<roblox ")=>rbx_xml::from_reader_default(buf).map_err(ReadDomError::Xml),
|
||||
_=>Err(ReadDomError::UnknownFormat(peek.to_owned())),
|
||||
pub fn read_dom<R:std::io::Read+std::io::Seek>(mut input:R)->Result<rbx_dom_weak::WeakDom,ReadDomError>{
|
||||
let mut first_8=[0u8;8];
|
||||
std::io::Read::read_exact(&mut input,&mut first_8).map_err(ReadDomError::Read)?;
|
||||
std::io::Seek::rewind(&mut input).map_err(ReadDomError::Seek)?;
|
||||
match &first_8[0..4]{
|
||||
b"<rob"=>{
|
||||
match &first_8[4..8]{
|
||||
b"lox!"=>rbx_binary::from_reader(input).map_err(ReadDomError::Binary),
|
||||
b"lox "=>rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()).map_err(ReadDomError::Xml),
|
||||
_=>Err(ReadDomError::UnknownFormat(first_8)),
|
||||
}
|
||||
},
|
||||
_=>Err(ReadDomError::UnknownFormat(first_8)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
|
||||
rbx_dom_weak::ustr(s)
|
||||
pub fn class_is_a(class:&str,superclass:&str)->bool{
|
||||
if class==superclass{
|
||||
return true
|
||||
}
|
||||
let class_descriptor=rbx_reflection_database::get().classes.get(class);
|
||||
if let Some(descriptor)=&class_descriptor{
|
||||
if let Some(class_super)=&descriptor.superclass{
|
||||
return class_is_a(&class_super,superclass)
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn find_first_child_name_and_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str,class:&str)->Option<&'a rbx_dom_weak::Instance>{
|
||||
instance.children().iter().filter_map(|&r|dom.get_by_ref(r)).find(|inst|inst.name==name&&inst.class==class)
|
||||
pub fn find_first_child_class<'a>(dom:&'a rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,name:&str,class:&str)->Option<&'a rbx_dom_weak::Instance>{
|
||||
for &referent in instance.children(){
|
||||
if let Some(c)=dom.get_by_ref(referent){
|
||||
if c.name==name&&class_is_a(c.class.as_str(),class) {
|
||||
return Some(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub enum GameID{
|
||||
@ -51,19 +74,7 @@ impl std::str::FromStr for GameID{
|
||||
if s.starts_with("flytrials_"){
|
||||
return Ok(GameID::FlyTrials);
|
||||
}
|
||||
Err(ParseGameIDError)
|
||||
}
|
||||
}
|
||||
pub struct GameIDError;
|
||||
impl TryFrom<u32> for GameID{
|
||||
type Error=GameIDError;
|
||||
fn try_from(value:u32)->Result<Self,Self::Error>{
|
||||
match value{
|
||||
1=>Ok(GameID::Bhop),
|
||||
2=>Ok(GameID::Surf),
|
||||
5=>Ok(GameID::FlyTrials),
|
||||
_=>Err(GameIDError)
|
||||
}
|
||||
return Err(ParseGameIDError);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,7 +84,6 @@ pub struct MapInfo<'a>{
|
||||
pub game_id:Result<GameID,ParseGameIDError>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StringValueError{
|
||||
ObjectNotFound,
|
||||
ValueNotSet,
|
||||
@ -82,7 +92,7 @@ pub enum StringValueError{
|
||||
|
||||
fn string_value(instance:Option<&rbx_dom_weak::Instance>)->Result<&str,StringValueError>{
|
||||
let instance=instance.ok_or(StringValueError::ObjectNotFound)?;
|
||||
let value=instance.properties.get(&static_ustr("Value")).ok_or(StringValueError::ValueNotSet)?;
|
||||
let value=instance.properties.get("Value").ok_or(StringValueError::ValueNotSet)?;
|
||||
match value{
|
||||
rbx_dom_weak::types::Variant::String(value)=>Ok(value),
|
||||
_=>Err(StringValueError::NonStringValue),
|
||||
@ -90,24 +100,20 @@ fn string_value(instance:Option<&rbx_dom_weak::Instance>)->Result<&str,StringVal
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GetRootInstanceError{
|
||||
pub enum GetMapInfoError{
|
||||
ModelFileRootMustHaveOneChild,
|
||||
ModelFileChildRefIsNil,
|
||||
}
|
||||
|
||||
pub fn get_root_instance(dom:&rbx_dom_weak::WeakDom)->Result<&rbx_dom_weak::Instance,GetRootInstanceError>{
|
||||
pub fn get_mapinfo(dom:&rbx_dom_weak::WeakDom)->Result<MapInfo,GetMapInfoError>{
|
||||
let &[map_ref]=dom.root().children()else{
|
||||
return Err(GetRootInstanceError::ModelFileRootMustHaveOneChild);
|
||||
return Err(GetMapInfoError::ModelFileRootMustHaveOneChild);
|
||||
};
|
||||
let model_instance=dom.get_by_ref(map_ref).ok_or(GetRootInstanceError::ModelFileChildRefIsNil)?;
|
||||
let model_instance=dom.get_by_ref(map_ref).ok_or(GetMapInfoError::ModelFileChildRefIsNil)?;
|
||||
|
||||
Ok(model_instance)
|
||||
}
|
||||
|
||||
pub fn get_mapinfo<'a>(dom:&'a rbx_dom_weak::WeakDom,model_instance:&rbx_dom_weak::Instance)->MapInfo<'a>{
|
||||
MapInfo{
|
||||
display_name:string_value(find_first_child_name_and_class(dom,model_instance,"DisplayName","StringValue")),
|
||||
creator:string_value(find_first_child_name_and_class(dom,model_instance,"Creator","StringValue")),
|
||||
Ok(MapInfo{
|
||||
display_name:string_value(find_first_child_class(dom,model_instance,"DisplayName","StringValue")),
|
||||
creator:string_value(find_first_child_class(dom,model_instance,"Creator","StringValue")),
|
||||
game_id:model_instance.name.parse(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::download::download_asset_version;
|
||||
use crate::nats_types::UploadMapfixRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Download(crate::download::Error),
|
||||
IO(std::io::Error),
|
||||
GetLocation(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
Get(rbx_asset::cloud::GetError),
|
||||
Json(serde_json::Error),
|
||||
Upload(rbx_asset::cookie::UploadError),
|
||||
ApiActionMapfixUploaded(submissions_api::Error),
|
||||
@ -19,14 +19,19 @@ impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn upload_mapfix(&self,upload_info:UploadMapfixRequest)->Result<(),Error>{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
// download the location of the map model
|
||||
let location=self.cloud_context.get_asset_version_location(rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:upload_info.ModelID,
|
||||
version:upload_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
}).await.map_err(Error::GetLocation)?;
|
||||
|
||||
// transparently handle gzipped models
|
||||
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
|
||||
// if the location does not exist, you are not allowed to donwload it
|
||||
let Some(location)=location.location else{
|
||||
return Err(Error::NonFreeModel);
|
||||
};
|
||||
|
||||
// download the map model
|
||||
let model_data=self.cloud_context.get_asset(&location).await.map_err(Error::Get)?;
|
||||
|
||||
// upload the map to the strafesnet group
|
||||
let _upload_response=self.cookie_context.upload(rbx_asset::cookie::UploadRequest{
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::download::download_asset_version;
|
||||
use crate::nats_types::UploadSubmissionRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Download(crate::download::Error),
|
||||
IO(std::io::Error),
|
||||
GetLocation(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
Get(rbx_asset::cloud::GetError),
|
||||
Json(serde_json::Error),
|
||||
Create(rbx_asset::cookie::CreateError),
|
||||
SystemTime(std::time::SystemTimeError),
|
||||
@ -20,14 +20,19 @@ impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn upload_submission(&self,upload_info:UploadSubmissionRequest)->Result<(),Error>{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
// download the location of the map model
|
||||
let location=self.cloud_context.get_asset_version_location(rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:upload_info.ModelID,
|
||||
version:upload_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
}).await.map_err(Error::GetLocation)?;
|
||||
|
||||
// transparently handle gzipped models
|
||||
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
|
||||
// if the location does not exist, you are not allowed to donwload it
|
||||
let Some(location)=location.location else{
|
||||
return Err(Error::NonFreeModel);
|
||||
};
|
||||
|
||||
// download the map model
|
||||
let model_data=self.cloud_context.get_asset(&location).await.map_err(Error::Get)?;
|
||||
|
||||
// upload the map to the strafesnet group
|
||||
let upload_response=self.cookie_context.create(rbx_asset::cookie::CreateRequest{
|
||||
|
@ -26,13 +26,10 @@ impl crate::message_handler::MessageHandler{
|
||||
).await.map_err(Error::ApiActionMapfixValidate)?;
|
||||
},
|
||||
Err(e)=>{
|
||||
// log error
|
||||
println!("[validate_mapfix] Error: {e}");
|
||||
|
||||
// update the mapfix model status to accepted
|
||||
self.api.action_mapfix_accepted(submissions_api::types::ActionMapfixAcceptedRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
StatusMessage:format!("{e}"),
|
||||
}).await.map_err(Error::ApiActionMapfixValidate)?;
|
||||
},
|
||||
}
|
||||
|
@ -26,13 +26,10 @@ impl crate::message_handler::MessageHandler{
|
||||
).await.map_err(Error::ApiActionSubmissionValidate)?;
|
||||
},
|
||||
Err(e)=>{
|
||||
// log error
|
||||
println!("[validate_submission] Error: {e}");
|
||||
|
||||
// update the submission model status to accepted
|
||||
self.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{
|
||||
SubmissionID:submission_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
StatusMessage:format!("{e}"),
|
||||
}).await.map_err(Error::ApiActionSubmissionValidate)?;
|
||||
},
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
use futures::TryStreamExt;
|
||||
use submissions_api::types::ResourceType;
|
||||
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{read_dom,static_ustr,ReadDomError};
|
||||
use crate::rbx_util::{class_is_a,read_dom,ReadDomError};
|
||||
use crate::types::ResourceID;
|
||||
|
||||
const SCRIPT_CONCURRENCY:usize=16;
|
||||
@ -21,7 +20,7 @@ struct NamePolicy{
|
||||
}
|
||||
|
||||
fn source_has_illegal_keywords(source:&str)->bool{
|
||||
source.contains("getfenv")||source.contains("require")
|
||||
source.find("getfenv").is_some()||source.find("require").is_some()
|
||||
}
|
||||
|
||||
fn hash_source(source:&str)->String{
|
||||
@ -37,13 +36,15 @@ pub enum Error{
|
||||
ScriptFlaggedIllegalKeyword(String),
|
||||
ScriptBlocked(Option<submissions_api::types::ScriptID>),
|
||||
ScriptNotYetReviewed(Option<submissions_api::types::ScriptID>),
|
||||
Download(crate::download::Error),
|
||||
ModelLocationDownload(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
ModelFileDownload(rbx_asset::cloud::GetError),
|
||||
ModelFileDecode(ReadDomError),
|
||||
ApiGetScriptPolicyFromHash(submissions_api::types::ScriptPolicySingleItemError),
|
||||
ApiGetScriptPolicyFromHash(submissions_api::types::SingleItemError),
|
||||
ApiGetScript(submissions_api::Error),
|
||||
ApiCreateScript(submissions_api::Error),
|
||||
ApiCreateScriptPolicy(submissions_api::Error),
|
||||
ApiGetScriptFromHash(submissions_api::types::ScriptSingleItemError),
|
||||
ApiGetScriptFromHash(submissions_api::types::SingleItemError),
|
||||
ApiUpdateMapfixModel(submissions_api::Error),
|
||||
ApiUpdateSubmissionModel(submissions_api::Error),
|
||||
ModelFileRootMustHaveOneChild,
|
||||
@ -90,26 +91,31 @@ impl From<crate::nats_types::ValidateSubmissionRequest> for ValidateRequest{
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),Error>{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
// download the location of the map model
|
||||
let location=self.cloud_context.get_asset_version_location(rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:validate_info.ModelID,
|
||||
version:validate_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
}).await.map_err(Error::ModelLocationDownload)?;
|
||||
|
||||
// if the location does not exist, you are not allowed to donwload it
|
||||
let Some(location)=location.location else{
|
||||
return Err(Error::NonFreeModel);
|
||||
};
|
||||
|
||||
// download the map model
|
||||
let model_data=self.cloud_context.get_asset(&location).await.map_err(Error::ModelFileDownload)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let mut dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
let mut dom=read_dom(std::io::Cursor::new(model_data)).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
/* VALIDATE MAP */
|
||||
|
||||
// stupid ustr thing
|
||||
let source_property=static_ustr("Source");
|
||||
|
||||
// collect unique scripts
|
||||
let script_refs=get_script_refs(&dom);
|
||||
let mut script_map=std::collections::HashMap::<String,NamePolicy>::new();
|
||||
for &script_ref in &script_refs{
|
||||
if let Some(script)=dom.get_by_ref(script_ref){
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get(&source_property){
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get("Source"){
|
||||
// check the source for illegal keywords
|
||||
if source_has_illegal_keywords(source){
|
||||
// immediately abort
|
||||
@ -182,7 +188,7 @@ impl crate::message_handler::MessageHandler{
|
||||
let mut modified=false;
|
||||
for &script_ref in &script_refs{
|
||||
if let Some(script)=dom.get_by_ref_mut(script_ref){
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut(&source_property){
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut("Source"){
|
||||
match script_map.get(source.as_str()).map(|p|&p.policy){
|
||||
Some(Policy::Blocked)=>{
|
||||
let hash=hash_source(source.as_str());
|
||||
@ -280,6 +286,17 @@ impl crate::message_handler::MessageHandler{
|
||||
}
|
||||
}
|
||||
|
||||
fn recursive_collect_superclass(objects:&mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance,superclass:&str){
|
||||
for &referent in instance.children(){
|
||||
if let Some(c)=dom.get_by_ref(referent){
|
||||
if class_is_a(c.class.as_str(),superclass){
|
||||
objects.push(c.referent());//copy ref
|
||||
}
|
||||
recursive_collect_superclass(objects,dom,c,superclass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_partial_path(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)->String{
|
||||
let mut names:Vec<_>=core::iter::successors(
|
||||
Some(instance),
|
||||
@ -294,11 +311,7 @@ fn get_partial_path(dom:&rbx_dom_weak::WeakDom,instance:&rbx_dom_weak::Instance)
|
||||
}
|
||||
|
||||
fn get_script_refs(dom:&rbx_dom_weak::WeakDom)->Vec<rbx_dom_weak::types::Ref>{
|
||||
let db=rbx_reflection_database::get();
|
||||
let superclass=&db.classes["LuaSourceContainer"];
|
||||
dom.descendants().filter_map(|inst|{
|
||||
let class=db.classes.get(inst.class.as_str())?;
|
||||
db.has_superclass(class,superclass)
|
||||
.then_some(inst.referent())
|
||||
}).collect()
|
||||
let mut scripts=std::vec::Vec::new();
|
||||
recursive_collect_superclass(&mut scripts,dom,dom.root(),"LuaSourceContainer");
|
||||
scripts
|
||||
}
|
||||
|
@ -13,19 +13,18 @@
|
||||
"@emotion/styled": "^11.14.0",
|
||||
"@mui/icons-material": "^6.1.10",
|
||||
"@mui/material": "^6.1.10",
|
||||
"date-fns": "^4.1.0",
|
||||
"next": "^15.1.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"sass": "^1.82.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"typescript": "^5.7.2",
|
||||
"@types/node": "^20.17.9",
|
||||
"@types/react": "^19.0.1",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"eslint": "^9.16.0",
|
||||
"eslint-config-next": "15.1.0",
|
||||
"typescript": "^5.7.2"
|
||||
"@eslint/eslintrc": "^3.2.0"
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before ![]() (image error) Size: 30 KiB |
Binary file not shown.
Before ![]() (image error) Size: 35 KiB |
@ -1,43 +0,0 @@
|
||||
import { Button, Container, Paper, Typography } from "@mui/material";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
|
||||
interface ErrorDisplayProps {
|
||||
title: string;
|
||||
message: string;
|
||||
buttonText?: string;
|
||||
onButtonClick?: () => void;
|
||||
}
|
||||
|
||||
export function ErrorDisplay({
|
||||
title,
|
||||
message,
|
||||
buttonText,
|
||||
onButtonClick
|
||||
}: ErrorDisplayProps) {
|
||||
return (
|
||||
<Webpage>
|
||||
<Container maxWidth="lg" sx={{ py: 6 }}>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
p: 4,
|
||||
textAlign: 'center',
|
||||
borderRadius: 2
|
||||
}}
|
||||
>
|
||||
<Typography variant="h5" gutterBottom>{title}</Typography>
|
||||
<Typography variant="body1">{message}</Typography>
|
||||
{buttonText && onButtonClick && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={onButtonClick}
|
||||
sx={{ mt: 3 }}
|
||||
>
|
||||
{buttonText}
|
||||
</Button>
|
||||
)}
|
||||
</Paper>
|
||||
</Container>
|
||||
</Webpage>
|
||||
);
|
||||
}
|
@ -1,151 +0,0 @@
|
||||
import {Box, IconButton, Typography} from "@mui/material";
|
||||
import {useEffect, useRef, useState} from "react";
|
||||
import Link from "next/link";
|
||||
import ArrowBackIosNewIcon from "@mui/icons-material/ArrowBackIosNew";
|
||||
import ArrowForwardIosIcon from "@mui/icons-material/ArrowForwardIos";
|
||||
import {SubmissionInfo} from "@/app/ts/Submission";
|
||||
import {MapfixInfo} from "@/app/ts/Mapfix";
|
||||
|
||||
// Type for the items in the carousel
|
||||
type CarouselItem = SubmissionInfo | MapfixInfo;
|
||||
|
||||
// Props for the Carousel component
|
||||
interface CarouselProps<T extends CarouselItem> {
|
||||
title: string;
|
||||
items: T[] | undefined;
|
||||
renderItem: (item: T) => React.ReactNode;
|
||||
viewAllLink: string;
|
||||
}
|
||||
|
||||
export function Carousel<T extends CarouselItem>({ title, items, renderItem, viewAllLink }: CarouselProps<T>) {
|
||||
const carouselRef = useRef<HTMLDivElement | null>(null);
|
||||
const [scrollPosition, setScrollPosition] = useState<number>(0);
|
||||
const [maxScroll, setMaxScroll] = useState<number>(0);
|
||||
|
||||
const SCROLL_AMOUNT = 300;
|
||||
|
||||
useEffect(() => {
|
||||
if (carouselRef.current) {
|
||||
const scrollWidth = carouselRef.current.scrollWidth;
|
||||
const clientWidth = carouselRef.current.clientWidth;
|
||||
setMaxScroll(scrollWidth - clientWidth);
|
||||
}
|
||||
}, [items]);
|
||||
|
||||
const scroll = (direction: 'left' | 'right'): void => {
|
||||
if (carouselRef.current) {
|
||||
const scrollAmount = direction === 'left' ? -SCROLL_AMOUNT : SCROLL_AMOUNT;
|
||||
|
||||
carouselRef.current.scrollBy({
|
||||
left: scrollAmount,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
if (carouselRef.current) {
|
||||
setScrollPosition(carouselRef.current.scrollLeft);
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleScroll = () => {
|
||||
if (carouselRef.current) {
|
||||
setScrollPosition(carouselRef.current.scrollLeft);
|
||||
}
|
||||
};
|
||||
|
||||
const ref = carouselRef.current;
|
||||
if (ref) {
|
||||
ref.addEventListener('scroll', handleScroll);
|
||||
return () => ref.removeEventListener('scroll', handleScroll);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Box mb={6}>
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
|
||||
<Typography variant="h4" component="h2" fontWeight="bold">
|
||||
{title}
|
||||
</Typography>
|
||||
<Link href={viewAllLink} style={{textDecoration: 'none'}}>
|
||||
<Typography component="span" color="primary">
|
||||
View All →
|
||||
</Typography>
|
||||
</Link>
|
||||
</Box>
|
||||
|
||||
<Box position="relative">
|
||||
<IconButton
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
left: -20,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
zIndex: 2,
|
||||
backgroundColor: 'background.paper',
|
||||
boxShadow: 2,
|
||||
'&:hover': {
|
||||
backgroundColor: 'action.hover',
|
||||
},
|
||||
visibility: scrollPosition <= 5 ? 'hidden' : 'visible',
|
||||
}}
|
||||
onClick={() => scroll('left')}
|
||||
>
|
||||
<ArrowBackIosNewIcon />
|
||||
</IconButton>
|
||||
|
||||
<Box
|
||||
ref={carouselRef}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
overflowX: 'auto',
|
||||
scrollbarWidth: 'none',
|
||||
msOverflowStyle: 'none',
|
||||
'&::-webkit-scrollbar': {
|
||||
display: 'none',
|
||||
},
|
||||
gap: '16px', // Fixed 16px gap - using string with px unit to ensure it's absolute
|
||||
padding: '8px 4px',
|
||||
}}
|
||||
>
|
||||
{items?.map((item, index) => (
|
||||
<Box
|
||||
key={index}
|
||||
sx={{
|
||||
flex: '0 0 auto',
|
||||
width: {
|
||||
xs: '260px', // Fixed width at different breakpoints
|
||||
sm: '280px',
|
||||
md: '300px'
|
||||
}
|
||||
}}
|
||||
>
|
||||
{renderItem(item)}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
|
||||
<IconButton
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
right: -20,
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
zIndex: 2,
|
||||
backgroundColor: 'background.paper',
|
||||
boxShadow: 2,
|
||||
'&:hover': {
|
||||
backgroundColor: 'action.hover',
|
||||
},
|
||||
visibility: scrollPosition >= maxScroll - 5 ? 'hidden' : 'visible',
|
||||
}}
|
||||
onClick={() => scroll('right')}
|
||||
>
|
||||
<ArrowForwardIosIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Avatar,
|
||||
Typography,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import PersonIcon from '@mui/icons-material/Person';
|
||||
import { formatDistanceToNow, format } from "date-fns";
|
||||
import { AuditEvent, decodeAuditEvent as auditEventMessage } from "@/app/ts/AuditEvent";
|
||||
|
||||
interface AuditEventItemProps {
|
||||
event: AuditEvent;
|
||||
validatorUser: number;
|
||||
}
|
||||
|
||||
export default function AuditEventItem({ event, validatorUser }: AuditEventItemProps) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<Avatar
|
||||
src={event.User === validatorUser ? undefined : `/thumbnails/user/${event.User}`}
|
||||
>
|
||||
<PersonIcon />
|
||||
</Avatar>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Typography variant="subtitle2">
|
||||
{event.User === validatorUser ? "Validator" : event.Username || "Unknown"}
|
||||
</Typography>
|
||||
<DateDisplay date={event.Date} />
|
||||
</Box>
|
||||
<Typography variant="body2">{auditEventMessage(event)}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface DateDisplayProps {
|
||||
date: number;
|
||||
}
|
||||
|
||||
function DateDisplay({ date }: DateDisplayProps) {
|
||||
return (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
<Tooltip title={format(new Date(date * 1000), 'PPpp')}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{formatDistanceToNow(new Date(date * 1000), { addSuffix: true })}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
);
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Stack,
|
||||
} from "@mui/material";
|
||||
import { AuditEvent, AuditEventType } from "@/app/ts/AuditEvent";
|
||||
import AuditEventItem from './AuditEventItem';
|
||||
|
||||
interface AuditEventsTabPanelProps {
|
||||
activeTab: number;
|
||||
auditEvents: AuditEvent[];
|
||||
validatorUser: number;
|
||||
}
|
||||
|
||||
export default function AuditEventsTabPanel({
|
||||
activeTab,
|
||||
auditEvents,
|
||||
validatorUser
|
||||
}: AuditEventsTabPanelProps) {
|
||||
const filteredEvents = auditEvents.filter(
|
||||
event => event.EventType !== AuditEventType.Comment
|
||||
);
|
||||
|
||||
return (
|
||||
<Box role="tabpanel" hidden={activeTab !== 1}>
|
||||
{activeTab === 1 && (
|
||||
<Stack spacing={2}>
|
||||
{filteredEvents.map((event, index) => (
|
||||
<AuditEventItem
|
||||
key={index}
|
||||
event={event}
|
||||
validatorUser={validatorUser}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Avatar,
|
||||
Typography,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import PersonIcon from '@mui/icons-material/Person';
|
||||
import { formatDistanceToNow, format } from "date-fns";
|
||||
import { AuditEvent, decodeAuditEvent } from "@/app/ts/AuditEvent";
|
||||
|
||||
interface CommentItemProps {
|
||||
event: AuditEvent;
|
||||
validatorUser: number;
|
||||
}
|
||||
|
||||
export default function CommentItem({ event, validatorUser }: CommentItemProps) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 2 }}>
|
||||
<Avatar
|
||||
src={event.User === validatorUser ? undefined : `/thumbnails/user/${event.User}`}
|
||||
>
|
||||
<PersonIcon />
|
||||
</Avatar>
|
||||
<Box sx={{ flexGrow: 1 }}>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Typography variant="subtitle2">
|
||||
{event.User === validatorUser ? "Validator" : event.Username || "Unknown"}
|
||||
</Typography>
|
||||
<DateDisplay date={event.Date} />
|
||||
</Box>
|
||||
<Typography variant="body2">{decodeAuditEvent(event)}</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface DateDisplayProps {
|
||||
date: number;
|
||||
}
|
||||
|
||||
function DateDisplay({ date }: DateDisplayProps) {
|
||||
return (
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
<Tooltip title={format(new Date(date * 1000), 'PPpp')}>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{formatDistanceToNow(new Date(date * 1000), { addSuffix: true })}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
</Typography>
|
||||
);
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
import React, {useState} from 'react';
|
||||
import {
|
||||
Paper,
|
||||
Box,
|
||||
Tabs,
|
||||
Tab,
|
||||
} from "@mui/material";
|
||||
import CommentsTabPanel from './CommentsTabPanel';
|
||||
import AuditEventsTabPanel from './AuditEventsTabPanel';
|
||||
import { AuditEvent } from "@/app/ts/AuditEvent";
|
||||
|
||||
interface CommentsAndAuditSectionProps {
|
||||
auditEvents: AuditEvent[];
|
||||
newComment: string;
|
||||
setNewComment: (comment: string) => void;
|
||||
handleCommentSubmit: () => void;
|
||||
validatorUser: number;
|
||||
userId: number | null;
|
||||
}
|
||||
|
||||
export default function CommentsAndAuditSection({
|
||||
auditEvents,
|
||||
newComment,
|
||||
setNewComment,
|
||||
handleCommentSubmit,
|
||||
validatorUser,
|
||||
userId,
|
||||
}: CommentsAndAuditSectionProps) {
|
||||
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const handleTabChange = (event: React.SyntheticEvent, newValue: number) => {
|
||||
setActiveTab(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<Paper sx={{ p: 3, mt: 3 }}>
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 2 }}>
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onChange={handleTabChange}
|
||||
aria-label="comments and audit tabs"
|
||||
>
|
||||
<Tab label="Comments" />
|
||||
<Tab label="Audit Events" />
|
||||
</Tabs>
|
||||
</Box>
|
||||
|
||||
<CommentsTabPanel
|
||||
activeTab={activeTab}
|
||||
auditEvents={auditEvents}
|
||||
validatorUser={validatorUser}
|
||||
newComment={newComment}
|
||||
setNewComment={setNewComment}
|
||||
handleCommentSubmit={handleCommentSubmit}
|
||||
userId={userId}
|
||||
/>
|
||||
|
||||
<AuditEventsTabPanel
|
||||
activeTab={activeTab}
|
||||
auditEvents={auditEvents}
|
||||
validatorUser={validatorUser}
|
||||
/>
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Stack,
|
||||
Avatar,
|
||||
TextField,
|
||||
IconButton
|
||||
} from "@mui/material";
|
||||
import SendIcon from '@mui/icons-material/Send';
|
||||
import { AuditEvent, AuditEventType } from "@/app/ts/AuditEvent";
|
||||
import CommentItem from './CommentItem';
|
||||
|
||||
interface CommentsTabPanelProps {
|
||||
activeTab: number;
|
||||
auditEvents: AuditEvent[];
|
||||
validatorUser: number;
|
||||
newComment: string;
|
||||
setNewComment: (comment: string) => void;
|
||||
handleCommentSubmit: () => void;
|
||||
userId: number | null;
|
||||
}
|
||||
|
||||
export default function CommentsTabPanel({
|
||||
activeTab,
|
||||
auditEvents,
|
||||
validatorUser,
|
||||
newComment,
|
||||
setNewComment,
|
||||
handleCommentSubmit,
|
||||
userId
|
||||
}: CommentsTabPanelProps) {
|
||||
const commentEvents = auditEvents.filter(
|
||||
event => event.EventType === AuditEventType.Comment
|
||||
);
|
||||
|
||||
return (
|
||||
<Box role="tabpanel" hidden={activeTab !== 0}>
|
||||
{activeTab === 0 && (
|
||||
<>
|
||||
<Stack spacing={2} sx={{ mb: 3 }}>
|
||||
{commentEvents.map((event, index) => (
|
||||
<CommentItem
|
||||
key={index}
|
||||
event={event}
|
||||
validatorUser={validatorUser}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
|
||||
<CommentInput
|
||||
newComment={newComment}
|
||||
setNewComment={setNewComment}
|
||||
handleCommentSubmit={handleCommentSubmit}
|
||||
userId={userId}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
interface CommentInputProps {
|
||||
newComment: string;
|
||||
setNewComment: (comment: string) => void;
|
||||
handleCommentSubmit: () => void;
|
||||
userId: number | null;
|
||||
}
|
||||
|
||||
function CommentInput({ newComment, setNewComment, handleCommentSubmit, userId }: CommentInputProps) {
|
||||
return (
|
||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'flex-start' }}>
|
||||
<Avatar
|
||||
src={`/thumbnails/user/${userId}`}
|
||||
/>
|
||||
<TextField
|
||||
fullWidth
|
||||
multiline
|
||||
rows={2}
|
||||
placeholder="Add a comment..."
|
||||
value={newComment}
|
||||
onChange={(e) => setNewComment(e.target.value)}
|
||||
/>
|
||||
<IconButton
|
||||
color="primary"
|
||||
onClick={handleCommentSubmit}
|
||||
disabled={!newComment.trim()}
|
||||
>
|
||||
<SendIcon />
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
}
|
@ -1,245 +1,30 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import Image from "next/image";
|
||||
import { UserInfo } from "@/app/ts/User";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import AppBar from "@mui/material/AppBar";
|
||||
import Toolbar from "@mui/material/Toolbar";
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import Menu from "@mui/material/Menu";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import MenuIcon from "@mui/icons-material/Menu";
|
||||
import Drawer from "@mui/material/Drawer";
|
||||
import List from "@mui/material/List";
|
||||
import ListItem from "@mui/material/ListItem";
|
||||
import ListItemButton from "@mui/material/ListItemButton";
|
||||
import ListItemText from "@mui/material/ListItemText";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import "./styles/header.scss"
|
||||
|
||||
interface HeaderButton {
|
||||
name: string;
|
||||
href: string;
|
||||
name: string,
|
||||
href: string
|
||||
}
|
||||
|
||||
const navItems: HeaderButton[] = [
|
||||
{ name: "Submissions", href: "/submissions" },
|
||||
{ name: "Mapfixes", href: "/mapfixes" },
|
||||
{ name: "Maps", href: "/maps" },
|
||||
];
|
||||
|
||||
function HeaderButton(header: HeaderButton) {
|
||||
return (
|
||||
<Button color="inherit" component={Link} href={header.href}>
|
||||
{header.name}
|
||||
</Button>
|
||||
);
|
||||
<Link href={header.href}>
|
||||
<button>{header.name}</button>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
const theme = useTheme();
|
||||
const isMobile = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
|
||||
const handleLoginClick = () => {
|
||||
window.location.href =
|
||||
"/auth/oauth2/login?redirect=" + window.location.href;
|
||||
};
|
||||
|
||||
const [valid, setValid] = useState<boolean>(false);
|
||||
const [user, setUser] = useState<UserInfo | null>(null);
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
|
||||
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleMenuClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const handleDrawerToggle = () => {
|
||||
setMobileOpen(!mobileOpen);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function getLoginInfo() {
|
||||
try {
|
||||
const response = await fetch("/api/session/user");
|
||||
|
||||
if (!response.ok) {
|
||||
setValid(false);
|
||||
setUser(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const userData = await response.json();
|
||||
const isLoggedIn = userData && 'UserID' in userData;
|
||||
|
||||
setValid(isLoggedIn);
|
||||
setUser(isLoggedIn ? userData : null);
|
||||
} catch (error) {
|
||||
console.error("Error fetching user data:", error);
|
||||
setValid(false);
|
||||
setUser(null);
|
||||
}
|
||||
}
|
||||
|
||||
getLoginInfo();
|
||||
}, []);
|
||||
|
||||
// Mobile navigation drawer content
|
||||
const drawer = (
|
||||
<Box onClick={handleDrawerToggle} sx={{ textAlign: 'center' }}>
|
||||
<List>
|
||||
{navItems.map((item) => (
|
||||
<ListItem key={item.name} disablePadding>
|
||||
<ListItemButton component={Link} href={item.href} sx={{ textAlign: 'center' }}>
|
||||
<ListItemText primary={item.name} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
))}
|
||||
{valid && user && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton component={Link} href="/submit" sx={{ textAlign: 'center' }}>
|
||||
<ListItemText primary="Submit Map" sx={{ color: 'success.main' }} />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
{!valid && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton onClick={handleLoginClick} sx={{ textAlign: 'center' }}>
|
||||
<ListItemText primary="Login" />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
{valid && user && (
|
||||
<ListItem disablePadding>
|
||||
<ListItemButton component={Link} href="/auth" sx={{ textAlign: 'center' }}>
|
||||
<ListItemText primary="Manage Account" />
|
||||
</ListItemButton>
|
||||
</ListItem>
|
||||
)}
|
||||
</List>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<AppBar position="static">
|
||||
<Toolbar>
|
||||
{isMobile && (
|
||||
<IconButton
|
||||
color="inherit"
|
||||
aria-label="open drawer"
|
||||
edge="start"
|
||||
onClick={handleDrawerToggle}
|
||||
sx={{ mr: 2 }}
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
)}
|
||||
|
||||
{/* Desktop navigation */}
|
||||
{!isMobile && (
|
||||
<Box display="flex" flexGrow={1} gap={2}>
|
||||
{navItems.map((item) => (
|
||||
<HeaderButton key={item.name} name={item.name} href={item.href} />
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Spacer for mobile view */}
|
||||
{isMobile && <Box sx={{ flexGrow: 1 }} />}
|
||||
|
||||
{/* Right side of nav */}
|
||||
<Box display="flex" gap={2}>
|
||||
{!isMobile && valid && user && (
|
||||
<Button variant="outlined" color="success" component={Link} href="/submit">
|
||||
Submit Map
|
||||
</Button>
|
||||
)}
|
||||
{!isMobile && valid && user ? (
|
||||
<Box display="flex" alignItems="center">
|
||||
<Button
|
||||
onClick={handleMenuOpen}
|
||||
color="inherit"
|
||||
size="small"
|
||||
style={{ textTransform: "none" }}
|
||||
>
|
||||
<Image
|
||||
className="avatar"
|
||||
width={28}
|
||||
height={28}
|
||||
priority={true}
|
||||
src={user.AvatarURL}
|
||||
alt={user.Username}
|
||||
style={{ marginRight: 8 }}
|
||||
/>
|
||||
<Typography variant="body1">{user.Username}</Typography>
|
||||
</Button>
|
||||
<Menu
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={handleMenuClose}
|
||||
anchorOrigin={{
|
||||
vertical: "bottom",
|
||||
horizontal: "left",
|
||||
}}
|
||||
transformOrigin={{
|
||||
vertical: "top",
|
||||
horizontal: "left",
|
||||
}}
|
||||
>
|
||||
<MenuItem component={Link} href="/auth">
|
||||
Manage
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Box>
|
||||
) : !isMobile && (
|
||||
<Button color="inherit" onClick={handleLoginClick}>
|
||||
Login
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{/* In mobile view, display just the avatar if logged in */}
|
||||
{isMobile && valid && user && (
|
||||
<IconButton
|
||||
onClick={handleMenuOpen}
|
||||
color="inherit"
|
||||
size="small"
|
||||
>
|
||||
<Image
|
||||
className="avatar"
|
||||
width={28}
|
||||
height={28}
|
||||
priority={true}
|
||||
src={user.AvatarURL}
|
||||
alt={user.Username}
|
||||
/>
|
||||
</IconButton>
|
||||
)}
|
||||
</Box>
|
||||
</Toolbar>
|
||||
|
||||
{/* Mobile drawer */}
|
||||
<Drawer
|
||||
variant="temporary"
|
||||
open={mobileOpen}
|
||||
onClose={handleDrawerToggle}
|
||||
ModalProps={{
|
||||
keepMounted: true, // Better open performance on mobile
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiDrawer-paper': { boxSizing: 'border-box', width: 240 },
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
</Drawer>
|
||||
</AppBar>
|
||||
);
|
||||
<header className="header-bar">
|
||||
<nav className="left">
|
||||
<HeaderButton name="Submissions" href="/submissions"/>
|
||||
<HeaderButton name="Mapfixes" href="/mapfixes"/>
|
||||
<HeaderButton name="Maps" href="/maps"/>
|
||||
</nav>
|
||||
<nav className="right">
|
||||
<HeaderButton name="Submit" href="/submit"/>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
@ -1,186 +1,71 @@
|
||||
import React from "react";
|
||||
import {Avatar, Box, Card, CardActionArea, CardContent, CardMedia, Divider, Grid, Typography} from "@mui/material";
|
||||
import {Explore, Person2} from "@mui/icons-material";
|
||||
import {StatusChip} from "@/app/_components/statusChip";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Rating } from "@mui/material";
|
||||
|
||||
interface MapCardProps {
|
||||
interface SubmissionCardProps {
|
||||
displayName: string;
|
||||
assetId: number;
|
||||
authorId: number;
|
||||
author: string;
|
||||
rating: number;
|
||||
id: number;
|
||||
statusID: number;
|
||||
gameID: number;
|
||||
created: number;
|
||||
type: 'mapfix' | 'submission';
|
||||
}
|
||||
|
||||
const CARD_WIDTH = 270;
|
||||
|
||||
export function MapCard(props: MapCardProps) {
|
||||
export function SubmissionCard(props: SubmissionCardProps) {
|
||||
return (
|
||||
<Grid item xs={12} sm={6} md={3} key={props.assetId}>
|
||||
<Box sx={{
|
||||
width: CARD_WIDTH,
|
||||
mx: 'auto', // Center the card in its grid cell
|
||||
}}>
|
||||
<Card sx={{
|
||||
width: CARD_WIDTH,
|
||||
height: 340, // Fixed height for all cards
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
}}>
|
||||
<CardActionArea
|
||||
sx={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'stretch'
|
||||
}}
|
||||
href={`/${props.type === 'submission' ? 'submissions' : 'mapfixes'}/${props.id}`}>
|
||||
<Box sx={{ position: 'relative' }}>
|
||||
<CardMedia
|
||||
component="img"
|
||||
image={`/thumbnails/asset/${props.assetId}`}
|
||||
alt={props.displayName}
|
||||
sx={{
|
||||
height: 160, // Fixed height for all images
|
||||
objectFit: 'cover',
|
||||
}}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: 12,
|
||||
right: 12,
|
||||
}}
|
||||
>
|
||||
<StatusChip status={props.statusID}/>
|
||||
</Box>
|
||||
</Box>
|
||||
<CardContent sx={{
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
p: 2,
|
||||
width: '100%',
|
||||
}}>
|
||||
<Box>
|
||||
<Typography
|
||||
variant="subtitle1"
|
||||
component="div"
|
||||
sx={{
|
||||
mb: 1,
|
||||
fontWeight: 600,
|
||||
color: '#fff',
|
||||
lineHeight: '1.3',
|
||||
// Allow text to wrap
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 2,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
}}
|
||||
>
|
||||
{props.displayName}
|
||||
</Typography>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
mb: 1.5,
|
||||
}}>
|
||||
<Explore sx={{
|
||||
mr: 0.75,
|
||||
mt: 0.25,
|
||||
color: 'text.secondary',
|
||||
fontSize: '0.9rem',
|
||||
flexShrink: 0,
|
||||
}} />
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
// Allow text to wrap
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 2,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
lineHeight: '1.2',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{props.gameID === 1 ? 'Bhop' : props.gameID === 2 ? 'Surf' : props.gameID === 5 ? 'Fly Trials' : props.gameID === 4 ? 'Deathrun' : 'Unknown'}
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
mb: 1.5,
|
||||
}}>
|
||||
<Person2 sx={{
|
||||
mr: 0.75,
|
||||
mt: 0.25,
|
||||
color: 'text.secondary',
|
||||
fontSize: '0.9rem',
|
||||
flexShrink: 0,
|
||||
}} />
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
fontWeight: 500,
|
||||
// Allow text to wrap
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: '-webkit-box',
|
||||
WebkitLineClamp: 2,
|
||||
WebkitBoxOrient: 'vertical',
|
||||
lineHeight: '1.2',
|
||||
wordBreak: 'break-word',
|
||||
}}
|
||||
>
|
||||
{props.author}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Divider sx={{ my: 1.5 }} />
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Avatar
|
||||
src={`/thumbnails/user/${props.authorId}`}
|
||||
alt={props.author}
|
||||
sx={{
|
||||
width: 24,
|
||||
height: 24,
|
||||
border: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
variant="caption"
|
||||
sx={{
|
||||
ml: 1,
|
||||
color: 'text.secondary',
|
||||
fontWeight: 500,
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap',
|
||||
}}
|
||||
>
|
||||
{/*In the future author should be the username of the submitter not the info from the map*/}
|
||||
{props.author} - {new Date(props.created * 1000).toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
})}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
</CardContent>
|
||||
</CardActionArea>
|
||||
</Card>
|
||||
</Box>
|
||||
</Grid>
|
||||
)
|
||||
<Link href={`/submissions/${props.id}`}>
|
||||
<div className="submissionCard">
|
||||
<div className="content">
|
||||
<div className="map-image">
|
||||
{/* TODO: Grab image of model */}
|
||||
<Image width={230} height={230} layout="fixed" priority={true} src={`/thumbnails/asset/${props.assetId}`} alt={props.displayName} />
|
||||
</div>
|
||||
<div className="details">
|
||||
<div className="header">
|
||||
<span className="displayName">{props.displayName}</span>
|
||||
<div className="rating">
|
||||
<Rating value={props.rating} readOnly size="small" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer">
|
||||
<div className="author">
|
||||
<Image className="avatar" width={28} height={28} priority={true} src={`/thumbnails/user/${props.authorId}`} alt={props.author}/>
|
||||
<span>{props.author}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export function MapfixCard(props: SubmissionCardProps) {
|
||||
return (
|
||||
<Link href={`/mapfixes/${props.id}`}>
|
||||
<div className="MapfixCard">
|
||||
<div className="content">
|
||||
<div className="map-image">
|
||||
{/* TODO: Grab image of model */}
|
||||
<Image width={230} height={230} layout="fixed" priority={true} src={`/thumbnails/asset/${props.assetId}`} alt={props.displayName} />
|
||||
</div>
|
||||
<div className="details">
|
||||
<div className="header">
|
||||
<span className="displayName">{props.displayName}</span>
|
||||
<div className="rating">
|
||||
<Rating value={props.rating} readOnly size="small" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer">
|
||||
<div className="author">
|
||||
<Image className="avatar" width={28} height={28} priority={true} src={`/thumbnails/user/${props.authorId}`} alt={props.author}/>
|
||||
<span>{props.author}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
import { Typography, Box, IconButton, Tooltip } from "@mui/material";
|
||||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
|
||||
interface CopyableFieldProps {
|
||||
label: string;
|
||||
value: string | number | null | undefined;
|
||||
onCopy: (value: string) => void;
|
||||
placeholderText?: string;
|
||||
}
|
||||
|
||||
export const CopyableField = ({
|
||||
label,
|
||||
value,
|
||||
onCopy,
|
||||
placeholderText = "Not assigned"
|
||||
}: CopyableFieldProps) => {
|
||||
const displayValue = value?.toString() || placeholderText;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="body2" color="text.secondary">{label}</Typography>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Typography variant="body1">{displayValue}</Typography>
|
||||
{value && (
|
||||
<Tooltip title="Copy ID">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={() => onCopy(value.toString())}
|
||||
sx={{ ml: 1 }}
|
||||
>
|
||||
<ContentCopyIcon fontSize="small" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,174 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, Stack } from '@mui/material';
|
||||
import {MapfixInfo } from "@/app/ts/Mapfix";
|
||||
import {hasRole, Roles, RolesConstants} from "@/app/ts/Roles";
|
||||
import {SubmissionInfo, SubmissionStatus} from "@/app/ts/Submission";
|
||||
|
||||
interface ReviewAction {
|
||||
name: string,
|
||||
action: string,
|
||||
}
|
||||
|
||||
interface ReviewButtonsProps {
|
||||
onClick: (action: string, id: number) => void;
|
||||
item: (SubmissionInfo | MapfixInfo);
|
||||
userId: number | null;
|
||||
roles: Roles;
|
||||
type: "submission" | "mapfix";
|
||||
}
|
||||
|
||||
const ReviewActions = {
|
||||
Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
|
||||
BypassSubmit: {name:"Bypass Submit", action:"bypass-submit"} as ReviewAction,
|
||||
ResetSubmitting: {name:"Reset Submitting",action:"reset-submitting"} as ReviewAction,
|
||||
Revoke: {name:"Revoke",action:"revoke"} as ReviewAction,
|
||||
Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction,
|
||||
Reject: {name:"Reject",action:"reject"} as ReviewAction,
|
||||
Validate: {name:"Validate",action:"retry-validate"} as ReviewAction,
|
||||
ResetValidating: {name:"Reset Validating",action:"reset-validating"} as ReviewAction,
|
||||
RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction,
|
||||
Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction,
|
||||
ResetUploading: {name:"Reset Uploading",action:"reset-uploading"} as ReviewAction,
|
||||
}
|
||||
|
||||
const ReviewButtons: React.FC<ReviewButtonsProps> = ({
|
||||
onClick,
|
||||
item,
|
||||
userId,
|
||||
roles,
|
||||
type,
|
||||
}) => {
|
||||
const getVisibleButtons = () => {
|
||||
if (!item || userId === null) return [];
|
||||
|
||||
// Define a type for the button
|
||||
type ReviewButton = {
|
||||
action: ReviewAction;
|
||||
color: "primary" | "error" | "success" | "info" | "warning";
|
||||
};
|
||||
|
||||
const buttons: ReviewButton[] = [];
|
||||
const is_submitter = userId === item.Submitter;
|
||||
const status = item.StatusID;
|
||||
|
||||
// Helper function to check status regardless of which enum type it is
|
||||
const statusMatches = (statusValues: number[]) => {
|
||||
return statusValues.includes(status);
|
||||
};
|
||||
|
||||
// Create status constants that work with both types
|
||||
const Status = {
|
||||
UnderConstruction: SubmissionStatus.UnderConstruction,
|
||||
ChangesRequested: SubmissionStatus.ChangesRequested,
|
||||
Submitting: SubmissionStatus.Submitting,
|
||||
Submitted: SubmissionStatus.Submitted,
|
||||
AcceptedUnvalidated: SubmissionStatus.AcceptedUnvalidated,
|
||||
Validating: SubmissionStatus.Validating,
|
||||
Validated: SubmissionStatus.Validated,
|
||||
Uploading: SubmissionStatus.Uploading,
|
||||
Uploaded: SubmissionStatus.Uploaded,
|
||||
Rejected: SubmissionStatus.Rejected,
|
||||
Release: SubmissionStatus.Released
|
||||
};
|
||||
|
||||
const reviewRole = type === "submission" ? RolesConstants.SubmissionReview : RolesConstants.MapfixReview;
|
||||
const uploadRole = type === "submission" ? RolesConstants.SubmissionUpload : RolesConstants.MapfixUpload;
|
||||
|
||||
if (is_submitter) {
|
||||
if (statusMatches([Status.UnderConstruction, Status.ChangesRequested])) {
|
||||
buttons.push({
|
||||
action: ReviewActions.Submit,
|
||||
color: "primary"
|
||||
});
|
||||
}
|
||||
|
||||
if (statusMatches([Status.Submitted, Status.ChangesRequested])) {
|
||||
buttons.push({
|
||||
action: ReviewActions.Revoke,
|
||||
color: "error"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons for review role
|
||||
if (hasRole(roles, reviewRole)) {
|
||||
if (status === Status.Submitted && !is_submitter) {
|
||||
buttons.push(
|
||||
{
|
||||
action: ReviewActions.Accept,
|
||||
color: "success"
|
||||
},
|
||||
{
|
||||
action: ReviewActions.Reject,
|
||||
color: "error"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (status === Status.AcceptedUnvalidated) {
|
||||
buttons.push({
|
||||
action: ReviewActions.Validate,
|
||||
color: "info"
|
||||
});
|
||||
}
|
||||
|
||||
if (status === Status.Validating) {
|
||||
buttons.push({
|
||||
action: ReviewActions.ResetValidating,
|
||||
color: "warning"
|
||||
});
|
||||
}
|
||||
|
||||
if (statusMatches([Status.Validated, Status.AcceptedUnvalidated, Status.Submitted]) && !is_submitter) {
|
||||
buttons.push({
|
||||
action: ReviewActions.RequestChanges,
|
||||
color: "warning"
|
||||
});
|
||||
}
|
||||
|
||||
if (status === Status.ChangesRequested) {
|
||||
buttons.push({
|
||||
action: ReviewActions.BypassSubmit,
|
||||
color: "warning"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Buttons for upload role
|
||||
if (hasRole(roles, uploadRole)) {
|
||||
if (status === Status.Validated) {
|
||||
buttons.push({
|
||||
action: ReviewActions.Upload,
|
||||
color: "success"
|
||||
});
|
||||
}
|
||||
|
||||
if (status === Status.Uploading) {
|
||||
buttons.push({
|
||||
action: ReviewActions.ResetUploading,
|
||||
color: "warning"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return buttons;
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack spacing={2} sx={{ mb: 3 }}>
|
||||
{getVisibleButtons().map((button, index) => (
|
||||
<Button
|
||||
key={index}
|
||||
variant="contained"
|
||||
color={button.color}
|
||||
fullWidth
|
||||
onClick={() => onClick(button.action.action, item.ID)}
|
||||
>
|
||||
{button.action.name}
|
||||
</Button>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReviewButtons;
|
@ -1,86 +0,0 @@
|
||||
import { Paper, Grid, Typography } from "@mui/material";
|
||||
import { ReviewItemHeader } from "./ReviewItemHeader";
|
||||
import { CopyableField } from "@/app/_components/review/CopyableField";
|
||||
import { SubmissionInfo } from "@/app/ts/Submission";
|
||||
import { MapfixInfo } from "@/app/ts/Mapfix";
|
||||
|
||||
// Define a field configuration for specific types
|
||||
interface FieldConfig {
|
||||
key: string;
|
||||
label: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
type ReviewItemType = SubmissionInfo | MapfixInfo;
|
||||
|
||||
interface ReviewItemProps {
|
||||
item: ReviewItemType;
|
||||
handleCopyValue: (value: string) => void;
|
||||
}
|
||||
|
||||
export function ReviewItem({
|
||||
item,
|
||||
handleCopyValue
|
||||
}: ReviewItemProps) {
|
||||
// Type guard to check if item is valid
|
||||
if (!item) return null;
|
||||
|
||||
// Determine the type of item
|
||||
const isSubmission = 'UploadedAssetID' in item;
|
||||
const isMapfix = 'TargetAssetID' in item;
|
||||
|
||||
// Define static fields based on item type
|
||||
let fields: FieldConfig[] = [];
|
||||
if (isSubmission) {
|
||||
// Fields for Submission
|
||||
fields = [
|
||||
{ key: 'Submitter', label: 'Submitter ID' },
|
||||
{ key: 'AssetID', label: 'Asset ID' },
|
||||
{ key: 'UploadedAssetID', label: 'Uploaded Asset ID' },
|
||||
];
|
||||
} else if (isMapfix) {
|
||||
// Fields for Mapfix
|
||||
fields = [
|
||||
{ key: 'Submitter', label: 'Submitter ID' },
|
||||
{ key: 'AssetID', label: 'Asset ID' },
|
||||
{ key: 'TargetAssetID', label: 'Target Asset ID' },
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper elevation={3} sx={{ p: 3, borderRadius: 2, mb: 4 }}>
|
||||
<ReviewItemHeader
|
||||
displayName={item.DisplayName}
|
||||
statusId={item.StatusID}
|
||||
creator={item.Creator}
|
||||
submitterId={item.Submitter}
|
||||
/>
|
||||
|
||||
{/* Item Details */}
|
||||
<Grid container spacing={2} sx={{ mt: 2 }}>
|
||||
{fields.map((field) => (
|
||||
<Grid item xs={12} sm={6} key={field.key}>
|
||||
<CopyableField
|
||||
label={field.label}
|
||||
value={(item as never)[field.key]}
|
||||
onCopy={handleCopyValue}
|
||||
placeholderText={field.placeholder}
|
||||
/>
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
|
||||
{/* Description Section */}
|
||||
{isMapfix && item.Description && (
|
||||
<div style={{ marginTop: 24 }}>
|
||||
<Typography variant="subtitle1" fontWeight="bold" gutterBottom>
|
||||
Description
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
{item.Description}
|
||||
</Typography>
|
||||
</div>
|
||||
)}
|
||||
</Paper>
|
||||
);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import {Typography, Box, Avatar} from "@mui/material";
|
||||
import { StatusChip } from "@/app/_components/statusChip";
|
||||
import { SubmissionStatus } from "@/app/ts/Submission";
|
||||
import { MapfixStatus } from "@/app/ts/Mapfix";
|
||||
|
||||
type StatusIdType = SubmissionStatus | MapfixStatus;
|
||||
|
||||
interface ReviewItemHeaderProps {
|
||||
displayName: string;
|
||||
statusId: StatusIdType;
|
||||
creator: string | null | undefined;
|
||||
submitterId: number;
|
||||
}
|
||||
|
||||
export const ReviewItemHeader = ({ displayName, statusId, creator, submitterId }: ReviewItemHeaderProps) => {
|
||||
return (
|
||||
<>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
|
||||
<Typography variant="h4" component="h1" gutterBottom>
|
||||
{displayName}
|
||||
</Typography>
|
||||
<StatusChip status={statusId as number} />
|
||||
</Box>
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1 }}>
|
||||
<Avatar
|
||||
src={`/thumbnails/user/${submitterId}`}
|
||||
sx={{ mr: 1, width: 24, height: 24 }}
|
||||
/>
|
||||
<Typography variant="body1">
|
||||
by {creator || "Unknown Creator"}
|
||||
</Typography>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,87 +0,0 @@
|
||||
import React, {JSX} from "react";
|
||||
import {Cancel, CheckCircle, Pending} from "@mui/icons-material";
|
||||
import {Chip} from "@mui/material";
|
||||
|
||||
export const StatusChip = ({status}: { status: number }) => {
|
||||
let color: 'default' | 'primary' | 'secondary' | 'error' | 'info' | 'success' | 'warning' = 'default';
|
||||
let icon: JSX.Element = <Pending fontSize="small"/>;
|
||||
let label: string = 'Unknown';
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
color = 'warning';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Under Construction';
|
||||
break;
|
||||
case 1:
|
||||
color = 'warning';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Changes Requested';
|
||||
break;
|
||||
case 2:
|
||||
color = 'info';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Submitting';
|
||||
break;
|
||||
case 3:
|
||||
color = 'warning';
|
||||
icon = <CheckCircle fontSize="small"/>;
|
||||
label = 'Under Review';
|
||||
break;
|
||||
case 4:
|
||||
color = 'warning';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Script Review';
|
||||
break;
|
||||
case 5:
|
||||
color = 'info';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Validating';
|
||||
break;
|
||||
case 6:
|
||||
color = 'success';
|
||||
icon = <CheckCircle fontSize="small"/>;
|
||||
label = 'Validated';
|
||||
break;
|
||||
case 7:
|
||||
color = 'info';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Uploading';
|
||||
break;
|
||||
case 8:
|
||||
color = 'success';
|
||||
icon = <CheckCircle fontSize="small"/>;
|
||||
label = 'Uploaded';
|
||||
break;
|
||||
case 9:
|
||||
color = 'error';
|
||||
icon = <Cancel fontSize="small"/>;
|
||||
label = 'Rejected';
|
||||
break;
|
||||
case 10:
|
||||
color = 'success';
|
||||
icon = <CheckCircle fontSize="small"/>;
|
||||
label = 'Released';
|
||||
break;
|
||||
default:
|
||||
color = 'default';
|
||||
icon = <Pending fontSize="small"/>;
|
||||
label = 'Unknown';
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<Chip
|
||||
icon={icon}
|
||||
label={label}
|
||||
color={color}
|
||||
size="small"
|
||||
sx={{
|
||||
height: 24,
|
||||
fontSize: '0.75rem',
|
||||
fontWeight: 600,
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
@ -1,8 +1,25 @@
|
||||
"use client"
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import Header from "./header";
|
||||
|
||||
async function login_check() {
|
||||
const response = await fetch("/api/session/validate")
|
||||
if (response.ok) {
|
||||
const logged_in = await response.json()
|
||||
if (!logged_in) {
|
||||
redirect("https://auth.staging.strafes.net/oauth2/login?redirect=" + window.location.href)
|
||||
}
|
||||
} else {
|
||||
console.error("No response from /api/session/validate")
|
||||
}
|
||||
}
|
||||
|
||||
export default function Webpage({children}: Readonly<{children?: React.ReactNode}>) {
|
||||
useEffect(() => { login_check() }, [])
|
||||
|
||||
return <>
|
||||
<Header/>
|
||||
{children}
|
||||
|
@ -1,65 +0,0 @@
|
||||
import { FormControl, Select, InputLabel, MenuItem } from "@mui/material";
|
||||
import { styled } from '@mui/material/styles';
|
||||
import InputBase from '@mui/material/InputBase';
|
||||
import React from "react";
|
||||
import { SelectChangeEvent } from "@mui/material";
|
||||
|
||||
// TODO: Properly style everything instead of pasting 🤚
|
||||
|
||||
type GameSelectionProps = {
|
||||
game: number;
|
||||
setGame: React.Dispatch<React.SetStateAction<number>>;
|
||||
};
|
||||
|
||||
const BootstrapInput = styled(InputBase)(({ theme }) => ({
|
||||
'label + &': {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
'& .MuiInputBase-input': {
|
||||
backgroundColor: '#0000',
|
||||
color: '#FFF',
|
||||
border: '1px solid rgba(175, 175, 175, 0.66)',
|
||||
fontSize: 16,
|
||||
padding: '10px 26px 10px 12px',
|
||||
transition: theme.transitions.create(['border-color', 'box-shadow']),
|
||||
fontFamily: [
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'"Helvetica Neue"',
|
||||
'Arial',
|
||||
'sans-serif',
|
||||
'"Apple Color Emoji"',
|
||||
'"Segoe UI Emoji"',
|
||||
'"Segoe UI Symbol"',
|
||||
].join(','),
|
||||
'&:focus': {
|
||||
borderRadius: 4,
|
||||
borderColor: '#80bdff',
|
||||
boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default function GameSelection({ game, setGame }: GameSelectionProps) {
|
||||
const handleChange = (event: SelectChangeEvent) => {
|
||||
setGame(Number(event.target.value)); // TODO: Change later!! there's 100% a proper way of doing this
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InputLabel sx={{ color: "#646464" }}>Game</InputLabel>
|
||||
<Select
|
||||
value={String(game)}
|
||||
label="Game"
|
||||
onChange={handleChange}
|
||||
input={<BootstrapInput />}
|
||||
>
|
||||
<MenuItem value={1}>Bhop</MenuItem>
|
||||
<MenuItem value={2}>Surf</MenuItem>
|
||||
<MenuItem value={3}>Fly Trials</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
"use client"
|
||||
|
||||
import { Button, TextField } from "@mui/material"
|
||||
|
||||
import GameSelection from "./_game";
|
||||
import SendIcon from '@mui/icons-material/Send';
|
||||
import Webpage from "@/app/_components/webpage"
|
||||
import React, { useState } from "react";
|
||||
|
||||
import "./(styles)/page.scss"
|
||||
|
||||
interface SubmissionPayload {
|
||||
AssetID: number;
|
||||
DisplayName: string;
|
||||
Creator: string;
|
||||
GameID: number;
|
||||
}
|
||||
interface IdResponse {
|
||||
OperationID: number;
|
||||
}
|
||||
|
||||
export default function SubmissionInfoPage() {
|
||||
const [game, setGame] = useState(1);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const form = event.currentTarget;
|
||||
const formData = new FormData(form);
|
||||
|
||||
const payload: SubmissionPayload = {
|
||||
DisplayName: (formData.get("display-name") as string) ?? "unknown", // TEMPORARY! TODO: Change
|
||||
Creator: (formData.get("creator") as string) ?? "unknown", // TEMPORARY! TODO: Change
|
||||
GameID: game,
|
||||
AssetID: Number((formData.get("asset-id") as string) ?? "-1"),
|
||||
};
|
||||
|
||||
console.log(payload)
|
||||
console.log(JSON.stringify(payload))
|
||||
|
||||
try {
|
||||
// Send the POST request
|
||||
const response = await fetch("/api/submissions-admin", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
// Check if the HTTP request was successful
|
||||
if (!response.ok) {
|
||||
const errorDetails = await response.text();
|
||||
|
||||
// Throw an error with detailed information
|
||||
throw new Error(`HTTP error! status: ${response.status}, details: ${errorDetails}`);
|
||||
}
|
||||
|
||||
// Allow any HTTP status
|
||||
const id_response:IdResponse = await response.json();
|
||||
|
||||
// navigate to newly created submission
|
||||
window.location.assign(`/operations/${id_response.OperationID}`)
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error submitting data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Webpage>
|
||||
<main>
|
||||
<header>
|
||||
<h1>Submit New Map on Behalf of Another User (Admin)</h1>
|
||||
<span className="spacer form-spacer"></span>
|
||||
</header>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField className="form-field" id="asset-id" name="asset-id" label="Asset ID (required)" variant="outlined"/>
|
||||
<TextField className="form-field" id="display-name" name="display-name" label="Display Name" variant="outlined"/>
|
||||
<TextField className="form-field" id="creator" name="creator" label="Creator" variant="outlined"/>
|
||||
<GameSelection game={game} setGame={setGame} />
|
||||
<span className="spacer form-spacer"></span>
|
||||
<Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{
|
||||
width: "400px",
|
||||
height: "50px",
|
||||
marginInline: "auto"
|
||||
}}>Create Submission in ChangesRequested Status (Ready to Force-Submit)</Button>
|
||||
</form>
|
||||
</main>
|
||||
</Webpage>
|
||||
)
|
||||
}
|
Binary file not shown.
Before Width: 48px | Height: 48px | Size: 15 KiB |
@ -1,16 +1,9 @@
|
||||
'use client';
|
||||
import "./globals.scss";
|
||||
import {theme} from "@/app/lib/theme";
|
||||
import {ThemeProvider} from "@mui/material";
|
||||
|
||||
export default function RootLayout({children}: Readonly<{children: React.ReactNode}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<ThemeProvider theme={theme}>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
</body>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import path from 'path';
|
||||
import { promises as fs } from 'fs';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function errorImageResponse(
|
||||
statusCode: number = 500,
|
||||
options?: { message?: string }
|
||||
): Promise<NextResponse> {
|
||||
const file = `${statusCode}.png`;
|
||||
const filePath = path.join(process.cwd(), 'public/errors', file);
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'image/png',
|
||||
};
|
||||
if (options?.message) {
|
||||
headers['X-Error-Message'] = encodeURIComponent(options.message);
|
||||
}
|
||||
|
||||
try {
|
||||
const buffer = await fs.readFile(filePath);
|
||||
headers['Content-Length'] = buffer.length.toString();
|
||||
return new NextResponse(buffer, {
|
||||
status: statusCode,
|
||||
headers,
|
||||
});
|
||||
} catch {
|
||||
const fallback = path.join(process.cwd(), 'public/errors', '500.png');
|
||||
const buffer = await fs.readFile(fallback);
|
||||
headers['Content-Length'] = buffer.length.toString();
|
||||
return new NextResponse(buffer, {
|
||||
status: 500,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
import {createTheme} from "@mui/material";
|
||||
|
||||
export const theme = createTheme({
|
||||
palette: {
|
||||
mode: 'dark',
|
||||
primary: {
|
||||
main: '#90caf9',
|
||||
},
|
||||
secondary: {
|
||||
main: '#f48fb1',
|
||||
},
|
||||
background: {
|
||||
default: '#121212',
|
||||
paper: '#1e1e1e',
|
||||
},
|
||||
},
|
||||
typography: {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||
h5: {
|
||||
fontWeight: 500,
|
||||
letterSpacing: '0.5px',
|
||||
},
|
||||
subtitle1: {
|
||||
fontWeight: 500,
|
||||
fontSize: '0.95rem',
|
||||
},
|
||||
body2: {
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
caption: {
|
||||
fontSize: '0.75rem',
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 8,
|
||||
},
|
||||
components: {
|
||||
MuiCard: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
||||
transition: 'transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out',
|
||||
'&:hover': {
|
||||
transform: 'translateY(-4px)',
|
||||
boxShadow: '0 8px 16px rgba(0, 0, 0, 0.2)',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardMedia: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiCardContent: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
padding: 16,
|
||||
'&:last-child': {
|
||||
paddingBottom: 16,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiChip: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
fontWeight: 500,
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiDivider: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
borderColor: 'rgba(255, 255, 255, 0.1)',
|
||||
},
|
||||
},
|
||||
},
|
||||
MuiPaper: {
|
||||
styleOverrides: {
|
||||
root: {
|
||||
backgroundImage: 'none',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
75
web/src/app/mapfixes/(styles)/page.scss
Normal file
75
web/src/app/mapfixes/(styles)/page.scss
Normal file
@ -0,0 +1,75 @@
|
||||
@forward "../../_components/styles/mapCard.scss";
|
||||
|
||||
@use "../../globals.scss";
|
||||
|
||||
a {
|
||||
color:rgb(255, 255, 255);
|
||||
|
||||
&:visited, &:hover, &:focus {
|
||||
text-decoration: none;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
&:active {
|
||||
color: rgb(192, 192, 192)
|
||||
}
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
grid-template-rows: repeat(3, 1fr);
|
||||
gap: 16px;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
overflow-x: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
margin: 0.3rem;
|
||||
}
|
||||
|
||||
.pagination button {
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 1.15rem;
|
||||
border: none;
|
||||
border-radius: 0.35rem;
|
||||
background-color: #33333350;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pagination button:disabled {
|
||||
background-color: #5555559a;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.pagination-dots {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.35rem;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: #bbb;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dot.active {
|
||||
background-color: #333;
|
||||
}
|
19
web/src/app/mapfixes/[mapfixId]/(styles)/page.scss
Normal file
19
web/src/app/mapfixes/[mapfixId]/(styles)/page.scss
Normal file
@ -0,0 +1,19 @@
|
||||
@forward "./page/commentWindow.scss";
|
||||
@forward "./page/reviewStatus.scss";
|
||||
@forward "./page/ratingWindow.scss";
|
||||
@forward "./page/reviewButtons.scss";
|
||||
@forward "./page/comments.scss";
|
||||
@forward "./page/review.scss";
|
||||
@forward "./page/map.scss";
|
||||
|
||||
@use "../../../globals.scss";
|
||||
|
||||
.map-page-main {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
.by-creator {
|
||||
margin-top: 10px;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user