1 Commits

Author SHA1 Message Date
69438a9d0c wip: restricted submissions endpoint
All checks were successful
continuous-integration/drone/push Build is passing
2025-04-03 15:06:52 -07:00
123 changed files with 1654 additions and 20202 deletions

738
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
# Stage 1: Build
FROM registry.itzana.me/docker-proxy/golang:1.24 AS builder
FROM docker.io/golang:1.23 AS builder
# Set the working directory in the container
WORKDIR /app
@@ -14,7 +14,7 @@ COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o service ./cmd/maps-service/service.go
# Stage 2: Run
FROM registry.itzana.me/docker-proxy/alpine:3.21
FROM alpine
# Set up a non-root user for security
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

View File

@@ -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`

View File

@@ -50,7 +50,6 @@ services:
- "3000:3000"
environment:
- API_HOST=http://submissions:8082/v1
- AUTH_HOST=http://localhost:8080/
validation:
image:

View File

@@ -48,81 +48,12 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: ValidatedModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-submitted:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
operationId: actionMapfixSubmitted
tags:
- 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 +88,7 @@ paths:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ErrorMessage
- name: StatusMessage
in: query
required: true
schema:
@@ -253,81 +184,12 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: ValidatedModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-submitted:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
operationId: actionSubmissionSubmitted
tags:
- 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 +224,7 @@ paths:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ErrorMessage
- name: StatusMessage
in: query
required: true
schema:
@@ -392,7 +254,6 @@ paths:
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
@@ -422,13 +283,11 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: Policy
in: query
schema:
type: integer
format: int32
minimum: 0
responses:
"200":
description: Successful response
@@ -498,13 +357,11 @@ paths:
schema:
type: integer
format: int32
minimum: 0
- name: ResourceID
in: query
schema:
type: integer
format: int64
minimum: 0
responses:
"200":
description: Successful response
@@ -575,7 +432,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
OperationID:
name: OperationID
in: path
@@ -584,7 +440,6 @@ components:
schema:
type: integer
format: int32
minimum: 0
SubmissionID:
name: SubmissionID
in: path
@@ -593,7 +448,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
ScriptID:
name: ScriptID
in: path
@@ -602,7 +456,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
Page:
name: Page
in: query
@@ -629,7 +482,6 @@ components:
MapfixID:
type: integer
format: int64
minimum: 0
SubmissionID:
required:
- SubmissionID
@@ -638,7 +490,6 @@ components:
SubmissionID:
type: integer
format: int64
minimum: 0
ScriptID:
required:
- ScriptID
@@ -647,7 +498,6 @@ components:
ScriptID:
type: integer
format: int64
minimum: 0
ScriptPolicyID:
required:
- ScriptPolicyID
@@ -656,7 +506,6 @@ components:
ScriptPolicyID:
type: integer
format: int64
minimum: 0
MapfixCreate:
required:
- OperationID
@@ -667,17 +516,14 @@ components:
- AssetID
- AssetVersion
- TargetAssetID
- Description
type: object
properties:
OperationID:
type: integer
format: int32
minimum: 0
AssetOwner:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
@@ -687,22 +533,15 @@ components:
GameID:
type: integer
format: int32
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
TargetAssetID:
type: integer
format: int64
minimum: 0
Description:
type: string
maxLength: 256
SubmissionCreate:
required:
- OperationID
@@ -712,18 +551,14 @@ components:
- GameID
- AssetID
- AssetVersion
- Status
- Roles
type: object
properties:
OperationID:
type: integer
format: int32
minimum: 0
AssetOwner:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
@@ -733,23 +568,12 @@ components:
GameID:
type: integer
format: int32
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
Status:
type: integer
format: uint32
minimum: 0
maximum: 9
Roles:
type: integer
format: uint32
Script:
required:
- ID
@@ -763,7 +587,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
Name:
type: string
maxLength: 128
@@ -777,11 +600,9 @@ components:
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptCreate:
required:
- Name
@@ -799,11 +620,9 @@ components:
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptPolicy:
required:
- ID
@@ -815,7 +634,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
FromScriptHash:
type: string
minLength: 16
@@ -823,11 +641,9 @@ components:
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
ScriptPolicyCreate:
required:
- FromScriptID
@@ -838,15 +654,12 @@ components:
FromScriptID:
type: integer
format: int64
minimum: 0
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
Error:
description: Represents error object
type: object
@@ -854,7 +667,6 @@ components:
code:
type: integer
format: int64
minimum: 0
message:
type: string
required:

View File

@@ -105,15 +105,11 @@ paths:
schema:
type: integer
format: int32
minimum: 1
maximum: 5
- name: Sort
in: query
schema:
type: integer
format: int32
minimum: 0
maximum: 4
responses:
"200":
description: Successful response
@@ -176,47 +172,20 @@ paths:
schema:
type: integer
format: int32
minimum: 1
maximum: 5
- name: Sort
in: query
schema:
type: integer
format: int32
minimum: 0
maximum: 4
- name: Submitter
in: query
schema:
type: integer
format: int64
minimum: 0
- name: AssetID
in: query
schema:
type: integer
format: int64
minimum: 0
- name: TargetAssetID
in: query
schema:
type: integer
format: int64
minimum: 0
- name: StatusID
in: query
schema:
type: integer
format: int32
minimum: 0
maximum: 9
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Mapfixes"
type: array
items:
$ref: "#/components/schemas/Mapfix"
default:
description: General Error
content:
@@ -269,56 +238,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/audit-events:
get:
summary: Retrieve a list of audit events
operationId: listMapfixAuditEvents
tags:
- Mapfixes
security: []
parameters:
- $ref: '#/components/parameters/MapfixID'
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AuditEvent"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/comment:
post:
summary: Post a comment to the audit log
operationId: createMapfixAuditComment
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
requestBody:
required: true
content:
text/plain:
schema:
type: string
maxLength: 1024
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/model:
post:
summary: Update model following role restrictions
@@ -333,14 +252,12 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: ModelVersion
- name: VersionID
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
@@ -367,44 +284,10 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/trigger-submit:
/mapfixes/{MapfixID}/status/submit:
post:
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting
operationId: actionMapfixTriggerSubmit
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/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
operationId: actionMapfixResetSubmitting
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
operationId: actionMapfixSubmit
tags:
- Mapfixes
parameters:
@@ -600,47 +483,20 @@ paths:
schema:
type: integer
format: int32
minimum: 1
maximum: 5
- name: Sort
in: query
schema:
type: integer
format: int32
minimum: 0
maximum: 4
- name: Submitter
in: query
schema:
type: integer
format: int64
minimum: 0
- name: AssetID
in: query
schema:
type: integer
format: int64
minimum: 0
- name: UploadedAssetID
in: query
schema:
type: integer
format: int64
minimum: 0
- name: StatusID
in: query
schema:
type: integer
format: int32
minimum: 0
maximum: 10
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Submissions"
type: array
items:
$ref: "#/components/schemas/Submission"
default:
description: General Error
content:
@@ -671,31 +527,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
@@ -718,56 +549,6 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/audit-events:
get:
summary: Retrieve a list of audit events
operationId: listSubmissionAuditEvents
tags:
- Submissions
security: []
parameters:
- $ref: '#/components/parameters/SubmissionID'
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/Limit"
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/AuditEvent"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/comment:
post:
summary: Post a comment to the audit log
operationId: createSubmissionAuditComment
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
requestBody:
required: true
content:
text/plain:
schema:
type: string
maxLength: 1024
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/model:
post:
summary: Update model following role restrictions
@@ -782,14 +563,12 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: ModelVersion
- name: VersionID
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
@@ -816,44 +595,10 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/trigger-submit:
/submissions/{SubmissionID}/status/submit:
post:
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting
operationId: actionSubmissionTriggerSubmit
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/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
operationId: actionSubmissionResetSubmitting
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
operationId: actionSubmissionSubmit
tags:
- Submissions
parameters:
@@ -1049,13 +794,11 @@ paths:
schema:
type: integer
format: int64
minimum: 0
- name: Policy
in: query
schema:
type: integer
format: int32
minimum: 0
responses:
"200":
description: Successful response
@@ -1186,13 +929,11 @@ paths:
schema:
type: integer
format: int32
minimum: 0
- name: ResourceID
in: query
schema:
type: integer
format: int64
minimum: 0
responses:
"200":
description: Successful response
@@ -1307,7 +1048,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
MapfixID:
name: MapfixID
in: path
@@ -1316,7 +1056,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
OperationID:
name: OperationID
in: path
@@ -1325,7 +1064,6 @@ components:
schema:
type: integer
format: int32
minimum: 0
SubmissionID:
name: SubmissionID
in: path
@@ -1334,7 +1072,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
ScriptID:
name: ScriptID
in: path
@@ -1343,7 +1080,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
ScriptPolicyID:
name: ScriptPolicyID
in: path
@@ -1352,7 +1088,6 @@ components:
schema:
type: integer
format: int64
minimum: 0
Page:
name: Page
in: query
@@ -1368,47 +1103,9 @@ components:
schema:
type: integer
format: int32
minimum: 0
minimum: 1
maximum: 100
schemas:
AuditEvent:
type: object
required:
- ID
- Date
- User
- Username
- ResourceType
- ResourceID
- EventType
- EventData
properties:
ID:
type: integer
format: int64
Date:
type: integer
format: int64
User:
type: integer
format: int64
Username:
type: string
maxLength: 64
ResourceType:
type: integer
format: int32
description: Is this a submission or is it a mapfix
ResourceID:
type: integer
format: int64
EventType:
type: integer
format: int32
EventData:
type: object
description: Arbitrary event data
additionalProperties: true
OperationID:
required:
- OperationID
@@ -1417,7 +1114,6 @@ components:
OperationID:
type: integer
format: int32
minimum: 0
ScriptID:
required:
- ScriptID
@@ -1426,7 +1122,6 @@ components:
ScriptID:
type: integer
format: int64
minimum: 0
ScriptPolicyID:
required:
- ScriptPolicyID
@@ -1435,7 +1130,6 @@ components:
ScriptPolicyID:
type: integer
format: int64
minimum: 0
Roles:
required:
- Roles
@@ -1444,7 +1138,6 @@ components:
Roles:
type: integer
format: int32
minimum: 0
User:
required:
- UserID
@@ -1455,7 +1148,6 @@ components:
UserID:
type: integer
format: int64
minimum: 0
Username:
type: string
maxLength: 128
@@ -1474,7 +1166,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
@@ -1484,11 +1175,9 @@ components:
GameID:
type: integer
format: int32
minimum: 0
Date:
type: integer
format: int64
minimum: 0
Mapfix:
required:
- ID
@@ -1503,13 +1192,12 @@ components:
- Completed
- TargetAssetID
- StatusID
- Description
- StatusMessage
type: object
properties:
ID:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
@@ -1519,72 +1207,44 @@ components:
GameID:
type: integer
format: int32
minimum: 0
CreatedAt:
type: integer
format: int64
minimum: 0
UpdatedAt:
type: integer
format: int64
minimum: 0
Submitter:
type: integer
format: int64
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
Completed:
type: boolean
TargetAssetID:
type: integer
format: int64
minimum: 0
StatusID:
type: integer
format: int32
minimum: 0
Description:
StatusMessage:
type: string
maxLength: 256
Mapfixes:
type: object
required:
- Total
- Mapfixes
properties:
Total:
type: integer
format: int64
minimum: 0
Mapfixes:
type: array
items:
$ref: "#/components/schemas/Mapfix"
MapfixTriggerCreate:
required:
- AssetID
- TargetAssetID
- Description
type: object
properties:
AssetID:
type: integer
format: int64
minimum: 0
TargetAssetID:
type: integer
format: int64
minimum: 0
Description:
type: string
maxLength: 256
Operation:
required:
- OperationID
@@ -1598,19 +1258,15 @@ components:
OperationID:
type: integer
format: int32
minimum: 0
Date:
type: integer
format: int64
minimum: 0
Owner:
type: integer
format: int64
minimum: 0
Status:
type: integer
format: int32
minimum: 0
StatusMessage:
type: string
maxLength: 256
@@ -1633,12 +1289,12 @@ components:
- Completed
# - UploadedAssetID
- StatusID
- StatusMessage
type: object
properties:
ID:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
@@ -1648,81 +1304,46 @@ components:
GameID:
type: integer
format: int32
minimum: 0
CreatedAt:
type: integer
format: int64
minimum: 0
UpdatedAt:
type: integer
format: int64
minimum: 0
Submitter:
type: integer
format: int64
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
ValidatedAssetID:
type: integer
format: int64
minimum: 0
ValidatedAssetVersion:
type: integer
format: int64
minimum: 0
Completed:
type: boolean
UploadedAssetID:
type: integer
format: int64
minimum: 0
StatusID:
type: integer
format: int32
minimum: 0
Submissions:
required:
- Total
- Submissions
type: object
properties:
Total:
type: integer
format: int64
minimum: 0
Submissions:
type: array
items:
$ref: "#/components/schemas/Submission"
StatusMessage:
type: string
maxLength: 256
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
minimum: 0
ReleaseInfo:
required:
- SubmissionID
@@ -1732,7 +1353,6 @@ components:
SubmissionID:
type: integer
format: int64
minimum: 0
Date:
type: string
format: date-time
@@ -1749,7 +1369,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
Name:
type: string
maxLength: 128
@@ -1763,11 +1382,9 @@ components:
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptCreate:
required:
- Name
@@ -1785,11 +1402,9 @@ components:
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptUpdate:
required:
- ID
@@ -1798,7 +1413,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
Name:
type: string
maxLength: 128
@@ -1808,11 +1422,9 @@ components:
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptPolicy:
required:
- ID
@@ -1824,7 +1436,6 @@ components:
ID:
type: integer
format: int64
minimum: 0
FromScriptHash:
type: string
minLength: 16
@@ -1832,11 +1443,9 @@ components:
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
ScriptPolicyCreate:
required:
- FromScriptID
@@ -1847,15 +1456,12 @@ components:
FromScriptID:
type: integer
format: int64
minimum: 0
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
ScriptPolicyUpdate:
required:
- ID
@@ -1864,19 +1470,15 @@ components:
ID:
type: integer
format: int64
minimum: 0
FromScriptID:
type: integer
format: int64
minimum: 0
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
Error:
description: Represents error object
type: object
@@ -1884,7 +1486,6 @@ components:
code:
type: integer
format: int64
minimum: 0
message:
type: string
required:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -13,277 +13,6 @@ import (
"github.com/ogen-go/ogen/validate"
)
// Encode implements json.Marshaler.
func (s *AuditEvent) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *AuditEvent) encodeFields(e *jx.Encoder) {
{
e.FieldStart("ID")
e.Int64(s.ID)
}
{
e.FieldStart("Date")
e.Int64(s.Date)
}
{
e.FieldStart("User")
e.Int64(s.User)
}
{
e.FieldStart("Username")
e.Str(s.Username)
}
{
e.FieldStart("ResourceType")
e.Int32(s.ResourceType)
}
{
e.FieldStart("ResourceID")
e.Int64(s.ResourceID)
}
{
e.FieldStart("EventType")
e.Int32(s.EventType)
}
{
e.FieldStart("EventData")
s.EventData.Encode(e)
}
}
var jsonFieldsNameOfAuditEvent = [8]string{
0: "ID",
1: "Date",
2: "User",
3: "Username",
4: "ResourceType",
5: "ResourceID",
6: "EventType",
7: "EventData",
}
// Decode decodes AuditEvent from json.
func (s *AuditEvent) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode AuditEvent to nil")
}
var requiredBitSet [1]uint8
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "ID":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Int64()
s.ID = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"ID\"")
}
case "Date":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Int64()
s.Date = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Date\"")
}
case "User":
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Int64()
s.User = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"User\"")
}
case "Username":
requiredBitSet[0] |= 1 << 3
if err := func() error {
v, err := d.Str()
s.Username = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Username\"")
}
case "ResourceType":
requiredBitSet[0] |= 1 << 4
if err := func() error {
v, err := d.Int32()
s.ResourceType = int32(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"ResourceType\"")
}
case "ResourceID":
requiredBitSet[0] |= 1 << 5
if err := func() error {
v, err := d.Int64()
s.ResourceID = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"ResourceID\"")
}
case "EventType":
requiredBitSet[0] |= 1 << 6
if err := func() error {
v, err := d.Int32()
s.EventType = int32(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"EventType\"")
}
case "EventData":
requiredBitSet[0] |= 1 << 7
if err := func() error {
if err := s.EventData.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"EventData\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode AuditEvent")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b11111111,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(jsonFieldsNameOfAuditEvent) {
name = jsonFieldsNameOfAuditEvent[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *AuditEvent) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *AuditEvent) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s AuditEventEventData) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields implements json.Marshaler.
func (s AuditEventEventData) encodeFields(e *jx.Encoder) {
for k, elem := range s {
e.FieldStart(k)
if len(elem) != 0 {
e.Raw(elem)
}
}
}
// Decode decodes AuditEventEventData from json.
func (s *AuditEventEventData) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode AuditEventEventData to nil")
}
m := s.init()
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
var elem jx.Raw
if err := func() error {
v, err := d.RawAppend(nil)
elem = jx.Raw(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrapf(err, "decode field %q", k)
}
m[string(k)] = elem
return nil
}); err != nil {
return errors.Wrap(err, "decode AuditEventEventData")
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s AuditEventEventData) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *AuditEventEventData) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Error) Encode(e *jx.Encoder) {
e.ObjStart()
@@ -619,8 +348,8 @@ func (s *Mapfix) encodeFields(e *jx.Encoder) {
e.Int32(s.StatusID)
}
{
e.FieldStart("Description")
e.Str(s.Description)
e.FieldStart("StatusMessage")
e.Str(s.StatusMessage)
}
}
@@ -637,7 +366,7 @@ var jsonFieldsNameOfMapfix = [13]string{
9: "Completed",
10: "TargetAssetID",
11: "StatusID",
12: "Description",
12: "StatusMessage",
}
// Decode decodes Mapfix from json.
@@ -793,17 +522,17 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
}(); err != nil {
return errors.Wrap(err, "decode field \"StatusID\"")
}
case "Description":
case "StatusMessage":
requiredBitSet[1] |= 1 << 4
if err := func() error {
v, err := d.Str()
s.Description = string(v)
s.StatusMessage = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Description\"")
return errors.Wrap(err, "decode field \"StatusMessage\"")
}
default:
return d.Skip()
@@ -879,16 +608,11 @@ func (s *MapfixTriggerCreate) encodeFields(e *jx.Encoder) {
e.FieldStart("TargetAssetID")
e.Int64(s.TargetAssetID)
}
{
e.FieldStart("Description")
e.Str(s.Description)
}
}
var jsonFieldsNameOfMapfixTriggerCreate = [3]string{
var jsonFieldsNameOfMapfixTriggerCreate = [2]string{
0: "AssetID",
1: "TargetAssetID",
2: "Description",
}
// Decode decodes MapfixTriggerCreate from json.
@@ -924,18 +648,6 @@ func (s *MapfixTriggerCreate) Decode(d *jx.Decoder) error {
}(); err != nil {
return errors.Wrap(err, "decode field \"TargetAssetID\"")
}
case "Description":
requiredBitSet[0] |= 1 << 2
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()
}
@@ -946,7 +658,7 @@ func (s *MapfixTriggerCreate) Decode(d *jx.Decoder) error {
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000111,
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
@@ -992,129 +704,6 @@ func (s *MapfixTriggerCreate) UnmarshalJSON(data []byte) error {
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Mapfixes) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *Mapfixes) encodeFields(e *jx.Encoder) {
{
e.FieldStart("Total")
e.Int64(s.Total)
}
{
e.FieldStart("Mapfixes")
e.ArrStart()
for _, elem := range s.Mapfixes {
elem.Encode(e)
}
e.ArrEnd()
}
}
var jsonFieldsNameOfMapfixes = [2]string{
0: "Total",
1: "Mapfixes",
}
// Decode decodes Mapfixes from json.
func (s *Mapfixes) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Mapfixes to nil")
}
var requiredBitSet [1]uint8
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "Total":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Int64()
s.Total = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Total\"")
}
case "Mapfixes":
requiredBitSet[0] |= 1 << 1
if err := func() error {
s.Mapfixes = make([]Mapfix, 0)
if err := d.Arr(func(d *jx.Decoder) error {
var elem Mapfix
if err := elem.Decode(d); err != nil {
return err
}
s.Mapfixes = append(s.Mapfixes, elem)
return nil
}); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Mapfixes\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Mapfixes")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(jsonFieldsNameOfMapfixes) {
name = jsonFieldsNameOfMapfixes[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *Mapfixes) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *Mapfixes) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Operation) Encode(e *jx.Encoder) {
e.ObjStart()
@@ -2885,9 +2474,13 @@ func (s *Submission) encodeFields(e *jx.Encoder) {
e.FieldStart("StatusID")
e.Int32(s.StatusID)
}
{
e.FieldStart("StatusMessage")
e.Str(s.StatusMessage)
}
}
var jsonFieldsNameOfSubmission = [14]string{
var jsonFieldsNameOfSubmission = [15]string{
0: "ID",
1: "DisplayName",
2: "Creator",
@@ -2902,6 +2495,7 @@ var jsonFieldsNameOfSubmission = [14]string{
11: "Completed",
12: "UploadedAssetID",
13: "StatusID",
14: "StatusMessage",
}
// Decode decodes Submission from json.
@@ -3075,6 +2669,18 @@ func (s *Submission) Decode(d *jx.Decoder) error {
}(); err != nil {
return errors.Wrap(err, "decode field \"StatusID\"")
}
case "StatusMessage":
requiredBitSet[1] |= 1 << 6
if err := func() error {
v, err := d.Str()
s.StatusMessage = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"StatusMessage\"")
}
default:
return d.Skip()
}
@@ -3086,7 +2692,7 @@ func (s *Submission) Decode(d *jx.Decoder) error {
var failures []validate.FieldError
for i, mask := range [2]uint8{
0b11111111,
0b00101001,
0b01101001,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
@@ -3145,25 +2751,10 @@ func (s *SubmissionTriggerCreate) encodeFields(e *jx.Encoder) {
e.FieldStart("AssetID")
e.Int64(s.AssetID)
}
{
e.FieldStart("DisplayName")
e.Str(s.DisplayName)
}
{
e.FieldStart("Creator")
e.Str(s.Creator)
}
{
e.FieldStart("GameID")
e.Int32(s.GameID)
}
}
var jsonFieldsNameOfSubmissionTriggerCreate = [4]string{
var jsonFieldsNameOfSubmissionTriggerCreate = [1]string{
0: "AssetID",
1: "DisplayName",
2: "Creator",
3: "GameID",
}
// Decode decodes SubmissionTriggerCreate from json.
@@ -3187,42 +2778,6 @@ func (s *SubmissionTriggerCreate) Decode(d *jx.Decoder) error {
}(); err != nil {
return errors.Wrap(err, "decode field \"AssetID\"")
}
case "DisplayName":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.DisplayName = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"DisplayName\"")
}
case "Creator":
requiredBitSet[0] |= 1 << 2
if err := func() error {
v, err := d.Str()
s.Creator = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Creator\"")
}
case "GameID":
requiredBitSet[0] |= 1 << 3
if err := func() error {
v, err := d.Int32()
s.GameID = int32(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"")
}
default:
return d.Skip()
}
@@ -3233,7 +2788,7 @@ func (s *SubmissionTriggerCreate) Decode(d *jx.Decoder) error {
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00001111,
0b00000001,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
@@ -3279,129 +2834,6 @@ func (s *SubmissionTriggerCreate) UnmarshalJSON(data []byte) error {
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Submissions) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *Submissions) encodeFields(e *jx.Encoder) {
{
e.FieldStart("Total")
e.Int64(s.Total)
}
{
e.FieldStart("Submissions")
e.ArrStart()
for _, elem := range s.Submissions {
elem.Encode(e)
}
e.ArrEnd()
}
}
var jsonFieldsNameOfSubmissions = [2]string{
0: "Total",
1: "Submissions",
}
// Decode decodes Submissions from json.
func (s *Submissions) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Submissions to nil")
}
var requiredBitSet [1]uint8
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "Total":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Int64()
s.Total = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Total\"")
}
case "Submissions":
requiredBitSet[0] |= 1 << 1
if err := func() error {
s.Submissions = make([]Submission, 0)
if err := d.Arr(func(d *jx.Decoder) error {
var elem Submission
if err := elem.Decode(d); err != nil {
return err
}
s.Submissions = append(s.Submissions, elem)
return nil
}); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Submissions\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Submissions")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(jsonFieldsNameOfSubmissions) {
name = jsonFieldsNameOfSubmissions[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *Submissions) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *Submissions) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *User) Encode(e *jx.Encoder) {
e.ObjStart()

View File

@@ -7,34 +7,27 @@ type OperationName = string
const (
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
ActionMapfixBypassSubmitOperation OperationName = "ActionMapfixBypassSubmit"
ActionMapfixRejectOperation OperationName = "ActionMapfixReject"
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
ActionMapfixResetSubmittingOperation OperationName = "ActionMapfixResetSubmitting"
ActionMapfixRetryValidateOperation OperationName = "ActionMapfixRetryValidate"
ActionMapfixRevokeOperation OperationName = "ActionMapfixRevoke"
ActionMapfixTriggerSubmitOperation OperationName = "ActionMapfixTriggerSubmit"
ActionMapfixSubmitOperation OperationName = "ActionMapfixSubmit"
ActionMapfixTriggerUploadOperation OperationName = "ActionMapfixTriggerUpload"
ActionMapfixTriggerValidateOperation OperationName = "ActionMapfixTriggerValidate"
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
ActionSubmissionBypassSubmitOperation OperationName = "ActionSubmissionBypassSubmit"
ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject"
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
ActionSubmissionResetSubmittingOperation OperationName = "ActionSubmissionResetSubmitting"
ActionSubmissionRetryValidateOperation OperationName = "ActionSubmissionRetryValidate"
ActionSubmissionRevokeOperation OperationName = "ActionSubmissionRevoke"
ActionSubmissionTriggerSubmitOperation OperationName = "ActionSubmissionTriggerSubmit"
ActionSubmissionSubmitOperation OperationName = "ActionSubmissionSubmit"
ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload"
ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
CreateMapfixOperation OperationName = "CreateMapfix"
CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment"
CreateScriptOperation OperationName = "CreateScript"
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
CreateSubmissionOperation OperationName = "CreateSubmission"
CreateSubmissionAdminOperation OperationName = "CreateSubmissionAdmin"
CreateSubmissionAuditCommentOperation OperationName = "CreateSubmissionAuditComment"
DeleteScriptOperation OperationName = "DeleteScript"
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
GetMapOperation OperationName = "GetMap"
@@ -43,12 +36,10 @@ const (
GetScriptOperation OperationName = "GetScript"
GetScriptPolicyOperation OperationName = "GetScriptPolicy"
GetSubmissionOperation OperationName = "GetSubmission"
ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents"
ListMapfixesOperation OperationName = "ListMapfixes"
ListMapsOperation OperationName = "ListMaps"
ListScriptPolicyOperation OperationName = "ListScriptPolicy"
ListScriptsOperation OperationName = "ListScripts"
ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents"
ListSubmissionsOperation OperationName = "ListSubmissions"
ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions"
SessionRolesOperation OperationName = "SessionRoles"

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,13 @@
package api
import (
"fmt"
"io"
"mime"
"net/http"
"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 +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"))
@@ -72,54 +72,12 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
}
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) decodeCreateMapfixAuditCommentRequest(r *http.Request) (
req CreateMapfixAuditCommentReq,
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())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "text/plain":
reader := r.Body
request := CreateMapfixAuditCommentReq{Data: reader}
return request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateScriptRequest(r *http.Request) (
req *ScriptCreate,
close func() error,
@@ -131,13 +89,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 +160,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"))
@@ -248,14 +206,6 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
}
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)
@@ -273,13 +223,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"))
@@ -319,125 +269,12 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
}
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())
}
}()
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) decodeCreateSubmissionAuditCommentRequest(r *http.Request) (
req CreateSubmissionAuditCommentReq,
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())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "text/plain":
reader := r.Body
request := CreateSubmissionAuditCommentReq{Data: reader}
return request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
req []ReleaseInfo,
close func() error,
@@ -449,13 +286,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"))
@@ -515,23 +352,6 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
}).ValidateLength(len(request)); err != nil {
return errors.Wrap(err, "array")
}
var failures []validate.FieldError
for i, elem := range request {
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 req, close, errors.Wrap(err, "validate")
@@ -553,13 +373,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 +444,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"))
@@ -670,14 +490,6 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
}
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)

View File

@@ -25,16 +25,6 @@ func encodeCreateMapfixRequest(
return nil
}
func encodeCreateMapfixAuditCommentRequest(
req CreateMapfixAuditCommentReq,
r *http.Request,
) error {
const contentType = "text/plain"
body := req
ht.SetBody(r, body, contentType)
return nil
}
func encodeCreateScriptRequest(
req *ScriptCreate,
r *http.Request,
@@ -77,30 +67,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,
) error {
const contentType = "text/plain"
body := req
ht.SetBody(r, body, contentType)
return nil
}
func encodeReleaseSubmissionsRequest(
req []ReleaseInfo,
r *http.Request,

File diff suppressed because it is too large Load Diff

View File

@@ -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))
@@ -41,13 +34,6 @@ func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChang
return nil
}
func encodeActionMapfixResetSubmittingResponse(response *ActionMapfixResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixRetryValidateResponse(response *ActionMapfixRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -62,7 +48,7 @@ func encodeActionMapfixRevokeResponse(response *ActionMapfixRevokeNoContent, w h
return nil
}
func encodeActionMapfixTriggerSubmitResponse(response *ActionMapfixTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
func encodeActionMapfixSubmitResponse(response *ActionMapfixSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -97,13 +83,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))
@@ -118,13 +97,6 @@ func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequ
return nil
}
func encodeActionSubmissionResetSubmittingResponse(response *ActionSubmissionResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionRetryValidateResponse(response *ActionSubmissionRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -139,7 +111,7 @@ func encodeActionSubmissionRevokeResponse(response *ActionSubmissionRevokeNoCont
return nil
}
func encodeActionSubmissionTriggerSubmitResponse(response *ActionSubmissionTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
func encodeActionSubmissionSubmitResponse(response *ActionSubmissionSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -181,13 +153,6 @@ func encodeCreateMapfixResponse(response *OperationID, w http.ResponseWriter, sp
return nil
}
func encodeCreateMapfixAuditCommentResponse(response *CreateMapfixAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeCreateScriptResponse(response *ScriptID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
@@ -230,27 +195,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))
return nil
}
func encodeDeleteScriptResponse(response *DeleteScriptNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -349,7 +293,7 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp
return nil
}
func encodeListMapfixAuditEventsResponse(response []AuditEvent, w http.ResponseWriter, span trace.Span) error {
func encodeListMapfixesResponse(response []Mapfix, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
@@ -367,20 +311,6 @@ func encodeListMapfixAuditEventsResponse(response []AuditEvent, w http.ResponseW
return nil
}
func encodeListMapfixesResponse(response *Mapfixes, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeListMapsResponse(response []Map, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
@@ -435,7 +365,7 @@ func encodeListScriptsResponse(response []Script, w http.ResponseWriter, span tr
return nil
}
func encodeListSubmissionAuditEventsResponse(response []AuditEvent, w http.ResponseWriter, span trace.Span) error {
func encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
@@ -453,20 +383,6 @@ func encodeListSubmissionAuditEventsResponse(response []AuditEvent, w http.Respo
return nil
}
func encodeListSubmissionsResponse(response *Submissions, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeReleaseSubmissionsResponse(response *ReleaseSubmissionsCreated, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(201)
span.SetStatus(codes.Ok, http.StatusText(201))

View File

@@ -136,9 +136,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 'a': // Prefix: "audit-events"
case 'c': // Prefix: "completed"
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
@@ -147,75 +147,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "GET":
s.handleListMapfixAuditEventsRequest([1]string{
case "POST":
s.handleSetMapfixCompletedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
s.notAllowed(w, r, "POST")
}
return
}
case 'c': // Prefix: "com"
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'm': // Prefix: "ment"
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleCreateMapfixAuditCommentRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'p': // Prefix: "pleted"
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleSetMapfixCompletedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
}
case 'm': // Prefix: "model"
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
@@ -250,28 +192,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" {
@@ -340,28 +260,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 's': // Prefix: "submitting"
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionMapfixResetSubmittingRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "uploading"
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
@@ -454,6 +352,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionMapfixSubmitRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 't': // Prefix: "trigger-"
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
@@ -466,28 +386,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionMapfixTriggerSubmitRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "upload"
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
@@ -892,26 +790,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] == "/" {
@@ -954,9 +832,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 'a': // Prefix: "audit-events"
case 'c': // Prefix: "completed"
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
@@ -965,75 +843,17 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "GET":
s.handleListSubmissionAuditEventsRequest([1]string{
case "POST":
s.handleSetSubmissionCompletedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
s.notAllowed(w, r, "POST")
}
return
}
case 'c': // Prefix: "com"
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'm': // Prefix: "ment"
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleCreateSubmissionAuditCommentRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'p': // Prefix: "pleted"
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleSetSubmissionCompletedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
}
case 'm': // Prefix: "model"
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
@@ -1068,28 +888,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" {
@@ -1158,28 +956,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 's': // Prefix: "submitting"
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionSubmissionResetSubmittingRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "uploading"
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
@@ -1272,6 +1048,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionSubmissionSubmitRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 't': // Prefix: "trigger-"
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
@@ -1284,28 +1082,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break
}
switch elem[0] {
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionSubmissionTriggerSubmitRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "upload"
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
@@ -1543,9 +1319,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 'a': // Prefix: "audit-events"
case 'c': // Prefix: "completed"
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
@@ -1554,11 +1330,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 {
// Leaf node.
switch method {
case "GET":
r.name = ListMapfixAuditEventsOperation
r.summary = "Retrieve a list of audit events"
r.operationID = "listMapfixAuditEvents"
r.pathPattern = "/mapfixes/{MapfixID}/audit-events"
case "POST":
r.name = SetMapfixCompletedOperation
r.summary = "Called by maptest when a player completes the map"
r.operationID = "setMapfixCompleted"
r.pathPattern = "/mapfixes/{MapfixID}/completed"
r.args = args
r.count = 1
return r, true
@@ -1567,68 +1343,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
}
}
case 'c': // Prefix: "com"
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'm': // Prefix: "ment"
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = CreateMapfixAuditCommentOperation
r.summary = "Post a comment to the audit log"
r.operationID = "createMapfixAuditComment"
r.pathPattern = "/mapfixes/{MapfixID}/comment"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'p': // Prefix: "pleted"
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = SetMapfixCompletedOperation
r.summary = "Called by maptest when a player completes the map"
r.operationID = "setMapfixCompleted"
r.pathPattern = "/mapfixes/{MapfixID}/completed"
r.args = args
r.count = 1
return r, true
default:
return
}
}
}
case 'm': // Prefix: "model"
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
@@ -1665,30 +1379,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" {
@@ -1761,30 +1451,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 's': // Prefix: "submitting"
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionMapfixResetSubmittingOperation
r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction"
r.operationID = "actionMapfixResetSubmitting"
r.pathPattern = "/mapfixes/{MapfixID}/status/reset-submitting"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "uploading"
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
@@ -1885,6 +1551,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
}
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionMapfixSubmitOperation
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
r.operationID = "actionMapfixSubmit"
r.pathPattern = "/mapfixes/{MapfixID}/status/submit"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 't': // Prefix: "trigger-"
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
@@ -1897,30 +1587,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionMapfixTriggerSubmitOperation
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting"
r.operationID = "actionMapfixTriggerSubmit"
r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "upload"
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
@@ -2403,30 +2069,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] == "/" {
@@ -2471,9 +2113,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 'a': // Prefix: "audit-events"
case 'c': // Prefix: "completed"
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
@@ -2482,11 +2124,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 {
// Leaf node.
switch method {
case "GET":
r.name = ListSubmissionAuditEventsOperation
r.summary = "Retrieve a list of audit events"
r.operationID = "listSubmissionAuditEvents"
r.pathPattern = "/submissions/{SubmissionID}/audit-events"
case "POST":
r.name = SetSubmissionCompletedOperation
r.summary = "Called by maptest when a player completes the map"
r.operationID = "setSubmissionCompleted"
r.pathPattern = "/submissions/{SubmissionID}/completed"
r.args = args
r.count = 1
return r, true
@@ -2495,68 +2137,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
}
}
case 'c': // Prefix: "com"
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'm': // Prefix: "ment"
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = CreateSubmissionAuditCommentOperation
r.summary = "Post a comment to the audit log"
r.operationID = "createSubmissionAuditComment"
r.pathPattern = "/submissions/{SubmissionID}/comment"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'p': // Prefix: "pleted"
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = SetSubmissionCompletedOperation
r.summary = "Called by maptest when a player completes the map"
r.operationID = "setSubmissionCompleted"
r.pathPattern = "/submissions/{SubmissionID}/completed"
r.args = args
r.count = 1
return r, true
default:
return
}
}
}
case 'm': // Prefix: "model"
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
@@ -2593,30 +2173,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" {
@@ -2689,30 +2245,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 's': // Prefix: "submitting"
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionSubmissionResetSubmittingOperation
r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction"
r.operationID = "actionSubmissionResetSubmitting"
r.pathPattern = "/submissions/{SubmissionID}/status/reset-submitting"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "uploading"
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
@@ -2813,6 +2345,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
}
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionSubmissionSubmitOperation
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
r.operationID = "actionSubmissionSubmit"
r.pathPattern = "/submissions/{SubmissionID}/status/submit"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 't': // Prefix: "trigger-"
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
@@ -2825,30 +2381,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break
}
switch elem[0] {
case 's': // Prefix: "submit"
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionSubmissionTriggerSubmitOperation
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting"
r.operationID = "actionSubmissionTriggerSubmit"
r.pathPattern = "/submissions/{SubmissionID}/status/trigger-submit"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "upload"
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {

View File

@@ -4,10 +4,7 @@ package api
import (
"fmt"
"io"
"time"
"github.com/go-faster/jx"
)
func (s *ErrorStatusCode) Error() string {
@@ -17,26 +14,20 @@ func (s *ErrorStatusCode) Error() string {
// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
type ActionMapfixAcceptedNoContent struct{}
// ActionMapfixBypassSubmitNoContent is response for ActionMapfixBypassSubmit operation.
type ActionMapfixBypassSubmitNoContent struct{}
// ActionMapfixRejectNoContent is response for ActionMapfixReject operation.
type ActionMapfixRejectNoContent struct{}
// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
type ActionMapfixRequestChangesNoContent struct{}
// ActionMapfixResetSubmittingNoContent is response for ActionMapfixResetSubmitting operation.
type ActionMapfixResetSubmittingNoContent struct{}
// ActionMapfixRetryValidateNoContent is response for ActionMapfixRetryValidate operation.
type ActionMapfixRetryValidateNoContent struct{}
// ActionMapfixRevokeNoContent is response for ActionMapfixRevoke operation.
type ActionMapfixRevokeNoContent struct{}
// ActionMapfixTriggerSubmitNoContent is response for ActionMapfixTriggerSubmit operation.
type ActionMapfixTriggerSubmitNoContent struct{}
// ActionMapfixSubmitNoContent is response for ActionMapfixSubmit operation.
type ActionMapfixSubmitNoContent struct{}
// ActionMapfixTriggerUploadNoContent is response for ActionMapfixTriggerUpload operation.
type ActionMapfixTriggerUploadNoContent struct{}
@@ -50,26 +41,20 @@ type ActionMapfixValidatedNoContent struct{}
// ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
type ActionSubmissionAcceptedNoContent struct{}
// ActionSubmissionBypassSubmitNoContent is response for ActionSubmissionBypassSubmit operation.
type ActionSubmissionBypassSubmitNoContent struct{}
// ActionSubmissionRejectNoContent is response for ActionSubmissionReject operation.
type ActionSubmissionRejectNoContent struct{}
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation.
type ActionSubmissionRequestChangesNoContent struct{}
// ActionSubmissionResetSubmittingNoContent is response for ActionSubmissionResetSubmitting operation.
type ActionSubmissionResetSubmittingNoContent struct{}
// ActionSubmissionRetryValidateNoContent is response for ActionSubmissionRetryValidate operation.
type ActionSubmissionRetryValidateNoContent struct{}
// ActionSubmissionRevokeNoContent is response for ActionSubmissionRevoke operation.
type ActionSubmissionRevokeNoContent struct{}
// ActionSubmissionTriggerSubmitNoContent is response for ActionSubmissionTriggerSubmit operation.
type ActionSubmissionTriggerSubmitNoContent struct{}
// ActionSubmissionSubmitNoContent is response for ActionSubmissionSubmit operation.
type ActionSubmissionSubmitNoContent struct{}
// ActionSubmissionTriggerUploadNoContent is response for ActionSubmissionTriggerUpload operation.
type ActionSubmissionTriggerUploadNoContent struct{}
@@ -80,115 +65,8 @@ type ActionSubmissionTriggerValidateNoContent struct{}
// ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation.
type ActionSubmissionValidatedNoContent struct{}
// Ref: #/components/schemas/AuditEvent
type AuditEvent struct {
ID int64 `json:"ID"`
Date int64 `json:"Date"`
User int64 `json:"User"`
Username string `json:"Username"`
// Is this a submission or is it a mapfix.
ResourceType int32 `json:"ResourceType"`
ResourceID int64 `json:"ResourceID"`
EventType int32 `json:"EventType"`
// Arbitrary event data.
EventData AuditEventEventData `json:"EventData"`
}
// GetID returns the value of ID.
func (s *AuditEvent) GetID() int64 {
return s.ID
}
// GetDate returns the value of Date.
func (s *AuditEvent) GetDate() int64 {
return s.Date
}
// GetUser returns the value of User.
func (s *AuditEvent) GetUser() int64 {
return s.User
}
// GetUsername returns the value of Username.
func (s *AuditEvent) GetUsername() string {
return s.Username
}
// GetResourceType returns the value of ResourceType.
func (s *AuditEvent) GetResourceType() int32 {
return s.ResourceType
}
// GetResourceID returns the value of ResourceID.
func (s *AuditEvent) GetResourceID() int64 {
return s.ResourceID
}
// GetEventType returns the value of EventType.
func (s *AuditEvent) GetEventType() int32 {
return s.EventType
}
// GetEventData returns the value of EventData.
func (s *AuditEvent) GetEventData() AuditEventEventData {
return s.EventData
}
// SetID sets the value of ID.
func (s *AuditEvent) SetID(val int64) {
s.ID = val
}
// SetDate sets the value of Date.
func (s *AuditEvent) SetDate(val int64) {
s.Date = val
}
// SetUser sets the value of User.
func (s *AuditEvent) SetUser(val int64) {
s.User = val
}
// SetUsername sets the value of Username.
func (s *AuditEvent) SetUsername(val string) {
s.Username = val
}
// SetResourceType sets the value of ResourceType.
func (s *AuditEvent) SetResourceType(val int32) {
s.ResourceType = val
}
// SetResourceID sets the value of ResourceID.
func (s *AuditEvent) SetResourceID(val int64) {
s.ResourceID = val
}
// SetEventType sets the value of EventType.
func (s *AuditEvent) SetEventType(val int32) {
s.EventType = val
}
// SetEventData sets the value of EventData.
func (s *AuditEvent) SetEventData(val AuditEventEventData) {
s.EventData = val
}
// Arbitrary event data.
type AuditEventEventData map[string]jx.Raw
func (s *AuditEventEventData) init() AuditEventEventData {
m := *s
if m == nil {
m = map[string]jx.Raw{}
*s = m
}
return m
}
type CookieAuth struct {
APIKey string
Roles []string
}
// GetAPIKey returns the value of APIKey.
@@ -196,55 +74,11 @@ func (s *CookieAuth) GetAPIKey() string {
return s.APIKey
}
// GetRoles returns the value of Roles.
func (s *CookieAuth) GetRoles() []string {
return s.Roles
}
// SetAPIKey sets the value of APIKey.
func (s *CookieAuth) SetAPIKey(val string) {
s.APIKey = val
}
// SetRoles sets the value of Roles.
func (s *CookieAuth) SetRoles(val []string) {
s.Roles = val
}
// CreateMapfixAuditCommentNoContent is response for CreateMapfixAuditComment operation.
type CreateMapfixAuditCommentNoContent struct{}
type CreateMapfixAuditCommentReq struct {
Data io.Reader
}
// Read reads data from the Data reader.
//
// Kept to satisfy the io.Reader interface.
func (s CreateMapfixAuditCommentReq) Read(p []byte) (n int, err error) {
if s.Data == nil {
return 0, io.EOF
}
return s.Data.Read(p)
}
// CreateSubmissionAuditCommentNoContent is response for CreateSubmissionAuditComment operation.
type CreateSubmissionAuditCommentNoContent struct{}
type CreateSubmissionAuditCommentReq struct {
Data io.Reader
}
// Read reads data from the Data reader.
//
// Kept to satisfy the io.Reader interface.
func (s CreateSubmissionAuditCommentReq) Read(p []byte) (n int, err error) {
if s.Data == nil {
return 0, io.EOF
}
return s.Data.Read(p)
}
// DeleteScriptNoContent is response for DeleteScript operation.
type DeleteScriptNoContent struct{}
@@ -377,7 +211,7 @@ type Mapfix struct {
Completed bool `json:"Completed"`
TargetAssetID int64 `json:"TargetAssetID"`
StatusID int32 `json:"StatusID"`
Description string `json:"Description"`
StatusMessage string `json:"StatusMessage"`
}
// GetID returns the value of ID.
@@ -440,9 +274,9 @@ func (s *Mapfix) GetStatusID() int32 {
return s.StatusID
}
// GetDescription returns the value of Description.
func (s *Mapfix) GetDescription() string {
return s.Description
// GetStatusMessage returns the value of StatusMessage.
func (s *Mapfix) GetStatusMessage() string {
return s.StatusMessage
}
// SetID sets the value of ID.
@@ -505,16 +339,15 @@ func (s *Mapfix) SetStatusID(val int32) {
s.StatusID = val
}
// SetDescription sets the value of Description.
func (s *Mapfix) SetDescription(val string) {
s.Description = val
// SetStatusMessage sets the value of StatusMessage.
func (s *Mapfix) SetStatusMessage(val string) {
s.StatusMessage = val
}
// Ref: #/components/schemas/MapfixTriggerCreate
type MapfixTriggerCreate struct {
AssetID int64 `json:"AssetID"`
TargetAssetID int64 `json:"TargetAssetID"`
Description string `json:"Description"`
AssetID int64 `json:"AssetID"`
TargetAssetID int64 `json:"TargetAssetID"`
}
// GetAssetID returns the value of AssetID.
@@ -527,11 +360,6 @@ func (s *MapfixTriggerCreate) GetTargetAssetID() int64 {
return s.TargetAssetID
}
// GetDescription returns the value of Description.
func (s *MapfixTriggerCreate) GetDescription() string {
return s.Description
}
// SetAssetID sets the value of AssetID.
func (s *MapfixTriggerCreate) SetAssetID(val int64) {
s.AssetID = val
@@ -542,37 +370,6 @@ func (s *MapfixTriggerCreate) SetTargetAssetID(val int64) {
s.TargetAssetID = val
}
// SetDescription sets the value of Description.
func (s *MapfixTriggerCreate) SetDescription(val string) {
s.Description = val
}
// Ref: #/components/schemas/Mapfixes
type Mapfixes struct {
Total int64 `json:"Total"`
Mapfixes []Mapfix `json:"Mapfixes"`
}
// GetTotal returns the value of Total.
func (s *Mapfixes) GetTotal() int64 {
return s.Total
}
// GetMapfixes returns the value of Mapfixes.
func (s *Mapfixes) GetMapfixes() []Mapfix {
return s.Mapfixes
}
// SetTotal sets the value of Total.
func (s *Mapfixes) SetTotal(val int64) {
s.Total = val
}
// SetMapfixes sets the value of Mapfixes.
func (s *Mapfixes) SetMapfixes(val []Mapfix) {
s.Mapfixes = val
}
// Ref: #/components/schemas/Operation
type Operation struct {
OperationID int32 `json:"OperationID"`
@@ -1202,6 +999,7 @@ type Submission struct {
Completed bool `json:"Completed"`
UploadedAssetID OptInt64 `json:"UploadedAssetID"`
StatusID int32 `json:"StatusID"`
StatusMessage string `json:"StatusMessage"`
}
// GetID returns the value of ID.
@@ -1274,6 +1072,11 @@ func (s *Submission) GetStatusID() int32 {
return s.StatusID
}
// GetStatusMessage returns the value of StatusMessage.
func (s *Submission) GetStatusMessage() string {
return s.StatusMessage
}
// SetID sets the value of ID.
func (s *Submission) SetID(val int64) {
s.ID = val
@@ -1344,12 +1147,14 @@ func (s *Submission) SetStatusID(val int32) {
s.StatusID = val
}
// SetStatusMessage sets the value of StatusMessage.
func (s *Submission) SetStatusMessage(val string) {
s.StatusMessage = val
}
// Ref: #/components/schemas/SubmissionTriggerCreate
type SubmissionTriggerCreate struct {
AssetID int64 `json:"AssetID"`
DisplayName string `json:"DisplayName"`
Creator string `json:"Creator"`
GameID int32 `json:"GameID"`
AssetID int64 `json:"AssetID"`
}
// GetAssetID returns the value of AssetID.
@@ -1357,67 +1162,11 @@ func (s *SubmissionTriggerCreate) GetAssetID() int64 {
return s.AssetID
}
// GetDisplayName returns the value of DisplayName.
func (s *SubmissionTriggerCreate) GetDisplayName() string {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *SubmissionTriggerCreate) GetCreator() string {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *SubmissionTriggerCreate) GetGameID() int32 {
return s.GameID
}
// SetAssetID sets the value of AssetID.
func (s *SubmissionTriggerCreate) SetAssetID(val int64) {
s.AssetID = val
}
// SetDisplayName sets the value of DisplayName.
func (s *SubmissionTriggerCreate) SetDisplayName(val string) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *SubmissionTriggerCreate) SetCreator(val string) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *SubmissionTriggerCreate) SetGameID(val int32) {
s.GameID = val
}
// Ref: #/components/schemas/Submissions
type Submissions struct {
Total int64 `json:"Total"`
Submissions []Submission `json:"Submissions"`
}
// GetTotal returns the value of Total.
func (s *Submissions) GetTotal() int64 {
return s.Total
}
// GetSubmissions returns the value of Submissions.
func (s *Submissions) GetSubmissions() []Submission {
return s.Submissions
}
// SetTotal sets the value of Total.
func (s *Submissions) SetTotal(val int64) {
s.Total = val
}
// SetSubmissions sets the value of Submissions.
func (s *Submissions) SetSubmissions(val []Submission) {
s.Submissions = val
}
// UpdateMapfixModelNoContent is response for UpdateMapfixModel operation.
type UpdateMapfixModelNoContent struct{}

View File

@@ -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

View File

@@ -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.
@@ -32,13 +26,6 @@ type Handler interface {
//
// POST /mapfixes/{MapfixID}/status/request-changes
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/reset-submitting
ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
@@ -51,12 +38,12 @@ type Handler interface {
//
// POST /mapfixes/{MapfixID}/status/revoke
ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
// ActionMapfixSubmit implements actionMapfixSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit
ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error
// POST /mapfixes/{MapfixID}/status/submit
ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error
// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
@@ -81,12 +68,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.
@@ -99,13 +80,6 @@ type Handler interface {
//
// POST /submissions/{SubmissionID}/status/request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/reset-submitting
ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
@@ -118,12 +92,12 @@ type Handler interface {
//
// POST /submissions/{SubmissionID}/status/revoke
ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
// ActionSubmissionSubmit implements actionSubmissionSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /submissions/{SubmissionID}/status/trigger-submit
ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error
// POST /submissions/{SubmissionID}/status/submit
ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error
// ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
@@ -148,12 +122,6 @@ type Handler interface {
//
// POST /mapfixes
CreateMapfix(ctx context.Context, req *MapfixTriggerCreate) (*OperationID, error)
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /mapfixes/{MapfixID}/comment
CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error
// CreateScript implements createScript operation.
//
// Create a new script.
@@ -172,18 +140,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.
//
// POST /submissions/{SubmissionID}/comment
CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
@@ -232,18 +188,12 @@ type Handler interface {
//
// GET /submissions/{SubmissionID}
GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /mapfixes/{MapfixID}/audit-events
ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) ([]AuditEvent, error)
// ListMapfixes implements listMapfixes operation.
//
// Get list of mapfixes.
//
// GET /mapfixes
ListMapfixes(ctx context.Context, params ListMapfixesParams) (*Mapfixes, error)
ListMapfixes(ctx context.Context, params ListMapfixesParams) ([]Mapfix, error)
// ListMaps implements listMaps operation.
//
// Get list of maps.
@@ -262,18 +212,12 @@ type Handler interface {
//
// GET /scripts
ListScripts(ctx context.Context, params ListScriptsParams) ([]Script, error)
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) ([]AuditEvent, error)
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error)
ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error)
// ReleaseSubmissions implements releaseSubmissions operation.
//
// Release a set of uploaded maps.

View File

@@ -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.
@@ -49,16 +40,6 @@ func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, para
return ht.ErrNotImplemented
}
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/reset-submitting
func (UnimplementedHandler) ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
@@ -77,12 +58,12 @@ func (UnimplementedHandler) ActionMapfixRevoke(ctx context.Context, params Actio
return ht.ErrNotImplemented
}
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
// ActionMapfixSubmit implements actionMapfixSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit
func (UnimplementedHandler) ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error {
// POST /mapfixes/{MapfixID}/status/submit
func (UnimplementedHandler) ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error {
return ht.ErrNotImplemented
}
@@ -122,15 +103,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.
@@ -149,16 +121,6 @@ func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context,
return ht.ErrNotImplemented
}
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/reset-submitting
func (UnimplementedHandler) ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
@@ -177,12 +139,12 @@ func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params A
return ht.ErrNotImplemented
}
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
// ActionSubmissionSubmit implements actionSubmissionSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /submissions/{SubmissionID}/status/trigger-submit
func (UnimplementedHandler) ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error {
// POST /submissions/{SubmissionID}/status/submit
func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error {
return ht.ErrNotImplemented
}
@@ -222,15 +184,6 @@ func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixTrigger
return r, ht.ErrNotImplemented
}
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /mapfixes/{MapfixID}/comment
func (UnimplementedHandler) CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error {
return ht.ErrNotImplemented
}
// CreateScript implements createScript operation.
//
// Create a new script.
@@ -258,24 +211,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.
//
// POST /submissions/{SubmissionID}/comment
func (UnimplementedHandler) CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error {
return ht.ErrNotImplemented
}
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
@@ -348,21 +283,12 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss
return r, ht.ErrNotImplemented
}
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /mapfixes/{MapfixID}/audit-events
func (UnimplementedHandler) ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) (r []AuditEvent, _ error) {
return r, ht.ErrNotImplemented
}
// ListMapfixes implements listMapfixes operation.
//
// Get list of mapfixes.
//
// GET /mapfixes
func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r *Mapfixes, _ error) {
func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r []Mapfix, _ error) {
return r, ht.ErrNotImplemented
}
@@ -393,21 +319,12 @@ func (UnimplementedHandler) ListScripts(ctx context.Context, params ListScriptsP
return r, ht.ErrNotImplemented
}
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
func (UnimplementedHandler) ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) (r []AuditEvent, _ error) {
return r, ht.ErrNotImplemented
}
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r *Submissions, _ error) {
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r []Submission, _ error) {
return r, ht.ErrNotImplemented
}

File diff suppressed because it is too large Load Diff

View File

@@ -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()))

View File

@@ -3,8 +3,6 @@ package datastore
import (
"context"
"errors"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
@@ -24,7 +22,6 @@ const (
)
type Datastore interface {
AuditEvents() AuditEvents
Mapfixes() Mapfixes
Operations() Operations
Submissions() Submissions
@@ -32,14 +29,6 @@ type Datastore interface {
ScriptPolicy() ScriptPolicy
}
type AuditEvents interface {
Get(ctx context.Context, id int64) (model.AuditEvent, error)
Create(ctx context.Context, smap model.AuditEvent) (model.AuditEvent, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.AuditEvent, error)
}
type Mapfixes interface {
Get(ctx context.Context, id int64) (model.Mapfix, error)
GetList(ctx context.Context, id []int64) ([]model.Mapfix, error)
@@ -49,7 +38,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)
ListRestricted(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort, submitter int64) ([]model.Mapfix, error)
}
type Operations interface {
@@ -57,7 +46,6 @@ type Operations interface {
Create(ctx context.Context, smap model.Operation) (model.Operation, error)
Update(ctx context.Context, id int32, values OptionalMap) error
Delete(ctx context.Context, id int32) error
CountSince(ctx context.Context, owner int64, since time.Time) (int64, error)
}
type Submissions interface {
@@ -69,7 +57,7 @@ type Submissions interface {
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) (model.Submission, error)
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Submission, error)
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Submission, error)
ListRestricted(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort, submitter int64) ([]model.Submission, error)
}
type Scripts interface {

View File

@@ -1,64 +0,0 @@
package gormstore
import (
"context"
"errors"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm"
)
type AuditEvents struct {
db *gorm.DB
}
func (env *AuditEvents) Get(ctx context.Context, id int64) (model.AuditEvent, error) {
var mdl model.AuditEvent
if err := env.db.First(&mdl, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
return mdl, err
}
return mdl, nil
}
func (env *AuditEvents) Create(ctx context.Context, smap model.AuditEvent) (model.AuditEvent, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *AuditEvents) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.AuditEvent{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *AuditEvents) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.AuditEvent{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *AuditEvents) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.AuditEvent, error) {
var events []model.AuditEvent
if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil {
return nil, err
}
return events, nil
}

View File

@@ -31,7 +31,6 @@ func New(ctx *cli.Context) (datastore.Datastore, error) {
if ctx.Bool("migrate") {
if err := db.AutoMigrate(
&model.AuditEvent{},
&model.Mapfix{},
&model.Operation{},
&model.Submission{},

View File

@@ -9,10 +9,6 @@ type Gormstore struct {
db *gorm.DB
}
func (g Gormstore) AuditEvents() datastore.AuditEvents {
return &AuditEvents{db: g.db}
}
func (g Gormstore) Mapfixes() datastore.Mapfixes {
return &Mapfixes{db: g.db}
}

View File

@@ -131,18 +131,39 @@ 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) {
// grab page items
maps, err := env.List(ctx, filters, page, sort)
if err != nil{
return 0, nil, err
func (env *Mapfixes) ListRestricted(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort, submitter int64) ([]model.Mapfix, error) {
var maps []model.Mapfix
db := env.db
switch sort {
case datastore.ListSortDisabled:
// No sort
break
case datastore.ListSortDisplayNameAscending:
db=db.Order("display_name ASC")
break
case datastore.ListSortDisplayNameDescending:
db=db.Order("display_name DESC")
break
case datastore.ListSortDateAscending:
db=db.Order("created_at ASC")
break
case datastore.ListSortDateDescending:
db=db.Order("created_at DESC")
break
default:
return nil, datastore.ErrInvalidListSort
}
// count total with filters
var total int64
if err := env.db.Model(&model.Mapfix{}).Where(filters.Map()).Count(&total).Error; err != nil {
return 0, nil, err
if err := db.
Where(filters.Map()).
Where("status_id NOT IN ? OR submitter = ? AND status_id IN ?",PrivateSubmissions,submitter,PrivateSubmissions).
Offset(int((page.Number - 1) * page.Size)).
Limit(int(page.Size)).
Find(&maps).Error; err != nil {
return nil, err
}
return total, maps, nil
return maps, nil
}

View File

@@ -3,7 +3,6 @@ package gormstore
import (
"context"
"errors"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
@@ -54,12 +53,3 @@ func (env *Operations) Delete(ctx context.Context, id int32) error {
return nil
}
func (env *Operations) CountSince(ctx context.Context, owner int64, since time.Time) (int64, error) {
var count int64
if err := env.db.Model(&model.Operation{}).Where("owner = ? AND created_at > ?",owner,since).Count(&count).Error; err != nil {
return count, err
}
return count, nil
}

View File

@@ -10,6 +10,13 @@ import (
"gorm.io/gorm/clause"
)
var(
PrivateSubmissions = []model.SubmissionStatus{
model.SubmissionStatusUnderConstruction,
model.SubmissionStatusChangesRequested,
}
)
type Submissions struct {
db *gorm.DB
}
@@ -131,18 +138,43 @@ func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap,
return maps, nil
}
func (env *Submissions) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Submission, error) {
// grab page items
maps, err := env.List(ctx, filters, page, sort)
if err != nil{
return 0, nil, err
func (env *Submissions) ListRestricted(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort, submitter int64) ([]model.Submission, error) {
var maps []model.Submission
db := env.db
switch sort {
case datastore.ListSortDisabled:
// No sort
break
case datastore.ListSortDisplayNameAscending:
db=db.Order("display_name ASC")
break
case datastore.ListSortDisplayNameDescending:
db=db.Order("display_name DESC")
break
case datastore.ListSortDateAscending:
db=db.Order("created_at ASC")
break
case datastore.ListSortDateDescending:
db=db.Order("created_at DESC")
break
default:
return nil, datastore.ErrInvalidListSort
}
// count total with filters
var total int64
if err := env.db.Model(&model.Submission{}).Where(filters.Map()).Count(&total).Error; err != nil {
return 0, nil, err
if err := db.
Where(filters.Map()).
// In order to see submissions,
// at least one of two criteria must be met:
// - You are the submitter
// - The submission is not under construction / changes requested
Where("status_id NOT IN ? OR submitter = ? AND status_id IN ?",PrivateSubmissions,submitter,PrivateSubmissions).
Offset(int((page.Number - 1) * page.Size)).
Limit(int(page.Size)).
Find(&maps).Error; err != nil {
return nil, err
}
return total, maps, nil
return maps, nil
}

View File

@@ -34,18 +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.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error
// ActionMapfixUploaded invokes actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -70,18 +58,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.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error
// ActionSubmissionUploaded invokes actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -269,15 +245,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,266 +282,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.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (c *Client) ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error {
_, err := c.sendActionMapfixSubmitted(ctx, params)
return err
}
func (c *Client) sendActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) (res *ActionMapfixSubmittedNoContent, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionMapfixSubmitted"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-submitted"),
}
// 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, ActionMapfixSubmittedOperation,
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-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 {
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 := decodeActionMapfixSubmittedResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// ActionMapfixUploaded invokes actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -929,15 +645,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,266 +682,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.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (c *Client) ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error {
_, err := c.sendActionSubmissionSubmitted(ctx, params)
return err
}
func (c *Client) sendActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) (res *ActionSubmissionSubmittedNoContent, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionSubmissionSubmitted"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-submitted"),
}
// 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, ActionSubmissionSubmittedOperation,
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-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 {
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 := decodeActionSubmissionSubmittedResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// ActionSubmissionUploaded invokes actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.

View File

@@ -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,324 +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.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (s *Server) handleActionMapfixSubmittedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionMapfixSubmitted"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-submitted"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixSubmittedOperation,
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: ActionMapfixSubmittedOperation,
ID: "actionMapfixSubmitted",
}
)
params, err := decodeActionMapfixSubmittedParams(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 *ActionMapfixSubmittedNoContent
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: ActionMapfixSubmittedOperation,
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> Submitted",
OperationID: "actionMapfixSubmitted",
Body: nil,
Params: middleware.Parameters{
{
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,
}
type (
Request = struct{}
Params = ActionMapfixSubmittedParams
Response = *ActionMapfixSubmittedNoContent
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackActionMapfixSubmittedParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.ActionMapfixSubmitted(ctx, params)
return response, err
},
)
} else {
err = s.h.ActionMapfixSubmitted(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 := encodeActionMapfixSubmittedResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleActionMapfixUploadedRequest handles actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -1051,9 +733,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,324 +787,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.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (s *Server) handleActionSubmissionSubmittedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
statusWriter := &codeRecorder{ResponseWriter: w}
w = statusWriter
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("actionSubmissionSubmitted"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-submitted"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionSubmittedOperation,
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: ActionSubmissionSubmittedOperation,
ID: "actionSubmissionSubmitted",
}
)
params, err := decodeActionSubmissionSubmittedParams(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 *ActionSubmissionSubmittedNoContent
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: ActionSubmissionSubmittedOperation,
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> Submitted",
OperationID: "actionSubmissionSubmitted",
Body: nil,
Params: middleware.Parameters{
{
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,
}
type (
Request = struct{}
Params = ActionSubmissionSubmittedParams
Response = *ActionSubmissionSubmittedNoContent
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackActionSubmissionSubmittedParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.ActionSubmissionSubmitted(ctx, params)
return response, err
},
)
} else {
err = s.h.ActionSubmissionSubmitted(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 := encodeActionSubmissionSubmittedResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleActionSubmissionUploadedRequest handles actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.

View File

@@ -166,13 +166,9 @@ func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
e.FieldStart("TargetAssetID")
e.Int64(s.TargetAssetID)
}
{
e.FieldStart("Description")
e.Str(s.Description)
}
}
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,7 +184,7 @@ 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) {
@@ -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.
@@ -1323,17 +1305,9 @@ func (s *SubmissionCreate) encodeFields(e *jx.Encoder) {
e.FieldStart("AssetVersion")
e.Int64(s.AssetVersion)
}
{
e.FieldStart("Status")
e.UInt32(s.Status)
}
{
e.FieldStart("Roles")
e.UInt32(s.Roles)
}
}
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,7 +1322,7 @@ 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) {
@@ -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.

View File

@@ -7,14 +7,10 @@ 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"
CreateMapfixOperation OperationName = "CreateMapfix"

File diff suppressed because it is too large Load Diff

View File

@@ -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"))
@@ -213,14 +214,6 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
}
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)
@@ -238,13 +231,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"))

View File

@@ -52,135 +52,6 @@ func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixA
}
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 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:
// Code 204.
return &ActionMapfixSubmittedNoContent{}, 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,
@@ -232,15 +103,6 @@ func decodeActionMapfixUploadedResponse(resp *http.Response) (res *ActionMapfixU
}
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,
@@ -292,15 +154,6 @@ func decodeActionMapfixValidatedResponse(resp *http.Response) (res *ActionMapfix
}
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,
@@ -352,15 +205,6 @@ func decodeActionOperationFailedResponse(resp *http.Response) (res *ActionOperat
}
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,
@@ -412,135 +256,6 @@ func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSub
}
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 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:
// Code 204.
return &ActionSubmissionSubmittedNoContent{}, 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,
@@ -592,15 +307,6 @@ func decodeActionSubmissionUploadedResponse(resp *http.Response) (res *ActionSub
}
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,
@@ -652,15 +358,6 @@ func decodeActionSubmissionValidatedResponse(resp *http.Response) (res *ActionSu
}
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,
@@ -708,15 +405,6 @@ func decodeCreateMapfixResponse(resp *http.Response) (res *MapfixID, _ error) {
}
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)
@@ -753,15 +441,6 @@ func decodeCreateMapfixResponse(resp *http.Response) (res *MapfixID, _ error) {
}
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,
@@ -809,15 +488,6 @@ func decodeCreateScriptResponse(resp *http.Response) (res *ScriptID, _ error) {
}
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)
@@ -854,15 +524,6 @@ func decodeCreateScriptResponse(resp *http.Response) (res *ScriptID, _ error) {
}
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,
@@ -910,15 +571,6 @@ func decodeCreateScriptPolicyResponse(resp *http.Response) (res *ScriptPolicyID,
}
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)
@@ -955,15 +607,6 @@ func decodeCreateScriptPolicyResponse(resp *http.Response) (res *ScriptPolicyID,
}
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,
@@ -1011,15 +654,6 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *SubmissionID, _ e
}
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)
@@ -1056,15 +690,6 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *SubmissionID, _ e
}
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,
@@ -1157,15 +782,6 @@ func decodeGetScriptResponse(resp *http.Response) (res *Script, _ error) {
}
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,
@@ -1283,15 +899,6 @@ func decodeListScriptPolicyResponse(resp *http.Response) (res []ScriptPolicy, _
}
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,
@@ -1409,15 +1016,6 @@ func decodeListScriptsResponse(resp *http.Response) (res []Script, _ error) {
}
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,
@@ -1469,15 +1067,6 @@ func decodeUpdateMapfixValidatedModelResponse(resp *http.Response) (res *UpdateM
}
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,
@@ -1529,15 +1118,6 @@ func decodeUpdateSubmissionValidatedModelResponse(resp *http.Response) (res *Upd
}
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,

View File

@@ -20,20 +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))
return nil
}
func encodeActionMapfixUploadedResponse(response *ActionMapfixUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -62,20 +48,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))
return nil
}
func encodeActionSubmissionUploadedResponse(response *ActionSubmissionUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))

View File

@@ -147,50 +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" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionMapfixSubmittedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "uploaded"
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
@@ -498,50 +454,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" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionSubmissionSubmittedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
case 'u': // Prefix: "uploaded"
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
@@ -804,54 +716,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" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionMapfixSubmittedOperation
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> Submitted"
r.operationID = "actionMapfixSubmitted"
r.pathPattern = "/mapfixes/{MapfixID}/status/validator-submitted"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "uploaded"
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
@@ -1195,54 +1059,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" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionSubmissionSubmittedOperation
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> Submitted"
r.operationID = "actionSubmissionSubmitted"
r.pathPattern = "/submissions/{SubmissionID}/status/validator-submitted"
r.args = args
r.count = 1
return r, true
default:
return
}
}
case 'u': // Prefix: "uploaded"
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {

View File

@@ -13,12 +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{}
// ActionMapfixUploadedNoContent is response for ActionMapfixUploaded operation.
type ActionMapfixUploadedNoContent struct{}
@@ -31,12 +25,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{}
// ActionSubmissionUploadedNoContent is response for ActionSubmissionUploaded operation.
type ActionSubmissionUploadedNoContent struct{}
@@ -106,7 +94,6 @@ type MapfixCreate struct {
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
TargetAssetID int64 `json:"TargetAssetID"`
Description string `json:"Description"`
}
// GetOperationID returns the value of OperationID.
@@ -149,11 +136,6 @@ func (s *MapfixCreate) GetTargetAssetID() int64 {
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) {
s.OperationID = val
@@ -194,11 +176,6 @@ func (s *MapfixCreate) SetTargetAssetID(val int64) {
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"`
@@ -594,8 +571,6 @@ type SubmissionCreate struct {
GameID int32 `json:"GameID"`
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
Status uint32 `json:"Status"`
Roles uint32 `json:"Roles"`
}
// GetOperationID returns the value of OperationID.
@@ -633,16 +608,6 @@ func (s *SubmissionCreate) GetAssetVersion() int64 {
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) {
s.OperationID = val
@@ -678,16 +643,6 @@ func (s *SubmissionCreate) SetAssetVersion(val int64) {
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"`

View File

@@ -14,18 +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.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -50,18 +38,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.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.

View File

@@ -22,24 +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.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (UnimplementedHandler) ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
@@ -76,24 +58,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.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (UnimplementedHandler) ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.

View File

@@ -8,107 +8,12 @@ import (
"github.com/ogen-go/ogen/validate"
)
func (s *Error) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.Code)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "code",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ErrorStatusCode) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := s.Response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Response",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *MapfixCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.OperationID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "OperationID",
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.AssetOwner)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetOwner",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
@@ -147,137 +52,6 @@ func (s *MapfixCreate) Validate() error {
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 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.AssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetID",
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.AssetVersion)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetVersion",
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.TargetAssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "TargetAssetID",
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}
}
return nil
}
func (s *MapfixID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.MapfixID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "MapfixID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
@@ -290,26 +64,6 @@ func (s *Script) Validate() error {
}
var failures []validate.FieldError
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.ID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ID",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
@@ -367,46 +121,6 @@ func (s *Script) Validate() error {
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.ResourceType)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceType",
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.ResourceID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
@@ -457,85 +171,6 @@ func (s *ScriptCreate) Validate() error {
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.ResourceType)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceType",
Error: err,
})
}
if err := func() error {
if value, ok := s.ResourceID.Get(); ok {
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(value)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.ScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ScriptID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
@@ -548,26 +183,6 @@ func (s *ScriptPolicy) Validate() error {
}
var failures []validate.FieldError
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.ID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ID",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 16,
@@ -587,150 +202,6 @@ func (s *ScriptPolicy) Validate() error {
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.ToScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ToScriptID",
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.Policy)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Policy",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicyCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.FromScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "FromScriptID",
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.ToScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ToScriptID",
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.Policy)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Policy",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicyID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.ScriptPolicyID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ScriptPolicyID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
@@ -743,46 +214,6 @@ func (s *SubmissionCreate) Validate() error {
}
var failures []validate.FieldError
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.OperationID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "OperationID",
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.AssetOwner)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetOwner",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
@@ -821,118 +252,6 @@ func (s *SubmissionCreate) Validate() error {
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 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.AssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetID",
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.AssetVersion)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetVersion",
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}
}
return nil
}
func (s *SubmissionID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
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.SubmissionID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "SubmissionID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}

View File

@@ -1,59 +0,0 @@
package model
import (
"encoding/json"
"time"
)
type AuditEventType int32
// User clicked "Submit", "Accept" etc
const AuditEventTypeAction AuditEventType = 0
type AuditEventDataAction struct {
TargetStatus uint32 `json:"target_status"`
}
// User wrote a comment
const AuditEventTypeComment AuditEventType = 1
type AuditEventDataComment struct {
Comment string `json:"comment"`
}
// User changed Model
const AuditEventTypeChangeModel AuditEventType = 2
type AuditEventDataChangeModel struct {
OldModelID uint64 `json:"old_model_id"`
OldModelVersion uint64 `json:"old_model_version"`
NewModelID uint64 `json:"new_model_id"`
NewModelVersion uint64 `json:"new_model_version"`
}
// Validator validates model
const AuditEventTypeChangeValidatedModel AuditEventType = 3
type AuditEventDataChangeValidatedModel struct {
ValidatedModelID uint64 `json:"validated_model_id"`
ValidatedModelVersion uint64 `json:"validated_model_version"`
}
// User changed DisplayName / Creator
const AuditEventTypeChangeDisplayName AuditEventType = 4
const AuditEventTypeChangeCreator AuditEventType = 5
type AuditEventDataChangeName struct {
OldName string `json:"old_name"`
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"`
CreatedAt time.Time
User uint64
ResourceType ResourceType // is this a submission or is it a mapfix
ResourceID int64 // submission / mapfix / map ID
EventType AuditEventType
EventData json.RawMessage `gorm:"type:jsonb"`
}

View File

@@ -5,39 +5,36 @@ import "time"
type MapfixStatus int32
const (
// Phase: Creation
MapfixStatusUnderConstruction MapfixStatus = 0
MapfixStatusChangesRequested MapfixStatus = 1
// Phase: Review
MapfixStatusSubmitting MapfixStatus = 2
MapfixStatusSubmitted MapfixStatus = 3
// Phase: Final MapfixStatus
MapfixStatusRejected MapfixStatus = 8
MapfixStatusUploaded MapfixStatus = 7 // uploaded to the group, final status for mapfixes
// Phase: Testing
MapfixStatusAcceptedUnvalidated MapfixStatus = 4 // pending script review, can re-trigger validation
MapfixStatusValidating MapfixStatus = 5
MapfixStatusValidated MapfixStatus = 6
MapfixStatusUploading MapfixStatus = 7
MapfixStatusUploading MapfixStatus = 6
MapfixStatusValidated MapfixStatus = 5
MapfixStatusValidating MapfixStatus = 4
MapfixStatusAccepted MapfixStatus = 3 // pending script review, can re-trigger validation
// Phase: Final MapfixStatus
MapfixStatusUploaded MapfixStatus = 8 // uploaded to the group, but pending release
MapfixStatusRejected MapfixStatus = 9
// Phase: Creation
MapfixStatusChangesRequested MapfixStatus = 2
MapfixStatusSubmitted MapfixStatus = 1
MapfixStatusUnderConstruction MapfixStatus = 0
)
type Mapfix struct {
ID int64 `gorm:"primaryKey"`
DisplayName string
Creator string
GameID uint32
GameID int32
CreatedAt time.Time
UpdatedAt time.Time
Submitter uint64 // UserID
AssetID uint64
AssetVersion uint64
ValidatedAssetID uint64
ValidatedAssetVersion uint64
Submitter int64 // UserID
AssetID int64
AssetVersion int64
ValidatedAssetID int64
ValidatedAssetVersion int64
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.
TargetAssetID int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
StatusID MapfixStatus
Description string // mapfix description
StatusMessage string
}

View File

@@ -7,59 +7,42 @@ package model
type CreateSubmissionRequest struct {
// operation_id is passed back in the response message
OperationID int32
ModelID uint64
DisplayName string
Creator string
GameID uint32
Status uint32
Roles uint32
OperationID int32
ModelID int64
}
type CreateMapfixRequest struct {
OperationID int32
ModelID uint64
TargetAssetID uint64
Description string
}
type CheckSubmissionRequest struct{
SubmissionID int64
ModelID uint64
}
type CheckMapfixRequest struct{
MapfixID int64
ModelID uint64
OperationID int32
ModelID int64
TargetAssetID int64
}
type ValidateSubmissionRequest struct {
// submission_id is passed back in the response message
SubmissionID int64
ModelID uint64
ModelVersion uint64
ValidatedModelID *uint64 // optional value
SubmissionID int64
ModelID int64
ModelVersion int64
ValidatedModelID *int64 // optional value
}
type ValidateMapfixRequest struct {
MapfixID int64
ModelID uint64
ModelVersion uint64
ValidatedModelID *uint64 // optional value
MapfixID int64
ModelID int64
ModelVersion int64
ValidatedModelID *int64 // optional value
}
// Create a new map
type UploadSubmissionRequest struct {
SubmissionID int64
ModelID uint64
ModelVersion uint64
SubmissionID int64
ModelID int64
ModelVersion int64
ModelName string
}
type UploadMapfixRequest struct {
MapfixID int64
ModelID uint64
ModelVersion uint64
TargetAssetID uint64
MapfixID int64
ModelID int64
ModelVersion int64
TargetAssetID int64
}

View File

@@ -12,7 +12,7 @@ const (
type Operation struct {
ID int32 `gorm:"primaryKey"`
CreatedAt time.Time
Owner uint64 // UserID
Owner int64 // UserID
StatusID OperationStatus
StatusMessage string
Path string // redirect to view completed operation e.g. "/mapfixes/4"

View File

@@ -5,39 +5,37 @@ import "time"
type SubmissionStatus int32
const (
// Phase: Creation
SubmissionStatusUnderConstruction SubmissionStatus = 0
SubmissionStatusChangesRequested SubmissionStatus = 1
// Phase: Review
SubmissionStatusSubmitting SubmissionStatus = 2
SubmissionStatusSubmitted SubmissionStatus = 3
// Phase: Final SubmissionStatus
SubmissionStatusReleased SubmissionStatus = 9
SubmissionStatusRejected SubmissionStatus = 8
// Phase: Testing
SubmissionStatusAcceptedUnvalidated SubmissionStatus = 4 // pending script review, can re-trigger validation
SubmissionStatusValidating SubmissionStatus = 5
SubmissionStatusValidated SubmissionStatus = 6
SubmissionStatusUploading SubmissionStatus = 7
SubmissionStatusUploaded SubmissionStatus = 8 // uploaded to the group, but pending release
SubmissionStatusUploaded SubmissionStatus = 7 // uploaded to the group, but pending release
SubmissionStatusUploading SubmissionStatus = 6
SubmissionStatusValidated SubmissionStatus = 5
SubmissionStatusValidating SubmissionStatus = 4
SubmissionStatusAccepted SubmissionStatus = 3 // pending script review, can re-trigger validation
// Phase: Final SubmissionStatus
SubmissionStatusRejected SubmissionStatus = 9
SubmissionStatusReleased SubmissionStatus = 10
// Phase: Creation
SubmissionStatusChangesRequested SubmissionStatus = 2
SubmissionStatusSubmitted SubmissionStatus = 1
SubmissionStatusUnderConstruction SubmissionStatus = 0
)
type Submission struct {
ID int64 `gorm:"primaryKey"`
DisplayName string
Creator string
GameID uint32
GameID int32
CreatedAt time.Time
UpdatedAt time.Time
Submitter uint64 // UserID
AssetID uint64
AssetVersion uint64
ValidatedAssetID uint64
ValidatedAssetVersion uint64
Submitter int64 // UserID
AssetID int64
AssetVersion int64
ValidatedAssetID int64
ValidatedAssetVersion int64
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.
UploadedAssetID int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
StatusID SubmissionStatus
StatusMessage string
}

View File

@@ -1,271 +0,0 @@
package service
import (
"context"
"encoding/json"
"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"
)
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log
//
// POST /mapfixes/{MapfixID}/comment
func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.CreateMapfixAuditCommentReq, params api.CreateMapfixAuditCommentParams) (error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleMapfixReview()
if err != nil {
return err
}
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 := []byte{}
_, err = req.Read(data)
if err != nil {
return err
}
Comment := string(data)
event_data := model.AuditEventDataComment{
Comment: Comment,
}
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.AuditEventTypeComment,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ListMapfixAuditEvents invokes listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /mapfixes/{MapfixID}/audit-events
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)
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
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{}
err = EventData.UnmarshalJSON(item.EventData)
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),
ResourceID: item.ResourceID,
EventType: int32(item.EventType),
EventData: EventData,
})
}
return resp, nil
}
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
//
// Post a comment to the audit log
//
// POST /submissions/{SubmissionID}/comment
func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.CreateSubmissionAuditCommentReq, params api.CreateSubmissionAuditCommentParams) (error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleSubmissionReview()
if err != nil {
return err
}
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 := []byte{}
_, err = req.Read(data)
if err != nil {
return err
}
Comment := string(data)
event_data := model.AuditEventDataComment{
Comment: Comment,
}
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.AuditEventTypeComment,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ListSubmissionAuditEvents invokes listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
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)
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
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{}
err = EventData.UnmarshalJSON(item.EventData)
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),
ResourceID: item.ResourceID,
EventType: int32(item.EventType),
EventData: EventData,
})
}
return resp, nil
}

View File

@@ -25,29 +25,18 @@ var(
model.MapfixStatusUploading,
model.MapfixStatusValidated,
model.MapfixStatusValidating,
model.MapfixStatusAcceptedUnvalidated,
model.MapfixStatusAccepted,
}
// Allow 5 mapfixes every 10 minutes
CreateMapfixRateLimit int64 = 5
CreateMapfixRecencyWindow = time.Second*600
)
var (
ErrCreationPhaseMapfixesLimit = errors.New("Active mapfixes limited to 20")
ErrActiveMapfixSameTargetAssetID = errors.New("There is an active mapfix with the same TargetAssetID")
ErrAcceptOwnMapfix = fmt.Errorf("%w: You cannot accept your own mapfix as the submitter", ErrPermissionDenied)
ErrCreateMapfixRateLimit = errors.New("You must not create more than 5 mapfixes every 10 minutes")
)
// POST /mapfixes
func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTriggerCreate) (*api.OperationID, error) {
// sanitization
if request.AssetID<0 || request.TargetAssetID<0{
return nil, ErrNegativeID
}
var ModelID=uint64(request.AssetID);
var TargetAssetID=uint64(request.TargetAssetID);
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
@@ -78,7 +67,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 {
@@ -87,23 +76,8 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
}
}
// Check if too many operations have been created recently
{
count, err := svc.DB.Operations().CountSince(ctx,
int64(userId),
time.Now().Add(-CreateMapfixRecencyWindow),
)
if err != nil {
return nil, err
}
if CreateMapfixRateLimit < count {
return nil, ErrCreateMapfixRateLimit
}
}
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
Owner: userId,
Owner: int64(userId),
StatusID: model.OperationStatusCreated,
})
if err != nil {
@@ -112,9 +86,8 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
create_request := model.CreateMapfixRequest{
OperationID: operation.ID,
ModelID: ModelID,
TargetAssetID: TargetAssetID,
Description: request.Description,
ModelID: request.AssetID,
TargetAssetID: request.TargetAssetID,
}
j, err := json.Marshal(create_request)
@@ -122,10 +95,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
return nil, err
}
_, err = svc.Nats.Publish("maptest.mapfixes.create", []byte(j))
if err != nil {
return nil, err
}
svc.Nats.Publish("maptest.mapfixes.create", []byte(j))
return &api.OperationID{
OperationID: operation.ID,
@@ -146,7 +116,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
ID: mapfix.ID,
DisplayName: mapfix.DisplayName,
Creator: mapfix.Creator,
GameID: int32(mapfix.GameID),
GameID: mapfix.GameID,
CreatedAt: mapfix.CreatedAt.Unix(),
UpdatedAt: mapfix.UpdatedAt.Unix(),
Submitter: int64(mapfix.Submitter),
@@ -155,7 +125,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
Completed: mapfix.Completed,
TargetAssetID: int64(mapfix.TargetAssetID),
StatusID: int32(mapfix.StatusID),
Description: mapfix.Description,
StatusMessage: mapfix.StatusMessage,
}, nil
}
@@ -164,7 +134,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
// Get list of mapfixes.
//
// GET /mapfixes
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) (*api.Mapfixes, error) {
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) ([]api.Mapfix, error) {
filter := datastore.Optional()
if params.DisplayName.IsSet(){
@@ -176,22 +146,10 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
if params.GameID.IsSet(){
filter.Add("game_id", params.GameID.Value)
}
if params.Submitter.IsSet(){
filter.Add("submitter", params.Submitter.Value)
}
if params.AssetID.IsSet(){
filter.Add("asset_id", params.AssetID.Value)
}
if params.TargetAssetID.IsSet(){
filter.Add("target_asset_id", params.TargetAssetID.Value)
}
if params.StatusID.IsSet(){
filter.Add("status_id", params.StatusID.Value)
}
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
total, items, err := svc.DB.Mapfixes().ListWithTotal(ctx, filter, model.Page{
items, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
},sort)
@@ -199,14 +157,13 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
return nil, err
}
var resp api.Mapfixes
resp.Total=total
var resp []api.Mapfix
for _, item := range items {
resp.Mapfixes = append(resp.Mapfixes, api.Mapfix{
resp = append(resp, api.Mapfix{
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),
@@ -215,11 +172,10 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
Completed: item.Completed,
TargetAssetID: int64(item.TargetAssetID),
StatusID: int32(item.StatusID),
Description: item.Description,
})
}
return &resp, nil
return resp, nil
}
// PatchMapfixCompleted implements patchMapfixCompleted operation.
@@ -264,58 +220,22 @@ func (svc *Service) UpdateMapfixModel(ctx context.Context, params api.UpdateMapf
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
if err != nil {
return err
}
// check if caller is the submitter
has_role := userId == mapfix.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
OldModelID := mapfix.AssetID
OldModelVersion := mapfix.AssetVersion
NewModelID := uint64(params.ModelID)
NewModelVersion := uint64(params.ModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("asset_id", NewModelID)
pmap.Add("asset_version", NewModelVersion)
pmap.AddNotNil("asset_id", params.ModelID)
pmap.AddNotNil("asset_version", params.VersionID)
//always reset completed when model changes
pmap.Add("completed", false)
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeModel{
OldModelID: OldModelID,
OldModelVersion: OldModelVersion,
NewModelID: NewModelID,
NewModelVersion: NewModelVersion,
}
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.AuditEventTypeChangeModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
}
// ActionMapfixReject invokes actionMapfixReject operation.
@@ -335,45 +255,13 @@ func (svc *Service) ActionMapfixReject(ctx context.Context, params api.ActionMap
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// transaction
target_status := model.MapfixStatusRejected
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{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.MapfixStatusRejected)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
}
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
@@ -393,13 +281,13 @@ func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params api.A
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixReview
return ErrPermissionDeniedNeedRoleMapReview
}
// transaction
smap := datastore.Optional()
smap.Add("status_id", model.MapfixStatusChangesRequested)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAcceptedUnvalidated, model.MapfixStatusSubmitted}, smap)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAccepted, model.MapfixStatusSubmitted}, smap)
}
// ActionMapfixRevoke invokes actionMapfixRevoke operation.
@@ -419,56 +307,27 @@ func (svc *Service) ActionMapfixRevoke(ctx context.Context, params api.ActionMap
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
if err != nil {
return err
}
// check if caller is the submitter
has_role := userId == mapfix.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
// transaction
target_status := model.MapfixStatusUnderConstruction
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, 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.MapfixStatusUnderConstruction)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap)
}
// ActionMapfixTriggerSubmit invokes actionMapfixTriggerSubmit operation.
// ActionMapfixSubmit invokes actionMapfixSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit
func (svc *Service) ActionMapfixTriggerSubmit(ctx context.Context, params api.ActionMapfixTriggerSubmitParams) error {
// POST /mapfixes/{MapfixID}/status/submit
func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMapfixSubmitParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
@@ -480,198 +339,19 @@ func (svc *Service) ActionMapfixTriggerSubmit(ctx context.Context, params api.Ac
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
if err != nil {
return err
}
// check if caller is the submitter
has_role := userId == mapfix.Submitter
if !has_role {
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)
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
}
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
//
// Role MapfixReview changes status from Submitting -> UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/reset-submitting
func (svc *Service) ActionMapfixResetSubmitting(ctx context.Context, params api.ActionMapfixResetSubmittingParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
}
// check when mapfix was updated
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
if err != nil {
return err
}
if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
// the last time the mapfix was updated must be longer than 10 seconds ago
return ErrDelayReset
}
// check if caller has required role
has_role := userId == mapfix.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
// transaction
target_status := model.MapfixStatusUnderConstruction
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.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.MapfixStatusSubmitted)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
}
// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
@@ -691,18 +371,12 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixUpload
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapUpload
}
// transaction
target_status := model.MapfixStatusUploading
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("status_id", model.MapfixStatusUploading)
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated}, smap)
if err != nil {
return err
@@ -721,31 +395,7 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac
return err
}
_, err = svc.Nats.Publish("maptest.mapfixes.upload", []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
}
svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j))
return nil
}
@@ -767,12 +417,7 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixUpload
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapUpload
}
// check when mapfix was updated
@@ -786,36 +431,9 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action
}
// transaction
target_status := model.MapfixStatusValidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, 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.MapfixStatusValidated)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
}
// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
@@ -835,7 +453,7 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixReview
return ErrPermissionDeniedNeedRoleMapReview
}
// read mapfix (this could be done with a transaction WHERE clause)
@@ -844,13 +462,11 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
return err
}
userId, err := userInfo.GetUserID()
has_role, err = userInfo.IsSubmitter(uint64(mapfix.Submitter))
if err != nil {
return err
}
// check if caller is NOT the submitter
has_role = userId == mapfix.Submitter
if has_role {
return ErrAcceptOwnMapfix
}
@@ -873,9 +489,8 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
}
// transaction
target_status := model.MapfixStatusValidating
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("status_id", model.MapfixStatusValidating)
mapfix, err = svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
if err != nil {
return err
@@ -898,31 +513,7 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
return err
}
_, err = svc.Nats.Publish("maptest.mapfixes.validate", []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
}
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
return nil
}
@@ -944,19 +535,13 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// transaction
target_status := model.MapfixStatusValidating
smap := datastore.Optional()
smap.Add("status_id", target_status)
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAcceptedUnvalidated}, smap)
smap.Add("status_id", model.MapfixStatusValidating)
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAccepted}, smap)
if err != nil {
return err
}
@@ -978,31 +563,7 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac
return err
}
_, err = svc.Nats.Publish("maptest.mapfixes.validate", []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
}
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
return nil
}
@@ -1024,12 +585,7 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleMapfixReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// check when mapfix was updated
@@ -1043,34 +599,8 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM
}
// transaction
target_status := model.MapfixStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, 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.MapfixStatusAccepted)
smap.Add("status_message", "Manually forced reset")
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
}

View File

@@ -25,7 +25,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]
filter.GameID = &params.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 {

View File

@@ -24,13 +24,11 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar
return nil, err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(operation.Owner))
if err != nil {
return nil, err
}
// check if caller is the submitter
has_role := userId == operation.Owner
// check if caller is operation owner
if !has_role {
return nil, ErrPermissionDeniedNotSubmitter
}
@@ -38,7 +36,7 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar
return &api.Operation{
OperationID: operation.ID,
Date: operation.CreatedAt.Unix(),
Owner: int64(operation.Owner),
Owner: operation.Owner,
Status: int32(operation.StatusID),
StatusMessage: operation.StatusMessage,
Path: operation.Path,

View File

@@ -63,13 +63,13 @@ func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptP
if err != nil {
return nil, err
}
filter.Add("from_script_hash", int64(hash)) // No type safety!
filter.AddNotNil("from_script_hash", int64(hash)) // No type safety!
}
if params.ToScriptID.IsSet(){
filter.Add("to_script_id", params.ToScriptID.Value)
filter.AddNotNil("to_script_id", params.ToScriptID.Value)
}
if params.Policy.IsSet(){
filter.Add("policy", params.Policy.Value)
filter.AddNotNil("policy", params.Policy.Value)
}
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{
@@ -121,6 +121,13 @@ func (svc *Service) DeleteScriptPolicy(ctx context.Context, params api.DeleteScr
//
// GET /script-policy/{ScriptPolicyID}
func (svc *Service) GetScriptPolicy(ctx context.Context, params api.GetScriptPolicyParams) (*api.ScriptPolicy, error) {
_, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
}
// Read permission for script policy only requires you to be logged in
policy, err := svc.DB.ScriptPolicy().Get(ctx, params.ScriptPolicyID)
if err != nil {
return nil, err

View File

@@ -57,19 +57,19 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
if err != nil {
return nil, err
}
filter.Add("hash", int64(hash)) // No type safety!
filter.AddNotNil("hash", int64(hash)) // No type safety!
}
if params.Name.IsSet(){
filter.Add("name", params.Name.Value)
filter.AddNotNil("name", params.Name.Value)
}
if params.Source.IsSet(){
filter.Add("source", params.Source.Value)
filter.AddNotNil("source", params.Source.Value)
}
if params.ResourceType.IsSet(){
filter.Add("resource_type", params.ResourceType.Value)
filter.AddNotNil("resource_type", params.ResourceType.Value)
}
if params.ResourceID.IsSet(){
filter.Add("resource_id", params.ResourceID.Value)
filter.AddNotNil("resource_id", params.ResourceID.Value)
}
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{
@@ -122,6 +122,13 @@ func (svc *Service) DeleteScript(ctx context.Context, params api.DeleteScriptPar
//
// GET /scripts/{ScriptID}
func (svc *Service) GetScript(ctx context.Context, params api.GetScriptParams) (*api.Script, error) {
_, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
}
// Read permission for scripts only requires you to be logged in
script, err := svc.DB.Scripts().Get(ctx, params.ScriptID)
if err != nil {
return nil, err

View File

@@ -88,6 +88,13 @@ func (usr UserInfoHandle) Validate() (bool, error) {
}
return validate.Valid, nil
}
func (usr UserInfoHandle) IsSubmitter(submitter uint64) (bool, error) {
userId, err := usr.GetUserID()
if err != nil {
return false, err
}
return userId == submitter, nil
}
func (usr UserInfoHandle) hasRoles(wantRoles Roles) (bool, error) {
haveroles, err := usr.GetRoles()
if err != nil {

View File

@@ -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"
@@ -20,21 +19,17 @@ var (
ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapfixUpload = fmt.Errorf("%w: Need Role MapfixUpload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapfixReview = fmt.Errorf("%w: Need Role MapfixReview", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapUpload = fmt.Errorf("%w: Need Role MapUpload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapReview = fmt.Errorf("%w: Need Role MapReview", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
ErrNegativeID = errors.New("A negative ID was provided")
)
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.

View File

@@ -20,16 +20,13 @@ 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,
model.SubmissionStatusValidating,
model.SubmissionStatusAcceptedUnvalidated,
model.SubmissionStatusAccepted,
}
// Allow 5 submissions every 10 minutes
CreateSubmissionRateLimit int64 = 5
CreateSubmissionRecencyWindow = time.Second*600
)
var (
@@ -38,17 +35,10 @@ var (
ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released")
ErrReleaseNoUploadedAssetID = errors.New("Only submissions with a UploadedAssetID can be released")
ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
ErrCreateSubmissionRateLimit = errors.New("You must not create more than 5 submissions every 10 minutes")
)
// POST /submissions
func (svc *Service) CreateSubmission(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
@@ -76,24 +66,8 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
return nil, ErrCreationPhaseSubmissionsLimit
}
}
// 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,
Owner: int64(userId),
StatusID: model.OperationStatusCreated,
})
if err != nil {
@@ -101,13 +75,8 @@ 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),
OperationID: operation.ID,
ModelID: request.AssetID,
}
j, err := json.Marshal(create_request)
@@ -115,86 +84,7 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
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)
if err != nil {
return nil, err
}
_, err = svc.Nats.Publish("maptest.submissions.create", []byte(j))
if err != nil {
return nil, err
}
svc.Nats.Publish("maptest.submissions.create", []byte(j))
return &api.OperationID{
OperationID: operation.ID,
@@ -215,7 +105,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
ID: submission.ID,
DisplayName: submission.DisplayName,
Creator: submission.Creator,
GameID: int32(submission.GameID),
GameID: submission.GameID,
CreatedAt: submission.CreatedAt.Unix(),
UpdatedAt: submission.UpdatedAt.Unix(),
Submitter: int64(submission.Submitter),
@@ -224,6 +114,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
}
@@ -232,7 +123,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
// Get list of submissions.
//
// GET /submissions
func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissionsParams) (*api.Submissions, error) {
func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissionsParams) ([]api.Submission, error) {
filter := datastore.Optional()
if params.DisplayName.IsSet(){
@@ -244,22 +135,10 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
if params.GameID.IsSet(){
filter.Add("game_id", params.GameID.Value)
}
if params.Submitter.IsSet(){
filter.Add("submitter", params.Submitter.Value)
}
if params.AssetID.IsSet(){
filter.Add("asset_id", params.AssetID.Value)
}
if params.UploadedAssetID.IsSet(){
filter.Add("uploaded_asset_id", params.UploadedAssetID.Value)
}
if params.StatusID.IsSet(){
filter.Add("status_id", params.StatusID.Value)
}
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
total, items, err := svc.DB.Submissions().ListWithTotal(ctx, filter, model.Page{
items, err := svc.DB.Submissions().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
},sort)
@@ -267,14 +146,13 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
return nil, err
}
var resp api.Submissions
resp.Total=total
var resp []api.Submission
for _, item := range items {
resp.Submissions = append(resp.Submissions, api.Submission{
resp = append(resp, api.Submission{
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),
@@ -286,7 +164,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
})
}
return &resp, nil
return resp, nil
}
// PatchSubmissionCompleted implements patchSubmissionCompleted operation.
@@ -331,58 +209,22 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
if err != nil {
return err
}
// check if caller is the submitter
has_role := userId == submission.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
OldModelID := submission.AssetID
OldModelVersion := submission.AssetVersion
NewModelID := uint64(params.ModelID)
NewModelVersion := uint64(params.ModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("asset_id", NewModelID)
pmap.Add("asset_version", NewModelVersion)
pmap.AddNotNil("asset_id", params.ModelID)
pmap.AddNotNil("asset_version", params.VersionID)
//always reset completed when model changes
pmap.Add("completed", false)
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusUnderConstruction}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeModel{
OldModelID: OldModelID,
OldModelVersion: OldModelVersion,
NewModelID: NewModelID,
NewModelVersion: NewModelVersion,
}
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: submission.ID,
EventType: model.AuditEventTypeChangeModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusSubmitted, model.SubmissionStatusUnderConstruction}, pmap)
}
// ActionSubmissionReject invokes actionSubmissionReject operation.
@@ -402,45 +244,13 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// transaction
target_status := model.SubmissionStatusRejected
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, 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.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusRejected)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
}
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
@@ -460,45 +270,13 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// 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.SubmissionStatusValidated, model.SubmissionStatusAcceptedUnvalidated, model.SubmissionStatusSubmitted}, 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.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusChangesRequested)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAccepted, model.SubmissionStatusSubmitted}, smap)
}
// ActionSubmissionRevoke invokes actionSubmissionRevoke operation.
@@ -518,56 +296,27 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
if err != nil {
return err
}
// check if caller is the submitter
has_role := userId == submission.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
// transaction
target_status := model.SubmissionStatusUnderConstruction
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, 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.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusUnderConstruction)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap)
}
// ActionSubmissionTriggerSubmit invokes actionSubmissionTriggerSubmit operation.
// ActionSubmissionSubmit invokes actionSubmissionSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
//
// POST /submissions/{SubmissionID}/status/trigger-submit
func (svc *Service) ActionSubmissionTriggerSubmit(ctx context.Context, params api.ActionSubmissionTriggerSubmitParams) error {
// POST /submissions/{SubmissionID}/status/submit
func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.ActionSubmissionSubmitParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
@@ -579,206 +328,19 @@ func (svc *Service) ActionSubmissionTriggerSubmit(ctx context.Context, params ap
return err
}
userId, err := userInfo.GetUserID()
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
if err != nil {
return err
}
// 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 {
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)
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
}
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
//
// Role SubmissionReview changes status from Submitting -> UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/reset-submitting
func (svc *Service) ActionSubmissionResetSubmitting(ctx context.Context, params api.ActionSubmissionResetSubmittingParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
}
// check when submission was updated
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil {
return err
}
if time.Now().Before(submission.UpdatedAt.Add(time.Second*10)) {
// the last time the submission was updated must be longer than 10 seconds ago
return ErrDelayReset
}
// check if caller has required role
has_role := userId == submission.Submitter
if !has_role {
return ErrPermissionDeniedNotSubmitter
}
// transaction
target_status := model.SubmissionStatusUnderConstruction
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
}
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
smap.Add("status_id", model.SubmissionStatusSubmitted)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
}
// ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation.
@@ -798,18 +360,12 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionUpload
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapUpload
}
// transaction
target_status := model.SubmissionStatusUploading
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("status_id", model.SubmissionStatusUploading)
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated}, smap)
if err != nil {
return err
@@ -831,36 +387,12 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
return err
}
_, err = svc.Nats.Publish("maptest.submissions.upload", []byte(j))
if err != nil {
return err
}
svc.Nats.Publish("maptest.submissions.upload", []byte(j))
} else {
// refuse to operate
return ErrUploadedAssetIDAlreadyExists
}
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
}
@@ -881,12 +413,7 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionUpload
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapUpload
}
// check when submission was updated
@@ -900,36 +427,9 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
}
// transaction
target_status := model.SubmissionStatusValidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, 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.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusValidated)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
}
// ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation.
@@ -949,7 +449,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionReview
return ErrPermissionDeniedNeedRoleMapReview
}
// read submission (this could be done with a transaction WHERE clause)
@@ -958,21 +458,18 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
return err
}
userId, err := userInfo.GetUserID()
has_role, err = userInfo.IsSubmitter(uint64(submission.Submitter))
if err != nil {
return err
}
// check if caller is NOT the submitter
has_role = userId == submission.Submitter
if has_role {
return ErrAcceptOwnSubmission
}
// transaction
target_status := model.SubmissionStatusValidating
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("status_id", model.SubmissionStatusValidating)
submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
if err != nil {
return err
@@ -995,31 +492,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
return err
}
_, err = svc.Nats.Publish("maptest.submissions.validate", []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
}
svc.Nats.Publish("maptest.submissions.validate", []byte(j))
return nil
}
@@ -1041,19 +514,13 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// transaction
target_status := model.SubmissionStatusValidating
smap := datastore.Optional()
smap.Add("status_id", target_status)
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAcceptedUnvalidated}, smap)
smap.Add("status_id", model.SubmissionStatusValidating)
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAccepted}, smap)
if err != nil {
return err
}
@@ -1075,31 +542,7 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap
return err
}
_, err = svc.Nats.Publish("maptest.submissions.validate", []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
}
svc.Nats.Publish("maptest.submissions.validate", []byte(j))
return nil
}
@@ -1121,12 +564,7 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
}
// check if caller has required role
if !has_role {
return ErrPermissionDeniedNeedRoleSubmissionReview
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
return ErrPermissionDeniedNeedRoleMapReview
}
// check when submission was updated
@@ -1140,36 +578,10 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
}
// transaction
target_status := model.SubmissionStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, 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.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusAccepted)
smap.Add("status_message", "Manually forced reset")
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
}
// ReleaseSubmissions invokes releaseSubmissions operation.
@@ -1215,13 +627,12 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
for i,submission := range submissions{
date := request[i].Date.Unix()
var GameID = int32(submission.GameID)
// create each map with go-grpc
_, err := svc.Maps.Create(ctx, &maps.MapRequest{
ID: int64(submission.UploadedAssetID),
_, err := svc.Client.Create(ctx, &maps.MapRequest{
ID: submission.UploadedAssetID,
DisplayName: &submission.DisplayName,
Creator: &submission.Creator,
GameID: &GameID,
GameID: &submission.GameID,
Date: &date,
})
if err != nil {

View File

@@ -2,7 +2,6 @@ package service_internal
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -17,7 +16,7 @@ var(
model.MapfixStatusUploading,
model.MapfixStatusValidated,
model.MapfixStatusValidating,
model.MapfixStatusAcceptedUnvalidated,
model.MapfixStatusAccepted,
model.MapfixStatusChangesRequested,
model.MapfixStatusSubmitted,
model.MapfixStatusUnderConstruction,
@@ -35,148 +34,13 @@ var(
//
// POST /mapfixes/{MapfixID}/validated-model
func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
ValidatedModelID := uint64(params.ValidatedModelID)
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("validated_asset_id", ValidatedModelID)
pmap.Add("validated_asset_version", ValidatedModelVersion)
pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// pmap.Add("completed", false)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: ValidatedModelID,
ValidatedModelVersion: ValidatedModelVersion,
}
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.AuditEventTypeChangeValidatedModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.ActionMapfixSubmittedParams) error {
// transaction
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
}
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
}
// 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
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
}
// ActionMapfixValidate invokes actionMapfixValidate operation.
@@ -198,61 +62,10 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.A
// POST /mapfixes/{MapfixID}/status/validator-failed
func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
// transaction
target_status := model.MapfixStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
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),
}
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
smap.Add("status_id", model.MapfixStatusAccepted)
smap.Add("status_message", params.StatusMessage)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
@@ -262,54 +75,13 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.Ac
// POST /mapfixes/{MapfixID}/status/validator-uploaded
func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
// transaction
target_status := model.MapfixStatusUploaded
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, 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: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.MapfixStatusUploaded)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
}
// POST /mapfixes
func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCreate) (*internal.MapfixID, error) {
// sanitization
if request.GameID<0||
request.AssetOwner<0||
request.AssetID<0||
request.AssetVersion<0||
request.TargetAssetID<0{
return nil, ErrNegativeID
}
var GameID=uint32(request.GameID);
var Submitter=uint64(request.AssetOwner);
var AssetID=uint64(request.AssetID);
var AssetVersion=uint64(request.AssetVersion);
var TargetAssetID=uint64(request.TargetAssetID);
// Check if an active mapfix with the same asset id exists
{
filter := datastore.Optional()
@@ -335,7 +107,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
// check if user owns asset
// TODO: allow bypass by admin
if operation.Owner != Submitter {
if operation.Owner != request.AssetOwner {
return nil, ErrNotAssetOwner
}
@@ -343,14 +115,13 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: GameID,
Submitter: Submitter,
AssetID: AssetID,
AssetVersion: AssetVersion,
GameID: request.GameID,
Submitter: request.AssetOwner,
AssetID: request.AssetID,
AssetVersion: request.AssetVersion,
Completed: false,
TargetAssetID: TargetAssetID,
TargetAssetID: request.TargetAssetID,
StatusID: model.MapfixStatusUnderConstruction,
Description: request.Description,
})
if err != nil {
return nil, err

View File

@@ -4,7 +4,7 @@ import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
@@ -49,13 +49,13 @@ func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptP
if err != nil {
return nil, err
}
filter.Add("from_script_hash", int64(hash)) // No type safety!
filter.AddNotNil("from_script_hash", int64(hash)) // No type safety!
}
if params.ToScriptID.IsSet(){
filter.Add("to_script_id", params.ToScriptID.Value)
filter.AddNotNil("to_script_id", params.ToScriptID.Value)
}
if params.Policy.IsSet(){
filter.Add("policy", params.Policy.Value)
filter.AddNotNil("policy", params.Policy.Value)
}
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{

View File

@@ -4,7 +4,7 @@ import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
@@ -44,19 +44,19 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
if err != nil {
return nil, err
}
filter.Add("hash", int64(hash)) // No type safety!
filter.AddNotNil("hash", int64(hash)) // No type safety!
}
if params.Name.IsSet(){
filter.Add("name", params.Name.Value)
filter.AddNotNil("name", params.Name.Value)
}
if params.Source.IsSet(){
filter.Add("source", params.Source.Value)
filter.AddNotNil("source", params.Source.Value)
}
if params.ResourceType.IsSet(){
filter.Add("resource_type", params.ResourceType.Value)
filter.AddNotNil("resource_type", params.ResourceType.Value)
}
if params.ResourceID.IsSet(){
filter.Add("resource_id", params.ResourceID.Value)
filter.AddNotNil("resource_id", params.ResourceID.Value)
}
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{

View File

@@ -3,21 +3,12 @@ package service_internal
import (
"context"
"errors"
"math"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"github.com/nats-io/nats.go"
)
const (
ValidtorUserID uint64 = uint64(math.MaxInt64)
)
var (
ErrNegativeID = errors.New("A negative ID was provided")
)
type Service struct {
DB datastore.Datastore
Nats nats.JetStreamContext

View File

@@ -2,14 +2,12 @@ package service_internal
import (
"context"
"encoding/json"
"errors"
"fmt"
"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(
@@ -18,7 +16,7 @@ var(
model.SubmissionStatusUploading,
model.SubmissionStatusValidated,
model.SubmissionStatusValidating,
model.SubmissionStatusAcceptedUnvalidated,
model.SubmissionStatusAccepted,
model.SubmissionStatusChangesRequested,
model.SubmissionStatusSubmitted,
model.SubmissionStatusUnderConstruction,
@@ -35,150 +33,13 @@ var(
//
// POST /submissions/{SubmissionID}/validated-model
func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params internal.UpdateSubmissionValidatedModelParams) error {
ValidatedModelID := uint64(params.ValidatedModelID)
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("validated_asset_id", ValidatedModelID)
pmap.Add("validated_asset_version", ValidatedModelVersion)
pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// pmap.Add("completed", false)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: ValidatedModelID,
ValidatedModelVersion: ValidatedModelVersion,
}
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.AuditEventTypeChangeValidatedModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params internal.ActionSubmissionSubmittedParams) error {
// transaction
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
}
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
}
// 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
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
}
// ActionSubmissionValidate invokes actionSubmissionValidate operation.
@@ -188,36 +49,9 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params i
// POST /submissions/{SubmissionID}/status/validator-validated
func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error {
// transaction
target_status := model.SubmissionStatusValidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, 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: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
smap.Add("status_id", model.SubmissionStatusValidated)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
}
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
@@ -227,62 +61,10 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params intern
// POST /submissions/{SubmissionID}/status/validator-failed
func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params internal.ActionSubmissionAcceptedParams) error {
// transaction
target_status := model.SubmissionStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
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),
}
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
smap.Add("status_id", model.SubmissionStatusAccepted)
smap.Add("status_message", params.StatusMessage)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
}
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
@@ -292,55 +74,14 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna
// POST /submissions/{SubmissionID}/status/validator-uploaded
func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error {
// transaction
target_status := model.SubmissionStatusUploaded
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("status_id", model.SubmissionStatusUploaded)
smap.Add("uploaded_asset_id", params.UploadedAssetID)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, 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: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
}
// POST /submissions
func (svc *Service) CreateSubmission(ctx context.Context, request *internal.SubmissionCreate) (*internal.SubmissionID, error) {
// sanitization
if request.GameID<0||
request.AssetOwner<0||
request.AssetID<0||
request.AssetVersion<0{
return nil, ErrNegativeID
}
var GameID=uint32(request.GameID);
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
{
filter := datastore.Optional()
@@ -365,11 +106,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 != request.AssetOwner {
return nil, ErrNotAssetOwner
}
@@ -377,12 +115,12 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: GameID,
Submitter: Submitter,
AssetID: AssetID,
AssetVersion: AssetVersion,
GameID: request.GameID,
Submitter: request.AssetOwner,
AssetID: request.AssetID,
AssetVersion: request.AssetVersion,
Completed: false,
StatusID: Status,
StatusID: model.SubmissionStatusUnderConstruction,
})
if err != nil {
return nil, err

View File

@@ -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.3.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"

View File

@@ -1,6 +1,6 @@
# Using the `rust-musl-builder` as base image, instead of
# the official Rust toolchain
FROM registry.itzana.me/docker-proxy/clux/muslrust:1.86.0-stable AS chef
FROM docker.io/clux/muslrust:stable AS chef
USER root
RUN cargo install cargo-chef
WORKDIR /app
@@ -17,7 +17,7 @@ RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path r
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl --bin maps-validation
FROM registry.itzana.me/docker-proxy/alpine:3.21 AS runtime
FROM docker.io/alpine:latest AS runtime
RUN addgroup -S myuser && adduser -S myuser -G myuser
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/maps-validation /usr/local/bin/
USER myuser

View File

@@ -1,6 +1,6 @@
[package]
name = "submissions-api"
version = "0.7.2"
version = "0.6.1"
edition = "2021"
publish = ["strafesnet"]
repository = "https://git.itzana.me/StrafesNET/maps-service"

View File

@@ -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
}
}

View File

@@ -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>,SingleItemError>{
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,
@@ -61,7 +61,7 @@ impl Context{
}
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>,SingleItemError>{
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,
@@ -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(())
}
}

View File

@@ -22,7 +22,7 @@ macro_rules! query_pairs{
macro_rules! action{
($system:expr,$fname:ident,$config:ident,$config_type:ident,$action:expr,$config_submission_id:expr,$(($param:expr,$value:expr))*)=>{
pub async fn $fname(&self,$config:$config_type)->Result<(),Error>{
let url_raw=format!(concat!("{}/",$system,"/{}/",$action),self.0.base_url,$config_submission_id);
let url_raw=format!(concat!("{}/",$system,"/{}/status/",$action),self.0.base_url,$config_submission_id);
let url=query_pairs!(reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?,$(($param,$value))*);
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>,SingleItemError>{
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,
@@ -91,7 +91,7 @@ impl Context{
}
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>,SingleItemError>{
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,
@@ -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,27 +162,18 @@ 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",action_submission_validated,config,SubmissionID,"validator-validated",config.0,);
action!("submissions",update_submission_validated_model,config,UpdateSubmissionModelRequest,"validated-model",config.SubmissionID,
("ValidatedModelID",config.ModelID.to_string().as_str())
("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
);
action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"status/validator-uploaded",config.SubmissionID,
action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"validator-uploaded",config.SubmissionID,
("UploadedAssetID",config.UploadedAssetID.to_string().as_str())
);
action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"status/validator-failed",config.SubmissionID,
("ErrorMessage",config.ErrorMessage.as_str())
action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"validator-failed",config.SubmissionID,
("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,26 +185,17 @@ 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",action_mapfix_validated,config,MapfixID,"validator-validated",config.0,);
action!("mapfixes",update_mapfix_validated_model,config,UpdateMapfixModelRequest,"validated-model",config.MapfixID,
("ValidatedModelID",config.ModelID.to_string().as_str())
("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
);
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())
action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"validator-uploaded",config.MapfixID,);
action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"validator-failed",config.MapfixID,
("StatusMessage",config.StatusMessage.as_str())
);
// simple operation endpoint
action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"status/operation-failed",config.OperationID,
action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"operation-failed",config.OperationID,
("StatusMessage",config.StatusMessage.as_str())
);
}

View File

@@ -27,7 +27,8 @@ 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,
}
@@ -35,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 {
@@ -55,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,
}))
}
}
@@ -74,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)]
@@ -92,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)]
@@ -173,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>{
@@ -230,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{
@@ -258,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)]
@@ -272,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{
@@ -299,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)]

View File

@@ -1,848 +0,0 @@
use std::collections::{HashSet,HashMap};
use crate::download::download_asset_version;
use crate::rbx_util::{class_is_a,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();
for instance in dom.descendants_of(model_instance.referent()){
if class_is_a(instance.class.as_str(),"BasePart"){
// 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})
}
}

View File

@@ -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(())
}
}

View File

@@ -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(())
}
}

View File

@@ -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),
ModelVersionsPage(rbx_asset::cookie::PageError),
EmptyVersionsPage,
CreatorTypeMustBeUser(rbx_asset::cookie::CreatorType),
ModelDetails(rbx_asset::cookie::GetError),
ModelInfoDownload(rbx_asset::cookie::GetAssetV2Error),
ModelFileDownload(rbx_asset::cookie::GetError),
NoLocations,
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,50 +27,57 @@ 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{
pub async fn create_inner(&self,create_info:CreateRequest)->Result<CreateResult,Error>{
// discover asset creator and latest version
let info=self.cloud_context.get_asset_info(
rbx_asset::cloud::GetAssetLatestRequest{asset_id:create_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);
// discover asset creator
let creator_fut=async{
self.cookie_context.get_asset_details(
rbx_asset::cookie::GetAssetDetailsRequest{asset_id:create_info.ModelID}
).await.map_err(Error::ModelDetails)
};
let asset_version=info.revisionId;
// download the map model
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
asset_id:create_info.ModelID,
version:asset_version,
}).await.map_err(Error::Download)?;
let asset_fut=async{
let asset_info=self.cookie_context.get_asset_v2(rbx_asset::cookie::GetAssetRequest{
asset_id:create_info.ModelID,
version:None,
}).await.map_err(Error::ModelInfoDownload)?;
let location=asset_info.info.locations.first().ok_or(Error::NoLocations)?;
let data=self.cookie_context.get_asset_v2_download(location).await.map_err(Error::ModelFileDownload)?;
Ok((asset_info.version,data))
};
let (details,(asset_version,model_data))=tokio::try_join!(creator_fut,asset_fut)?;
if details.Creator.CreatorType!=rbx_asset::cookie::CreatorType::User{
return Err(Error::CreatorTypeMustBeUser(details.Creator.CreatorType));
}
// 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(&mut 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:details.Creator.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,
})
}

View File

@@ -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?;
}

View File

@@ -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?;
}

View File

@@ -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)
}

View File

@@ -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;
@@ -24,7 +20,6 @@ pub enum StartupError{
NatsConnect(async_nats::ConnectError),
NatsGetStream(async_nats::jetstream::context::GetStreamError),
NatsConsumer(async_nats::jetstream::stream::ConsumerError),
NatsConsumerUpdate(async_nats::jetstream::stream::ConsumerUpdateError),
NatsStream(async_nats::jetstream::consumer::StreamError),
}
impl std::fmt::Display for StartupError{
@@ -43,15 +38,12 @@ 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
// talk to roblox through STRAFESNET_CI2 account
let cookie=std::env::var("RBXCOOKIE").expect("RBXCOOKIE env required");
let cookie_context=rbx_asset::cookie::Context::new(rbx_asset::cookie::Cookie::new(cookie));
// download models through cloud api
let api_key=std::env::var("RBX_API_KEY").expect("RBX_API_KEY env required");
let cloud_context=rbx_asset::cloud::Context::new(rbx_asset::cloud::ApiKey::new(api_key));
let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new(cookie));
// maps-service api
let api_host_internal=std::env::var("API_HOST_INTERNAL").expect("API_HOST_INTERNAL env required");
@@ -60,35 +52,20 @@ async fn main()->Result<(),StartupError>{
// nats
let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required");
let nats_fut=async{
const STREAM_NAME:&str="maptest";
const DURABLE_NAME:&str="validation";
const FILTER_SUBJECT:&str="maptest.>";
let nats_config=async_nats::jetstream::consumer::pull::Config{
name:Some(DURABLE_NAME.to_owned()),
durable_name:Some(DURABLE_NAME.to_owned()),
filter_subject:FILTER_SUBJECT.to_owned(),
..Default::default()
};
let nasty=async_nats::connect(nats_host).await.map_err(StartupError::NatsConnect)?;
// use nats jetstream
let stream=async_nats::jetstream::new(nasty)
.get_stream(STREAM_NAME).await.map_err(StartupError::NatsGetStream)?;
let consumer=stream.get_or_create_consumer(DURABLE_NAME,nats_config.clone()).await.map_err(StartupError::NatsConsumer)?;
// check if config matches expected config
if consumer.cached_info().config.filter_subject!=FILTER_SUBJECT{
stream.update_consumer(nats_config).await.map_err(StartupError::NatsConsumerUpdate)?;
}
// only need messages
consumer.messages().await.map_err(StartupError::NatsStream)
async_nats::jetstream::new(nasty)
.get_stream("maptest").await.map_err(StartupError::NatsGetStream)?
.get_or_create_consumer("validation",async_nats::jetstream::consumer::pull::Config{
name:Some("validation".to_owned()),
durable_name:Some("validation".to_owned()),
filter_subject:"maptest.>".to_owned(),
..Default::default()
}).await.map_err(StartupError::NatsConsumer)?
.messages().await.map_err(StartupError::NatsStream)
};
let message_handler=message_handler::MessageHandler::new(cloud_context,cookie_context,group_id,api);
let message_handler=message_handler::MessageHandler::new(cookie_context,group_id,api);
// Create a signal listener for SIGTERM
let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener");

View File

@@ -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),
@@ -28,21 +26,18 @@ fn from_slice<'a,T:serde::de::Deserialize<'a>>(slice:&'a [u8])->Result<T,HandleM
}
pub struct MessageHandler{
pub(crate) cloud_context:rbx_asset::cloud::Context,
pub(crate) cookie_context:rbx_asset::cookie::Context,
pub(crate) cookie_context:rbx_asset::cookie::CookieContext,
pub(crate) group_id:Option<u64>,
pub(crate) api:submissions_api::internal::Context,
}
impl MessageHandler{
pub fn new(
cloud_context:rbx_asset::cloud::Context,
cookie_context:rbx_asset::cookie::Context,
cookie_context:rbx_asset::cookie::CookieContext,
group_id:Option<u64>,
api:submissions_api::internal::Context,
)->Self{
Self{
cloud_context,
cookie_context,
group_id,
api,
@@ -54,8 +49,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),

View File

@@ -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)]

View File

@@ -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,30 +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>(input:&mut R)->Result<rbx_dom_weak::WeakDom,ReadDomError>{
let mut first_8=[0u8;8];
std::io::Read::read_exact(input,&mut first_8).map_err(ReadDomError::Read)?;
std::io::Seek::rewind(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{
let db=rbx_reflection_database::get();
let (Some(class),Some(superclass))=(db.classes.get(class),db.classes.get(superclass))else{
return false;
};
db.has_superclass(class,superclass)
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{
@@ -59,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);
}
}
@@ -81,7 +84,6 @@ pub struct MapInfo<'a>{
pub game_id:Result<GameID,ParseGameIDError>,
}
#[derive(Debug)]
pub enum StringValueError{
ObjectNotFound,
ValueNotSet,
@@ -90,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),
@@ -98,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(),
}
})
}

View File

@@ -1,11 +1,9 @@
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),
Get(rbx_asset::cookie::GetError),
Json(serde_json::Error),
Upload(rbx_asset::cookie::UploadError),
ApiActionMapfixUploaded(submissions_api::Error),
@@ -19,14 +17,11 @@ 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 map model version
let model_data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:upload_info.ModelID,
version:upload_info.ModelVersion,
}).await.map_err(Error::Download)?;
// transparently handle gzipped models
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
version:Some(upload_info.ModelVersion),
}).await.map_err(Error::Get)?;
// upload the map to the strafesnet group
let _upload_response=self.cookie_context.upload(rbx_asset::cookie::UploadRequest{

View File

@@ -1,11 +1,9 @@
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),
Get(rbx_asset::cookie::GetError),
Json(serde_json::Error),
Create(rbx_asset::cookie::CreateError),
SystemTime(std::time::SystemTimeError),
@@ -20,14 +18,11 @@ 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 map model version
let model_data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:upload_info.ModelID,
version:upload_info.ModelVersion,
}).await.map_err(Error::Download)?;
// transparently handle gzipped models
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
version:Some(upload_info.ModelVersion),
}).await.map_err(Error::Get)?;
// upload the map to the strafesnet group
let upload_response=self.cookie_context.create(rbx_asset::cookie::CreateRequest{

View File

@@ -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)?;
},
}

View File

@@ -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)?;
},
}

View File

@@ -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{
@@ -33,11 +32,11 @@ fn hash_source(source:&str)->String{
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error{
pub enum ValidateError{
ScriptFlaggedIllegalKeyword(String),
ScriptBlocked(Option<submissions_api::types::ScriptID>),
ScriptNotYetReviewed(Option<submissions_api::types::ScriptID>),
Download(crate::download::Error),
ModelFileDownload(rbx_asset::cookie::GetError),
ModelFileDecode(ReadDomError),
ApiGetScriptPolicyFromHash(submissions_api::types::SingleItemError),
ApiGetScript(submissions_api::Error),
@@ -52,12 +51,12 @@ pub enum Error{
AssetUpload(rbx_asset::cookie::UploadError),
AssetCreate(rbx_asset::cookie::CreateError),
}
impl std::fmt::Display for Error{
impl std::fmt::Display for ValidateError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for Error{}
impl std::error::Error for ValidateError{}
#[allow(nonstandard_style)]
pub struct ValidateRequest{
@@ -89,33 +88,30 @@ 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{
pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),ValidateError>{
// download map
let data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:validate_info.ModelID,
version:validate_info.ModelVersion,
}).await.map_err(Error::Download)?;
version:Some(validate_info.ModelVersion),
}).await.map_err(ValidateError::ModelFileDownload)?;
// decode dom (slow!)
let mut dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::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
// grab path to offending script
let path=get_partial_path(&dom,script);
return Err(Error::ScriptFlaggedIllegalKeyword(path));
return Err(ValidateError::ScriptFlaggedIllegalKeyword(path));
}
// associate a name and policy with the source code
// policy will be fetched from the database to replace the default policy
@@ -136,7 +132,7 @@ impl crate::message_handler::MessageHandler{
// fetch the script policy
let script_policy=self.api.get_script_policy_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptPolicyFromHash)?;
}).await.map_err(ValidateError::ApiGetScriptPolicyFromHash)?;
// write the policy to the script_map, fetching the replacement code if necessary
if let Some(script_policy)=script_policy{
@@ -148,7 +144,7 @@ impl crate::message_handler::MessageHandler{
submissions_api::types::Policy::Replace=>{
let script=self.api.get_script(submissions_api::types::GetScriptRequest{
ScriptID:script_policy.ToScriptID,
}).await.map_err(Error::ApiGetScript)?;
}).await.map_err(ValidateError::ApiGetScript)?;
Policy::Replace(script.Source)
},
};
@@ -164,14 +160,14 @@ impl crate::message_handler::MessageHandler{
Source:source.as_str(),
ResourceType:resource_type,
ResourceID:Some(resource_id),
}).await.map_err(Error::ApiCreateScript)?;
}).await.map_err(ValidateError::ApiCreateScript)?;
// create a None policy (pending review by yours truly)
self.api.create_script_policy(submissions_api::types::CreateScriptPolicyRequest{
ToScriptID:script.ScriptID,
FromScriptID:script.ScriptID,
Policy:submissions_api::types::Policy::None,
}).await.map_err(Error::ApiCreateScriptPolicy)?;
}).await.map_err(ValidateError::ApiCreateScriptPolicy)?;
}
Ok(())
@@ -179,17 +175,17 @@ impl crate::message_handler::MessageHandler{
.await?;
// make the replacements
let mut modified=false;
let mut modified=true;
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());
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptBlocked(script.map(|s|s.ID)));
}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
return Err(ValidateError::ScriptBlocked(script.map(|s|s.ID)));
},
None
|Some(Policy::None)
@@ -197,8 +193,8 @@ impl crate::message_handler::MessageHandler{
let hash=hash_source(source.as_str());
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptNotYetReviewed(script.map(|s|s.ID)));
}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
return Err(ValidateError::ScriptNotYetReviewed(script.map(|s|s.ID)));
},
Some(Policy::Allowed)=>(),
Some(Policy::Delete)=>{
@@ -215,17 +211,19 @@ impl crate::message_handler::MessageHandler{
}
}
println!("[Validator] Forcing model upload! modified=true");
// if the model was validated, the submission must be changed to use the modified model
let (validated_model_id,validated_model_version)=if modified{
if modified{
// serialize model (slow!)
let mut data=Vec::new();
let &[map_ref]=dom.root().children()else{
return Err(Error::ModelFileRootMustHaveOneChild);
return Err(ValidateError::ModelFileRootMustHaveOneChild);
};
rbx_binary::to_writer(&mut data,&dom,&[map_ref]).map_err(Error::ModelFileEncode)?;
rbx_binary::to_writer(&mut data,&dom,&[map_ref]).map_err(ValidateError::ModelFileEncode)?;
// upload a model lol
if let Some(model_id)=validate_info.ValidatedModelID{
let model_id=if let Some(model_id)=validate_info.ValidatedModelID{
// upload to existing id
let response=self.cookie_context.upload(rbx_asset::cookie::UploadRequest{
assetid:model_id,
@@ -234,13 +232,13 @@ impl crate::message_handler::MessageHandler{
ispublic:None,
allowComments:None,
groupId:None,
},data).await.map_err(Error::AssetUpload)?;
},data).await.map_err(ValidateError::AssetUpload)?;
(response.AssetId,response.AssetVersion)
response.AssetId
}else{
// grab the map instance from the map ref
// grab the map instance from the map re
let Some(map_instance)=dom.get_by_ref(map_ref)else{
return Err(Error::ModelFileChildRefIsNil);
return Err(ValidateError::ModelFileChildRefIsNil);
};
// create new model
let response=self.cookie_context.create(rbx_asset::cookie::CreateRequest{
@@ -249,37 +247,46 @@ impl crate::message_handler::MessageHandler{
ispublic:true,
allowComments:true,
groupId:None,
},data).await.map_err(Error::AssetCreate)?;
},data).await.map_err(ValidateError::AssetCreate)?;
(response.AssetId,response.AssetVersion)
response.AssetId
};
match validate_info.ResourceID{
ResourceID::Mapfix(mapfix_id)=>{
// update the mapfix to use the validated model
self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
MapfixID:mapfix_id,
ModelID:model_id,
ModelVersion:1, //TODO
}).await.map_err(ValidateError::ApiUpdateMapfixModel)?;
},
ResourceID::Submission(submission_id)=>{
// update the submission to use the validated model
self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
SubmissionID:submission_id,
ModelID:model_id,
ModelVersion:1, //TODO
}).await.map_err(ValidateError::ApiUpdateSubmissionModel)?;
},
}
}else{
(validate_info.ModelID,validate_info.ModelVersion)
};
match validate_info.ResourceID{
ResourceID::Mapfix(mapfix_id)=>{
// update the mapfix to use the validated model
self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
MapfixID:mapfix_id,
ModelID:validated_model_id,
ModelVersion:validated_model_version,
}).await.map_err(Error::ApiUpdateMapfixModel)?;
},
ResourceID::Submission(submission_id)=>{
// update the submission to use the validated model
self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
SubmissionID:submission_id,
ModelID:validated_model_id,
ModelVersion:validated_model_version,
}).await.map_err(Error::ApiUpdateSubmissionModel)?;
},
}
Ok(())
}
}
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 +301,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
}

View File

@@ -1,4 +1,4 @@
FROM registry.itzana.me/docker-proxy/oven/bun:1.2.8
FROM oven/bun:latest
WORKDIR /app
@@ -10,4 +10,4 @@ ENV NEXT_TELEMETRY_DISABLED=1
RUN bun install
RUN bun run build
ENTRYPOINT ["bun", "run", "start"]
ENTRYPOINT ["bun", "run", "start"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -1,11 +1,6 @@
"use client"
import Link from "next/link"
import Image from "next/image";
import "./styles/header.scss"
import { UserInfo } from "@/app/ts/User";
import { useState, useEffect } from "react";
interface HeaderButton {
name: string,
@@ -20,25 +15,6 @@ function HeaderButton(header: HeaderButton) {
}
export default function Header() {
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)
useEffect(() => {
async function getLoginInfo() {
const [validateData, userData] = await Promise.all([
fetch("/api/session/validate").then(validateResponse => validateResponse.json()),
fetch("/api/session/user").then(userResponse => userResponse.json())
]);
setValid(validateData)
setUser(userData)
}
getLoginInfo()
}, [])
return (
<header className="header-bar">
<nav className="left">
@@ -48,16 +24,6 @@ export default function Header() {
</nav>
<nav className="right">
<HeaderButton name="Submit" href="/submit"/>
{valid && user ? (
<div className="author">
<Link href="/auth">
<Image className="avatar" width={28} height={28} priority={true} src={user.AvatarURL} alt={user.Username}/>
<button>{user.Username}</button>
</Link>
</div>
) : (
<button onClick={handleLoginClick}>Login</button>
)}
</nav>
</header>
)

View File

@@ -12,7 +12,7 @@ interface SubmissionCardProps {
id: number;
}
export function SubmissionCard(props: SubmissionCardProps) {
export default function SubmissionCard(props: SubmissionCardProps) {
return (
<Link href={`/submissions/${props.id}`}>
<div className="submissionCard">
@@ -40,32 +40,3 @@ export function SubmissionCard(props: SubmissionCardProps) {
</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>
);
}

View File

@@ -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}

View File

@@ -1,54 +0,0 @@
@use "../../globals.scss";
::placeholder {
color: var(--placeholder-text)
}
.form-spacer {
margin-bottom: 20px;
&:last-of-type {
margin-top: 15px;
}
}
#target-asset-radio {
color: var(--text-color);
font-size: globals.$form-label-fontsize;
}
.form-field {
width: 850px;
& label, & input {
color: var(--text-color);
}
& fieldset {
border-color: rgb(100,100,100);
}
& span {
color: white;
}
}
main {
display: grid;
justify-content: center;
align-items: center;
margin-inline: auto;
width: 700px;
}
header h1 {
text-align: center;
color: var(--text-color);
}
form {
display: grid;
gap: 25px;
fieldset {
border: blue
}
}

View File

@@ -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>
);
}

View File

@@ -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:  |  Height:  |  Size: 15 KiB

View File

@@ -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,
});
}
}

View File

@@ -1,13 +1,13 @@
$UnderConstruction: "0";
$Submitting: "1";
$Submitted: "2";
$ChangesRequested: "3";
$Accepted: "4";
$Validating: "5";
$Validated: "6";
$Uploading: "7";
$Uploaded: "8";
$Rejected: "9";
$Submitted: "1";
$ChangesRequested: "2";
$Accepted: "3";
$Validating: "4";
$Validated: "5";
$Uploading: "6";
$Uploaded: "7";
$Rejected: "8";
$Released: "9";
.review-status {
border-radius: 5px;
@@ -17,62 +17,62 @@ $Rejected: "9";
font-weight: bold;
}
&[data-review-status="#{$Released}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Rejected}"] {
background-color: rgb(255, 0, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Uploading}"] {
background-color: rgb(255, 165, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Uploaded}"] {
background-color: rgb(0, 150, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Validated}"] {
background-color: rgb(0, 255, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Validating}"] {
background-color: rgb(255, 165, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Accepted}"] {
background-color: rgb(0, 150, 0);
background-color: rgb(2, 162, 2);
p {
color: white;
}
}
&[data-review-status="#{$ChangesRequested}"] {
background-color: rgb(255, 125, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Submitted}"] {
background-color: rgb(255, 165, 0);
p {
color: white;
}
}
&[data-review-status="#{$Submitting}"] {
background-color: rgb(255, 165, 0);
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$UnderConstruction}"] {
background-color: rgb(0, 150, 255);
background-color: orange;
p {
color: white;
}

View File

@@ -12,9 +12,7 @@ interface CreatorAndReviewStatus {
asset_id: MapfixInfo["AssetID"],
creator: MapfixInfo["DisplayName"],
review: MapfixInfo["StatusID"],
submitter: MapfixInfo["Submitter"],
target_asset_id: MapfixInfo["TargetAssetID"],
description: MapfixInfo["Description"],
status_message: MapfixInfo["StatusMessage"],
comments: Comment[],
name: string
}
@@ -52,7 +50,7 @@ function LeaveAComment() {
)
}
export function Comments(stats: CommentersProps) {
export default function Comments(stats: CommentersProps) {
return (<>
<section className="comments">
{stats.comments_data.comments.length===0
@@ -66,6 +64,5 @@ export function Comments(stats: CommentersProps) {
}
export {
type CreatorAndReviewStatus,
type Comment,
type CreatorAndReviewStatus
}

View File

@@ -0,0 +1,14 @@
import { MapfixInfo } from "@/app/ts/Mapfix"
interface AssetID {
id: MapfixInfo["AssetID"]
}
function MapImage() {
return <p>Fetching map image...</p>
}
export {
type AssetID,
MapImage
}

View File

@@ -1,31 +0,0 @@
import Image from "next/image";
import { MapfixInfo } from "@/app/ts/Mapfix"
interface AssetID {
id: MapfixInfo["AssetID"]
}
function MapImage({ id }: AssetID) {
if (!id) {
return <p>Missing asset ID</p>;
}
const imageUrl = `/thumbnails/asset/${id}`;
return (
<Image
src={imageUrl}
alt="Map Thumbnail"
layout="responsive"
width={512}
height={512}
priority={true}
className="map-image"
/>
);
}
export {
type AssetID,
MapImage
}

View File

@@ -1,40 +1,21 @@
import { Roles, RolesConstants } from "@/app/ts/Roles";
import { MapfixStatus } from "@/app/ts/Mapfix";
import { Button, ButtonOwnProps } from "@mui/material";
import { useState, useEffect } from "react";
interface ReviewAction {
name: string,
action: string,
}
const ReviewActions = {
Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
BypassSubmit: {name:"Bypass Submit",action:"bypass-submit"} as ReviewAction,
ResetSubmitting: {name:"Reset Submitting (fix softlocked status)",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 (fix softlocked status)",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 (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
}
type Actions = "Completed" | "Submit" | "Reject" | "Revoke"
type ApiActions = Lowercase<Actions> | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
type Review = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
interface ReviewButton {
action: ReviewAction,
name: Review,
action: ApiActions,
mapfixId: string,
color: ButtonOwnProps["color"]
}
interface ReviewId {
mapfixId: string,
mapfixStatus: number,
mapfixSubmitter: number,
mapfixId: string
}
async function ReviewButtonClicked(action: string, mapfixId: string) {
async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
try {
const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, {
method: "POST",
@@ -60,10 +41,11 @@ function ReviewButton(props: ReviewButton) {
return <Button
color={props.color}
variant="contained"
onClick={() => { ReviewButtonClicked(props.action.action, props.mapfixId) }}>{props.action.name}</Button>
onClick={() => { ReviewButtonClicked(props.action, props.mapfixId) }}>{props.name}</Button>
}
export default function ReviewButtons(props: ReviewId) {
const mapfixId = props.mapfixId
// When is each button visible?
// Multiple buttons can be visible at once.
// Action | Role | When Current Status is One of:
@@ -77,93 +59,16 @@ export default function ReviewButtons(props: ReviewId) {
// RequestChanges | Reviewer | Validated, Accepted, Submitted
// Upload | MapAdmin | Validated
// ResetUploading | MapAdmin | Uploading
const { mapfixId, mapfixStatus } = props;
const [user, setUser] = useState<number|null>(null);
const [roles, setRoles] = useState<Roles>(RolesConstants.Empty);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
try {
const [rolesData, userData] = await Promise.all([
fetch("/api/session/roles").then(rolesResponse => rolesResponse.json()),
fetch("/api/session/user").then(userResponse => userResponse.json())
]);
setRoles(rolesData.Roles);
setUser(userData.UserID);
} catch (error) {
console.error("Error fetching data:", error);
} finally {
setLoading(false);
}
}
fetchData();
}, [mapfixId]);
if (loading) return <p>Loading...</p>;
const visibleButtons: ReviewButton[] = [];
const is_submitter = user === props.mapfixSubmitter;
if (is_submitter) {
if ([MapfixStatus.UnderConstruction, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
visibleButtons.push({ action: ReviewActions.Submit, color: "info", mapfixId });
}
if ([MapfixStatus.Submitted, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
visibleButtons.push({ action: ReviewActions.Revoke, color: "info", mapfixId });
}
if (mapfixStatus === MapfixStatus.Submitting) {
visibleButtons.push({ action: ReviewActions.ResetSubmitting, color: "error", mapfixId });
}
}
if (roles&RolesConstants.MapfixReview) {
// you can force submit a map in ChangesRequested status
if (!is_submitter && mapfixStatus === MapfixStatus.ChangesRequested) {
visibleButtons.push({ action: ReviewActions.BypassSubmit, color: "error", mapfixId });
}
// you can't review your own mapfix!
// note that this means there needs to be more than one person with MapfixReview
if (!is_submitter && mapfixStatus === MapfixStatus.Submitted) {
visibleButtons.push({ action: ReviewActions.Accept, color: "info", mapfixId });
visibleButtons.push({ action: ReviewActions.Reject, color: "error", mapfixId });
}
if (mapfixStatus === MapfixStatus.AcceptedUnvalidated) {
visibleButtons.push({ action: ReviewActions.Validate, color: "info", mapfixId });
}
if (mapfixStatus === MapfixStatus.Validating) {
visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", mapfixId });
}
// this button serves the same purpose as Revoke if you are both
// the map submitter and have MapfixReview when status is Submitted
if (
[MapfixStatus.Validated, MapfixStatus.AcceptedUnvalidated].includes(mapfixStatus!)
|| !is_submitter && mapfixStatus == MapfixStatus.Submitted
) {
visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", mapfixId });
}
}
if (roles&RolesConstants.MapfixUpload) {
if (mapfixStatus === MapfixStatus.Validated) {
visibleButtons.push({ action: ReviewActions.Upload, color: "info", mapfixId });
}
if (mapfixStatus === MapfixStatus.Uploading) {
visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", mapfixId });
}
}
return (
<section className="review-set">
{visibleButtons.length === 0 ? (
<p>No available actions</p>
) : (
visibleButtons.map((btn) => (
<ReviewButton key={btn.action.action} {...btn} />
))
)}
<ReviewButton color="info" name="Submit" action="submit" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Revoke" action="revoke" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Accept" action="trigger-validate" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Validate" action="retry-validate" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reject" action="reject" mapfixId={mapfixId}/>
<ReviewButton color="info" name="Upload" action="trigger-upload" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reset Uploading (fix softlocked status)" action="reset-uploading" mapfixId={mapfixId}/>
<ReviewButton color="error" name="Reset Validating (fix softlocked status)" action="reset-validating" mapfixId={mapfixId}/>
</section>
);
)
}

Some files were not shown because too many files have changed in this diff Show More