Compare commits

..

2 Commits
master ... nats

Author SHA1 Message Date
eb9eeb518f something like this 2024-12-02 23:29:13 -08:00
371271d084 nasty 2024-12-02 23:29:13 -08:00
83 changed files with 2645 additions and 11638 deletions

View File

@ -1,36 +0,0 @@
# Stage 1: Build
FROM docker.io/golang:1.23 AS builder
# Set the working directory in the container
WORKDIR /app
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
# Download dependencies
RUN --mount=type=secret,id=netrc,dst=/root/.netrc go mod download
# Copy the entire project
COPY . .
# Build the Go application
RUN CGO_ENABLED=0 GOOS=linux go build -o service ./cmd/maps-service/service.go
# Stage 2: Run
FROM alpine
# Set up a non-root user for security
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
# Set the working directory in the container
WORKDIR /home/appuser
# Copy the built application from the builder stage
COPY --from=builder /app/service .
# Expose application port (adjust if needed)
EXPOSE 8081
# Command to run the application
ENTRYPOINT ["./service"]

23
LICENSE
View File

@ -1,23 +0,0 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,8 +0,0 @@
.PHONY: maps-service web validation
maps-service:
DOCKER_BUILDKIT=1 docker build . -f Containerfile -t maps-service \
--secret id=netrc,src=/home/quat/.netrc
web:
docker build web -f web/Containerfile -t maps-service-web
validation:
docker build validation -f validation/Containerfile -t maps-service-validation

View File

@ -1,15 +1,6 @@
# STRAFES.NET Map Submission System # STRAFES.NET API
## Components ## How to Begin Development
- Submissions API (golang) `pkg/` `cmd/`
- Website `/web/`
- Script Validation (rust) `validation/`
## How to Begin Development on Each Component
### Submissions API
Prerequisite: golang installed
1. Run `go generate` to ensure the generated API is up-to-date. This project uses [ogen](https://github.com/ogen-go/ogen). 1. Run `go generate` to ensure the generated API is up-to-date. This project uses [ogen](https://github.com/ogen-go/ogen).
```bash ```bash
@ -21,38 +12,3 @@ Prerequisite: golang installed
``` ```
By default, the project opens at `localhost:8080`. By default, the project opens at `localhost:8080`.
### Website
Prerequisite: bun installed
1. `cd web`
2. `bun install`
#### For development:
3. `bun run dev`
#### For production:
3. `bun run build`
4. `bun run start` (optionally start a node server)
### Script Validation
Prerequisite: rust installed
1. `cd validation`
2. `cargo run --release`
#### License
<sup>
Licensed under <a href="LICENSE">MIT license</a>.
</sup>
<br>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, shall be licensed as above, without any
additional terms or conditions.
</sub>

View File

@ -1,119 +0,0 @@
version: '3.9'
networks:
maps-service-network:
driver: bridge
services:
nats:
image: docker.io/nats:latest
container_name: nats
command: ["-js"] #"-DVV"
networks:
- maps-service-network
mapsservice:
image:
maps-service
container_name: mapsservice
command: [
# debug
"--debug","serve",
# http service port
"--port","8082",
# postgres
"--pg-host","10.0.0.29",
"--pg-port","5432",
"--pg-db","maps",
"--pg-user","quat",
"--pg-password","happypostgresuser",
# other hosts
"--nats-host","nats:4222",
"--auth-rpc-host","authrpc:8081"
]
depends_on:
- authrpc
- nats
networks:
- maps-service-network
ports:
- "8082:8082"
web:
image:
maps-service-web
networks:
- maps-service-network
ports:
- "3000:3000"
validation:
image:
maps-service-validation
container_name: validation
environment:
- RBXCOOKIE
- API_HOST=http://mapsservice:8082
- NATS_HOST=nats:4222
- DATA_HOST=http://dataservice:9000
depends_on:
- nats
# note: this races the mapsservice which creates a nats stream
# the validation will panic if the nats stream is not created
- mapsservice
- dataservice
networks:
- maps-service-network
dataservice:
image: registry.itzana.me/strafesnet/data-service:master
container_name: dataservice
environment:
- DEBUG=true
- PG_HOST=10.0.0.29
- PG_PORT=5432
- PG_USER=quat
- PG_DB=data
- PG_PASS=happypostgresuser
networks:
- maps-service-network
authredis:
image: docker.io/redis:latest
container_name: authredis
volumes:
- redis-data:/data
command: ["redis-server", "--appendonly", "yes"]
networks:
- maps-service-network
authrpc:
image: registry.itzana.me/strafesnet/auth-service:master
container_name: authrpc
command: ["serve", "rpc"]
environment:
- REDIS_ADDR=authredis:6379
env_file:
- ../auth-compose/auth-service.env
depends_on:
- authredis
networks:
- maps-service-network
logging:
driver: "none"
auth-web:
image: registry.itzana.me/strafesnet/auth-service:master
command: ["serve", "web"]
environment:
- REDIS_ADDR=authredis:6379
env_file:
- ../auth-compose/auth-service.env
depends_on:
- authredis
networks:
- maps-service-network
ports:
- "8080:8080"
volumes:
redis-data:

1
go.mod
View File

@ -7,7 +7,6 @@ toolchain go1.23.3
require ( require (
git.itzana.me/strafesnet/go-grpc v0.0.0-20241129081229-9e166b3d11f7 git.itzana.me/strafesnet/go-grpc v0.0.0-20241129081229-9e166b3d11f7
git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9 git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9
github.com/dchest/siphash v1.2.3
github.com/go-faster/errors v0.7.1 github.com/go-faster/errors v0.7.1
github.com/go-faster/jx v1.1.0 github.com/go-faster/jx v1.1.0
github.com/nats-io/nats.go v1.37.0 github.com/nats-io/nats.go v1.37.0

2
go.sum
View File

@ -20,8 +20,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA=
github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=

View File

@ -1,18 +1,21 @@
openapi: 3.1.0 openapi: 3.1.0
info: info:
title: StrafesNET Submissions - OpenAPI 3.1 title: StrafesNET Submissions - OpenAPI 3.1
description: Browse and manage map submissions. description: Browse and manage map submissions in the staging pipeline.
version: 0.1.0 version: 0.1.0
servers: servers:
- url: https://submissions.strafes.net/v1 - url: https://submissions.strafes.net/v1
tags: tags:
- name: Submissions - name: Submissions
description: Submission operations description: Submission operations
- name: Scripts security:
description: Script operations - cookieAuth: []
- name: ScriptPolicy
description: Script policy operations
paths: paths:
# status
# submit
# accept
# publish
# complete
/submissions: /submissions:
get: get:
summary: Get list of submissions summary: Get list of submissions
@ -30,8 +33,6 @@ paths:
required: false required: false
schema: schema:
$ref: "#/components/schemas/SubmissionFilter" $ref: "#/components/schemas/SubmissionFilter"
security:
- cookieAuth: []
responses: responses:
"200": "200":
description: Successful response description: Successful response
@ -53,15 +54,12 @@ paths:
tags: tags:
- Submissions - Submissions
requestBody: requestBody:
required: true
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/SubmissionCreate' $ref: '#/components/schemas/SubmissionCreate'
security:
- cookieAuth: []
responses: responses:
"201": "200":
description: Successful response description: Successful response
content: content:
application/json: application/json:
@ -80,9 +78,12 @@ paths:
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"200": "200":
description: Successful response description: Successful response
@ -97,13 +98,18 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/model: /submissions/{SubmissionID}/model:
post: patch:
summary: Update model following role restrictions summary: Update model following role restrictions
operationId: updateSubmissionModel operationId: patchSubmissionModel
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
in: path
required: true
schema:
type: integer
format: int64
- name: ModelID - name: ModelID
in: query in: query
required: true required: true
@ -116,10 +122,8 @@ paths:
schema: schema:
type: integer type: integer
format: int64 format: int64
security:
- cookieAuth: []
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -128,17 +132,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/completed: /submissions/{SubmissionID}/completed:
post: patch:
summary: Retrieve map with ID summary: Retrieve map with ID
operationId: setSubmissionCompleted operationId: patchSubmissionCompleted
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -147,17 +154,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/submit: /submissions/{SubmissionID}/status/submit:
post: patch:
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
operationId: actionSubmissionSubmit operationId: actionSubmissionSubmit
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -166,17 +176,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/revoke: /submissions/{SubmissionID}/status/revoke:
post: patch:
summary: Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction summary: Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction
operationId: actionSubmissionRevoke operationId: actionSubmissionRevoke
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -185,17 +198,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/trigger-validate: /submissions/{SubmissionID}/status/trigger-validate:
post: patch:
summary: Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating summary: Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating
operationId: actionSubmissionTriggerValidate operationId: actionSubmissionTriggerValidate
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -204,17 +220,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/reject: /submissions/{SubmissionID}/status/reject:
post: patch:
summary: Role Reviewer changes status from Submitted -> Rejected summary: Role Reviewer changes status from Submitted -> Rejected
operationId: actionSubmissionReject operationId: actionSubmissionReject
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -223,17 +242,20 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/request-changes: /submissions/{SubmissionID}/status/request-changes:
post: patch:
summary: Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested summary: Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested
operationId: actionSubmissionRequestChanges operationId: actionSubmissionRequestChanges
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security: in: path
- cookieAuth: [] required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -241,16 +263,21 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-validated: /submissions/{SubmissionID}/status/validate:
post: patch:
summary: (Internal endpoint) Role Validator changes status from Validating -> Validated summary: Role Validator changes status from Validating -> Validated
operationId: actionSubmissionValidate operationId: actionSubmissionValidate
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
in: path
required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -258,16 +285,21 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-published: /submissions/{SubmissionID}/status/publish:
post: patch:
summary: (Internal endpoint) Role Validator changes status from Publishing -> Published summary: Role Validator changes status from Publishing -> Published
operationId: actionSubmissionPublish operationId: actionSubmissionPublish
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
in: path
required: true
schema:
type: integer
format: int64
responses: responses:
"204": "200":
description: Successful response description: Successful response
default: default:
description: General Error description: General Error
@ -276,231 +308,21 @@ paths:
schema: schema:
$ref: "#/components/schemas/Error" $ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/trigger-publish: /submissions/{SubmissionID}/status/trigger-publish:
post: patch:
summary: Role Admin changes status from Validated -> Publishing summary: Role Admin changes status from Validated -> Publishing
operationId: actionSubmissionTriggerPublish operationId: actionSubmissionTriggerPublish
tags: tags:
- Submissions - Submissions
parameters: parameters:
- $ref: '#/components/parameters/SubmissionID' - name: SubmissionID
security:
- cookieAuth: []
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/script-policy:
post:
summary: Create a new script policy
operationId: createScriptPolicy
tags:
- ScriptPolicy
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptPolicyCreate'
security:
- cookieAuth: []
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Id"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/script-policy/hash/{FromScriptHash}:
get:
summary: Get the policy for the given hash of script source code
operationId: getScriptPolicyFromHash
tags:
- ScriptPolicy
parameters:
- name: FromScriptHash
in: path in: path
required: true required: true
schema: schema:
type: string type: integer
minLength: 16 format: int64
maxLength: 16
security:
- cookieAuth: []
responses: responses:
"200": "200":
description: Successful response description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/ScriptPolicy"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/script-policy/id/{ScriptPolicyID}:
get:
summary: Get the specified script policy by ID
operationId: getScriptPolicy
tags:
- ScriptPolicy
parameters:
- $ref: '#/components/parameters/ScriptPolicyID'
security:
- cookieAuth: []
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/ScriptPolicy"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Update the specified script policy by ID
operationId: updateScriptPolicy
tags:
- ScriptPolicy
parameters:
- $ref: '#/components/parameters/ScriptPolicyID'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptPolicyUpdate'
security:
- cookieAuth: []
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
summary: Delete the specified script policy by ID
operationId: deleteScriptPolicy
tags:
- ScriptPolicy
parameters:
- $ref: '#/components/parameters/ScriptPolicyID'
security:
- cookieAuth: []
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/scripts:
post:
summary: Create a new script
operationId: createScript
tags:
- Scripts
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptCreate'
security:
- cookieAuth: []
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Id"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/scripts/{ScriptID}:
get:
summary: Get the specified script by ID
operationId: getScript
tags:
- Scripts
parameters:
- $ref: '#/components/parameters/ScriptID'
security:
- cookieAuth: []
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Script"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Update the specified script by ID
operationId: updateScript
tags:
- Scripts
parameters:
- $ref: '#/components/parameters/ScriptID'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptUpdate'
security:
- cookieAuth: []
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
delete:
summary: Delete the specified script by ID
operationId: deleteScript
tags:
- Scripts
parameters:
- $ref: '#/components/parameters/ScriptID'
security:
- cookieAuth: []
responses:
"204":
description: Successful response
default: default:
description: General Error description: General Error
content: content:
@ -512,56 +334,26 @@ components:
cookieAuth: cookieAuth:
type: apiKey type: apiKey
in: cookie in: cookie
name: session_id name: SESSIONID
parameters:
SubmissionID:
name: SubmissionID
in: path
required: true
description: The unique identifier for a submission.
schema:
type: integer
format: int64
ScriptID:
name: ScriptID
in: path
required: true
description: The unique identifier for a script.
schema:
type: integer
format: int64
ScriptPolicyID:
name: ScriptPolicyID
in: path
required: true
description: The unique identifier for a script policy.
schema:
type: integer
format: int64
schemas: schemas:
Id: Id:
required:
- ID
type: object type: object
properties: properties:
ID: ID:
type: integer type: integer
format: int64 format: int64
User:
type: object
properties:
ID:
type: integer
format: int64
Username:
type: string
StateID:
type: integer
format: int32
Submission: Submission:
required:
- ID
- DisplayName
- Creator
- GameID
- CreatedAt
- UpdatedAt
- Submitter
- AssetID
- AssetVersion
- Completed
- SubmissionType
# - TargetAssetID
- StatusID
type: object type: object
properties: properties:
ID: ID:
@ -569,17 +361,12 @@ components:
format: int64 format: int64
DisplayName: DisplayName:
type: string type: string
maxLength: 128
Creator: Creator:
type: string type: string
maxLength: 128
GameID: GameID:
type: integer type: integer
format: int32 format: int32
CreatedAt: Date:
type: integer
format: int64
UpdatedAt:
type: integer type: integer
format: int64 format: int64
Submitter: Submitter:
@ -603,8 +390,6 @@ components:
type: integer type: integer
format: int32 format: int32
SubmissionFilter: SubmissionFilter:
required:
- ID
type: object type: object
properties: properties:
ID: ID:
@ -612,142 +397,39 @@ components:
format: int64 format: int64
DisplayName: DisplayName:
type: string type: string
maxLength: 128
Creator: Creator:
type: string type: string
maxLength: 128
GameID: GameID:
type: integer type: integer
format: int32 format: int32
Date:
type: integer
format: int64
SubmissionCreate: SubmissionCreate:
required:
- DisplayName
- Creator
- GameID
- AssetID
- AssetVersion
# - TargetAssetID
type: object type: object
properties: properties:
DisplayName: DisplayName:
type: string type: string
maxLength: 128
Creator: Creator:
type: string type: string
maxLength: 128
GameID: GameID:
type: integer type: integer
format: int32 format: int32
Submitter:
type: integer
format: int64
AssetID: AssetID:
type: integer type: integer
format: int64 format: int64
AssetVersion: AssetVersion:
type: integer type: integer
format: int64 format: int64
SubmissionType:
type: integer
format: int32
TargetAssetID: TargetAssetID:
type: integer type: integer
format: int64 format: int64
Script:
required:
- ID
- Hash
- Source
- SubmissionID
type: object
properties:
ID:
type: integer
format: int64
Hash:
type: string
minLength: 16
maxLength: 16
Source:
type: string
maxLength: 1048576
SubmissionID:
type: integer
format: int64
ScriptCreate:
required:
- Source
# - SubmissionID
type: object
properties:
Source:
type: string
maxLength: 1048576
SubmissionID:
type: integer
format: int64
ScriptUpdate:
required:
- ID
type: object
properties:
ID:
type: integer
format: int64
Source:
type: string
maxLength: 1048576
SubmissionID:
type: integer
format: int64
ScriptPolicy:
required:
- ID
- FromScriptHash
- ToScriptID
- Policy
type: object
properties:
ID:
type: integer
format: int64
FromScriptHash:
type: string
minLength: 16
maxLength: 16
ToScriptID:
type: integer
format: int64
Policy:
type: integer
format: int32
ScriptPolicyCreate:
required:
- FromScriptID
- ToScriptID
- Policy
type: object
properties:
FromScriptID:
type: integer
format: int64
ToScriptID:
type: integer
format: int64
Policy:
type: integer
format: int32
ScriptPolicyUpdate:
required:
- ID
type: object
properties:
ID:
type: integer
format: int64
FromScriptID:
type: integer
format: int64
ToScriptID:
type: integer
format: int64
Policy:
type: integer
format: int32
Pagination: Pagination:
type: object type: object
required: required:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,18 +14,9 @@ const (
ActionSubmissionTriggerPublishOperation OperationName = "ActionSubmissionTriggerPublish" ActionSubmissionTriggerPublishOperation OperationName = "ActionSubmissionTriggerPublish"
ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate" ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
ActionSubmissionValidateOperation OperationName = "ActionSubmissionValidate" ActionSubmissionValidateOperation OperationName = "ActionSubmissionValidate"
CreateScriptOperation OperationName = "CreateScript"
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
CreateSubmissionOperation OperationName = "CreateSubmission" CreateSubmissionOperation OperationName = "CreateSubmission"
DeleteScriptOperation OperationName = "DeleteScript"
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
GetScriptOperation OperationName = "GetScript"
GetScriptPolicyOperation OperationName = "GetScriptPolicy"
GetScriptPolicyFromHashOperation OperationName = "GetScriptPolicyFromHash"
GetSubmissionOperation OperationName = "GetSubmission" GetSubmissionOperation OperationName = "GetSubmission"
ListSubmissionsOperation OperationName = "ListSubmissions" ListSubmissionsOperation OperationName = "ListSubmissions"
SetSubmissionCompletedOperation OperationName = "SetSubmissionCompleted" PatchSubmissionCompletedOperation OperationName = "PatchSubmissionCompleted"
UpdateScriptOperation OperationName = "UpdateScript" PatchSubmissionModelOperation OperationName = "PatchSubmissionModel"
UpdateScriptPolicyOperation OperationName = "UpdateScriptPolicy"
UpdateSubmissionModelOperation OperationName = "UpdateSubmissionModel"
) )

View File

@ -17,7 +17,6 @@ import (
// ActionSubmissionPublishParams is parameters of actionSubmissionPublish operation. // ActionSubmissionPublishParams is parameters of actionSubmissionPublish operation.
type ActionSubmissionPublishParams struct { type ActionSubmissionPublishParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -83,7 +82,6 @@ func decodeActionSubmissionPublishParams(args [1]string, argsEscaped bool, r *ht
// ActionSubmissionRejectParams is parameters of actionSubmissionReject operation. // ActionSubmissionRejectParams is parameters of actionSubmissionReject operation.
type ActionSubmissionRejectParams struct { type ActionSubmissionRejectParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -149,7 +147,6 @@ func decodeActionSubmissionRejectParams(args [1]string, argsEscaped bool, r *htt
// ActionSubmissionRequestChangesParams is parameters of actionSubmissionRequestChanges operation. // ActionSubmissionRequestChangesParams is parameters of actionSubmissionRequestChanges operation.
type ActionSubmissionRequestChangesParams struct { type ActionSubmissionRequestChangesParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -215,7 +212,6 @@ func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool
// ActionSubmissionRevokeParams is parameters of actionSubmissionRevoke operation. // ActionSubmissionRevokeParams is parameters of actionSubmissionRevoke operation.
type ActionSubmissionRevokeParams struct { type ActionSubmissionRevokeParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -281,7 +277,6 @@ func decodeActionSubmissionRevokeParams(args [1]string, argsEscaped bool, r *htt
// ActionSubmissionSubmitParams is parameters of actionSubmissionSubmit operation. // ActionSubmissionSubmitParams is parameters of actionSubmissionSubmit operation.
type ActionSubmissionSubmitParams struct { type ActionSubmissionSubmitParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -347,7 +342,6 @@ func decodeActionSubmissionSubmitParams(args [1]string, argsEscaped bool, r *htt
// ActionSubmissionTriggerPublishParams is parameters of actionSubmissionTriggerPublish operation. // ActionSubmissionTriggerPublishParams is parameters of actionSubmissionTriggerPublish operation.
type ActionSubmissionTriggerPublishParams struct { type ActionSubmissionTriggerPublishParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -413,7 +407,6 @@ func decodeActionSubmissionTriggerPublishParams(args [1]string, argsEscaped bool
// ActionSubmissionTriggerValidateParams is parameters of actionSubmissionTriggerValidate operation. // ActionSubmissionTriggerValidateParams is parameters of actionSubmissionTriggerValidate operation.
type ActionSubmissionTriggerValidateParams struct { type ActionSubmissionTriggerValidateParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -479,7 +472,6 @@ func decodeActionSubmissionTriggerValidateParams(args [1]string, argsEscaped boo
// ActionSubmissionValidateParams is parameters of actionSubmissionValidate operation. // ActionSubmissionValidateParams is parameters of actionSubmissionValidate operation.
type ActionSubmissionValidateParams struct { type ActionSubmissionValidateParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -543,354 +535,8 @@ func decodeActionSubmissionValidateParams(args [1]string, argsEscaped bool, r *h
return params, nil return params, nil
} }
// DeleteScriptParams is parameters of deleteScript operation.
type DeleteScriptParams struct {
// The unique identifier for a script.
ScriptID int64
}
func unpackDeleteScriptParams(packed middleware.Parameters) (params DeleteScriptParams) {
{
key := middleware.ParameterKey{
Name: "ScriptID",
In: "path",
}
params.ScriptID = packed[key].(int64)
}
return params
}
func decodeDeleteScriptParams(args [1]string, argsEscaped bool, r *http.Request) (params DeleteScriptParams, _ error) {
// Decode path: ScriptID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptID",
In: "path",
Err: err,
}
}
return params, nil
}
// DeleteScriptPolicyParams is parameters of deleteScriptPolicy operation.
type DeleteScriptPolicyParams struct {
// The unique identifier for a script policy.
ScriptPolicyID int64
}
func unpackDeleteScriptPolicyParams(packed middleware.Parameters) (params DeleteScriptPolicyParams) {
{
key := middleware.ParameterKey{
Name: "ScriptPolicyID",
In: "path",
}
params.ScriptPolicyID = packed[key].(int64)
}
return params
}
func decodeDeleteScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Request) (params DeleteScriptPolicyParams, _ error) {
// Decode path: ScriptPolicyID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptPolicyID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptPolicyID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptPolicyID",
In: "path",
Err: err,
}
}
return params, nil
}
// GetScriptParams is parameters of getScript operation.
type GetScriptParams struct {
// The unique identifier for a script.
ScriptID int64
}
func unpackGetScriptParams(packed middleware.Parameters) (params GetScriptParams) {
{
key := middleware.ParameterKey{
Name: "ScriptID",
In: "path",
}
params.ScriptID = packed[key].(int64)
}
return params
}
func decodeGetScriptParams(args [1]string, argsEscaped bool, r *http.Request) (params GetScriptParams, _ error) {
// Decode path: ScriptID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptID",
In: "path",
Err: err,
}
}
return params, nil
}
// GetScriptPolicyParams is parameters of getScriptPolicy operation.
type GetScriptPolicyParams struct {
// The unique identifier for a script policy.
ScriptPolicyID int64
}
func unpackGetScriptPolicyParams(packed middleware.Parameters) (params GetScriptPolicyParams) {
{
key := middleware.ParameterKey{
Name: "ScriptPolicyID",
In: "path",
}
params.ScriptPolicyID = packed[key].(int64)
}
return params
}
func decodeGetScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Request) (params GetScriptPolicyParams, _ error) {
// Decode path: ScriptPolicyID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptPolicyID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptPolicyID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptPolicyID",
In: "path",
Err: err,
}
}
return params, nil
}
// GetScriptPolicyFromHashParams is parameters of getScriptPolicyFromHash operation.
type GetScriptPolicyFromHashParams struct {
FromScriptHash string
}
func unpackGetScriptPolicyFromHashParams(packed middleware.Parameters) (params GetScriptPolicyFromHashParams) {
{
key := middleware.ParameterKey{
Name: "FromScriptHash",
In: "path",
}
params.FromScriptHash = packed[key].(string)
}
return params
}
func decodeGetScriptPolicyFromHashParams(args [1]string, argsEscaped bool, r *http.Request) (params GetScriptPolicyFromHashParams, _ error) {
// Decode path: FromScriptHash.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "FromScriptHash",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
params.FromScriptHash = c
return nil
}(); err != nil {
return err
}
if err := func() error {
if err := (validate.String{
MinLength: 16,
MinLengthSet: true,
MaxLength: 16,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(params.FromScriptHash)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "FromScriptHash",
In: "path",
Err: err,
}
}
return params, nil
}
// GetSubmissionParams is parameters of getSubmission operation. // GetSubmissionParams is parameters of getSubmission operation.
type GetSubmissionParams struct { type GetSubmissionParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
@ -1022,7 +668,7 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque
Name: "filter", Name: "filter",
Style: uri.QueryStyleForm, Style: uri.QueryStyleForm,
Explode: true, Explode: true,
Fields: []uri.QueryParameterObjectField{{Name: "ID", Required: true}, {Name: "DisplayName", Required: false}, {Name: "Creator", Required: false}, {Name: "GameID", Required: false}}, Fields: []uri.QueryParameterObjectField{{Name: "ID", Required: false}, {Name: "DisplayName", Required: false}, {Name: "Creator", Required: false}, {Name: "GameID", Required: false}, {Name: "Date", Required: false}},
} }
if err := q.HasParam(cfg); err == nil { if err := q.HasParam(cfg); err == nil {
@ -1038,21 +684,6 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque
}); err != nil { }); err != nil {
return err return err
} }
if err := func() error {
if value, ok := params.Filter.Get(); ok {
if err := func() error {
if err := value.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
return err
}
} }
return nil return nil
}(); err != nil { }(); err != nil {
@ -1065,13 +696,12 @@ func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Reque
return params, nil return params, nil
} }
// SetSubmissionCompletedParams is parameters of setSubmissionCompleted operation. // PatchSubmissionCompletedParams is parameters of patchSubmissionCompleted operation.
type SetSubmissionCompletedParams struct { type PatchSubmissionCompletedParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
} }
func unpackSetSubmissionCompletedParams(packed middleware.Parameters) (params SetSubmissionCompletedParams) { func unpackPatchSubmissionCompletedParams(packed middleware.Parameters) (params PatchSubmissionCompletedParams) {
{ {
key := middleware.ParameterKey{ key := middleware.ParameterKey{
Name: "SubmissionID", Name: "SubmissionID",
@ -1082,7 +712,7 @@ func unpackSetSubmissionCompletedParams(packed middleware.Parameters) (params Se
return params return params
} }
func decodeSetSubmissionCompletedParams(args [1]string, argsEscaped bool, r *http.Request) (params SetSubmissionCompletedParams, _ error) { func decodePatchSubmissionCompletedParams(args [1]string, argsEscaped bool, r *http.Request) (params PatchSubmissionCompletedParams, _ error) {
// Decode path: SubmissionID. // Decode path: SubmissionID.
if err := func() error { if err := func() error {
param := args[0] param := args[0]
@ -1131,147 +761,14 @@ func decodeSetSubmissionCompletedParams(args [1]string, argsEscaped bool, r *htt
return params, nil return params, nil
} }
// UpdateScriptParams is parameters of updateScript operation. // PatchSubmissionModelParams is parameters of patchSubmissionModel operation.
type UpdateScriptParams struct { type PatchSubmissionModelParams struct {
// The unique identifier for a script.
ScriptID int64
}
func unpackUpdateScriptParams(packed middleware.Parameters) (params UpdateScriptParams) {
{
key := middleware.ParameterKey{
Name: "ScriptID",
In: "path",
}
params.ScriptID = packed[key].(int64)
}
return params
}
func decodeUpdateScriptParams(args [1]string, argsEscaped bool, r *http.Request) (params UpdateScriptParams, _ error) {
// Decode path: ScriptID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptID",
In: "path",
Err: err,
}
}
return params, nil
}
// UpdateScriptPolicyParams is parameters of updateScriptPolicy operation.
type UpdateScriptPolicyParams struct {
// The unique identifier for a script policy.
ScriptPolicyID int64
}
func unpackUpdateScriptPolicyParams(packed middleware.Parameters) (params UpdateScriptPolicyParams) {
{
key := middleware.ParameterKey{
Name: "ScriptPolicyID",
In: "path",
}
params.ScriptPolicyID = packed[key].(int64)
}
return params
}
func decodeUpdateScriptPolicyParams(args [1]string, argsEscaped bool, r *http.Request) (params UpdateScriptPolicyParams, _ error) {
// Decode path: ScriptPolicyID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "ScriptPolicyID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ScriptPolicyID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ScriptPolicyID",
In: "path",
Err: err,
}
}
return params, nil
}
// UpdateSubmissionModelParams is parameters of updateSubmissionModel operation.
type UpdateSubmissionModelParams struct {
// The unique identifier for a submission.
SubmissionID int64 SubmissionID int64
ModelID int64 ModelID int64
VersionID int64 VersionID int64
} }
func unpackUpdateSubmissionModelParams(packed middleware.Parameters) (params UpdateSubmissionModelParams) { func unpackPatchSubmissionModelParams(packed middleware.Parameters) (params PatchSubmissionModelParams) {
{ {
key := middleware.ParameterKey{ key := middleware.ParameterKey{
Name: "SubmissionID", Name: "SubmissionID",
@ -1296,7 +793,7 @@ func unpackUpdateSubmissionModelParams(packed middleware.Parameters) (params Upd
return params return params
} }
func decodeUpdateSubmissionModelParams(args [1]string, argsEscaped bool, r *http.Request) (params UpdateSubmissionModelParams, _ error) { func decodePatchSubmissionModelParams(args [1]string, argsEscaped bool, r *http.Request) (params PatchSubmissionModelParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query()) q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: SubmissionID. // Decode path: SubmissionID.
if err := func() error { if err := func() error {

View File

@ -15,142 +15,8 @@ import (
"github.com/ogen-go/ogen/validate" "github.com/ogen-go/ogen/validate"
) )
func (s *Server) decodeCreateScriptRequest(r *http.Request) (
req *ScriptCreate,
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 = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(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 ScriptCreate
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) decodeCreateScriptPolicyRequest(r *http.Request) (
req *ScriptPolicyCreate,
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 = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(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 ScriptPolicyCreate
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
}
return &request, close, nil
default:
return req, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateSubmissionRequest(r *http.Request) ( func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
req *SubmissionCreate, req OptSubmissionCreate,
close func() error, close func() error,
rerr error, rerr error,
) { ) {
@ -169,6 +35,9 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
rerr = multierr.Append(rerr, close()) rerr = multierr.Append(rerr, close())
} }
}() }()
if _, ok := r.Header["Content-Type"]; !ok && r.ContentLength == 0 {
return req, close, nil
}
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil { if err != nil {
return req, close, errors.Wrap(err, "parse media type") return req, close, errors.Wrap(err, "parse media type")
@ -176,7 +45,7 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
switch { switch {
case ct == "application/json": case ct == "application/json":
if r.ContentLength == 0 { if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired return req, close, nil
} }
buf, err := io.ReadAll(r.Body) buf, err := io.ReadAll(r.Body)
if err != nil { if err != nil {
@ -184,13 +53,14 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
} }
if len(buf) == 0 { if len(buf) == 0 {
return req, close, validate.ErrBodyRequired return req, close, nil
} }
d := jx.DecodeBytes(buf) d := jx.DecodeBytes(buf)
var request SubmissionCreate var request OptSubmissionCreate
if err := func() error { if err := func() error {
request.Reset()
if err := request.Decode(d); err != nil { if err := request.Decode(d); err != nil {
return err return err
} }
@ -206,149 +76,7 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
} }
return req, close, err return req, close, err
} }
if err := func() error { return request, close, nil
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) decodeUpdateScriptRequest(r *http.Request) (
req *ScriptUpdate,
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 = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(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 ScriptUpdate
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) decodeUpdateScriptPolicyRequest(r *http.Request) (
req *ScriptPolicyUpdate,
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 = multierr.Append(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = multierr.Append(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 ScriptPolicyUpdate
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
}
return &request, close, nil
default: default:
return req, close, validate.InvalidContentType(ct) return req, close, validate.InvalidContentType(ct)
} }

View File

@ -11,71 +11,21 @@ import (
ht "github.com/ogen-go/ogen/http" ht "github.com/ogen-go/ogen/http"
) )
func encodeCreateScriptRequest(
req *ScriptCreate,
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 encodeCreateScriptPolicyRequest(
req *ScriptPolicyCreate,
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 encodeCreateSubmissionRequest( func encodeCreateSubmissionRequest(
req *SubmissionCreate, req OptSubmissionCreate,
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 encodeUpdateScriptRequest(
req *ScriptUpdate,
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 encodeUpdateScriptPolicyRequest(
req *ScriptPolicyUpdate,
r *http.Request, r *http.Request,
) error { ) error {
const contentType = "application/json" const contentType = "application/json"
if !req.Set {
// Keep request with empty body if value is not set.
return nil
}
e := new(jx.Encoder) e := new(jx.Encoder)
{ {
if req.Set {
req.Encode(e) req.Encode(e)
} }
}
encoded := e.Bytes() encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType) ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil return nil

View File

@ -3,7 +3,6 @@
package api package api
import ( import (
"fmt"
"io" "io"
"mime" "mime"
"net/http" "net/http"
@ -15,11 +14,11 @@ import (
"github.com/ogen-go/ogen/validate" "github.com/ogen-go/ogen/validate"
) )
func decodeActionSubmissionPublishResponse(resp *http.Response) (res *ActionSubmissionPublishNoContent, _ error) { func decodeActionSubmissionPublishResponse(resp *http.Response) (res *ActionSubmissionPublishOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionPublishNoContent{}, nil return &ActionSubmissionPublishOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -66,11 +65,11 @@ func decodeActionSubmissionPublishResponse(resp *http.Response) (res *ActionSubm
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionRejectResponse(resp *http.Response) (res *ActionSubmissionRejectNoContent, _ error) { func decodeActionSubmissionRejectResponse(resp *http.Response) (res *ActionSubmissionRejectOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionRejectNoContent{}, nil return &ActionSubmissionRejectOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -117,11 +116,11 @@ func decodeActionSubmissionRejectResponse(resp *http.Response) (res *ActionSubmi
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionRequestChangesResponse(resp *http.Response) (res *ActionSubmissionRequestChangesNoContent, _ error) { func decodeActionSubmissionRequestChangesResponse(resp *http.Response) (res *ActionSubmissionRequestChangesOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionRequestChangesNoContent{}, nil return &ActionSubmissionRequestChangesOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -168,11 +167,11 @@ func decodeActionSubmissionRequestChangesResponse(resp *http.Response) (res *Act
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionRevokeResponse(resp *http.Response) (res *ActionSubmissionRevokeNoContent, _ error) { func decodeActionSubmissionRevokeResponse(resp *http.Response) (res *ActionSubmissionRevokeOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionRevokeNoContent{}, nil return &ActionSubmissionRevokeOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -219,11 +218,11 @@ func decodeActionSubmissionRevokeResponse(resp *http.Response) (res *ActionSubmi
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionSubmitResponse(resp *http.Response) (res *ActionSubmissionSubmitNoContent, _ error) { func decodeActionSubmissionSubmitResponse(resp *http.Response) (res *ActionSubmissionSubmitOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionSubmitNoContent{}, nil return &ActionSubmissionSubmitOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -270,11 +269,11 @@ func decodeActionSubmissionSubmitResponse(resp *http.Response) (res *ActionSubmi
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionTriggerPublishResponse(resp *http.Response) (res *ActionSubmissionTriggerPublishNoContent, _ error) { func decodeActionSubmissionTriggerPublishResponse(resp *http.Response) (res *ActionSubmissionTriggerPublishOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionTriggerPublishNoContent{}, nil return &ActionSubmissionTriggerPublishOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -321,11 +320,11 @@ func decodeActionSubmissionTriggerPublishResponse(resp *http.Response) (res *Act
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionTriggerValidateResponse(resp *http.Response) (res *ActionSubmissionTriggerValidateNoContent, _ error) { func decodeActionSubmissionTriggerValidateResponse(resp *http.Response) (res *ActionSubmissionTriggerValidateOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionTriggerValidateNoContent{}, nil return &ActionSubmissionTriggerValidateOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -372,177 +371,11 @@ func decodeActionSubmissionTriggerValidateResponse(resp *http.Response) (res *Ac
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeActionSubmissionValidateResponse(resp *http.Response) (res *ActionSubmissionValidateNoContent, _ error) { func decodeActionSubmissionValidateResponse(resp *http.Response) (res *ActionSubmissionValidateOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &ActionSubmissionValidateNoContent{}, nil return &ActionSubmissionValidateOK{}, 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
}
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 decodeCreateScriptResponse(resp *http.Response) (res *ID, _ error) {
switch resp.StatusCode {
case 201:
// Code 201.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response ID
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
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
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 decodeCreateScriptPolicyResponse(resp *http.Response) (res *ID, _ error) {
switch resp.StatusCode {
case 201:
// Code 201.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response ID
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
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -591,8 +424,8 @@ func decodeCreateScriptPolicyResponse(resp *http.Response) (res *ID, _ error) {
func decodeCreateSubmissionResponse(resp *http.Response) (res *ID, _ error) { func decodeCreateSubmissionResponse(resp *http.Response) (res *ID, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 201: case 200:
// Code 201. // Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil { if err != nil {
return res, errors.Wrap(err, "parse media type") return res, errors.Wrap(err, "parse media type")
@ -672,384 +505,6 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *ID, _ error) {
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeDeleteScriptResponse(resp *http.Response) (res *DeleteScriptNoContent, _ error) {
switch resp.StatusCode {
case 204:
// Code 204.
return &DeleteScriptNoContent{}, 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
}
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 decodeDeleteScriptPolicyResponse(resp *http.Response) (res *DeleteScriptPolicyNoContent, _ error) {
switch resp.StatusCode {
case 204:
// Code 204.
return &DeleteScriptPolicyNoContent{}, 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
}
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 decodeGetScriptResponse(resp *http.Response) (res *Script, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
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 Script
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
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 decodeGetScriptPolicyResponse(resp *http.Response) (res *ScriptPolicy, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
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 ScriptPolicy
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
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 decodeGetScriptPolicyFromHashResponse(resp *http.Response) (res *ScriptPolicy, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
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 ScriptPolicy
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
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 decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) { func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 200: case 200:
@ -1083,15 +538,6 @@ func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error)
} }
return res, err return res, err
} }
// Validate response.
if err := func() error {
if err := response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return &response, nil return &response, nil
default: default:
return res, validate.InvalidContentType(ct) return res, validate.InvalidContentType(ct)
@ -1188,23 +634,6 @@ func decodeListSubmissionsResponse(resp *http.Response) (res []Submission, _ err
if response == nil { if response == nil {
return errors.New("nil is invalid value") return errors.New("nil is invalid value")
} }
var failures []validate.FieldError
for i, elem := range response {
if err := func() error {
if err := elem.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: fmt.Sprintf("[%d]", i),
Error: err,
})
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil return nil
}(); err != nil { }(); err != nil {
return res, errors.Wrap(err, "validate") return res, errors.Wrap(err, "validate")
@ -1259,11 +688,11 @@ func decodeListSubmissionsResponse(resp *http.Response) (res []Submission, _ err
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeSetSubmissionCompletedResponse(resp *http.Response) (res *SetSubmissionCompletedNoContent, _ error) { func decodePatchSubmissionCompletedResponse(resp *http.Response) (res *PatchSubmissionCompletedOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &SetSubmissionCompletedNoContent{}, nil return &PatchSubmissionCompletedOK{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {
@ -1310,113 +739,11 @@ func decodeSetSubmissionCompletedResponse(resp *http.Response) (res *SetSubmissi
return res, errors.Wrap(defRes, "error") return res, errors.Wrap(defRes, "error")
} }
func decodeUpdateScriptResponse(resp *http.Response) (res *UpdateScriptNoContent, _ error) { func decodePatchSubmissionModelResponse(resp *http.Response) (res *PatchSubmissionModelOK, _ error) {
switch resp.StatusCode { switch resp.StatusCode {
case 204: case 200:
// Code 204. // Code 200.
return &UpdateScriptNoContent{}, nil return &PatchSubmissionModelOK{}, 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
}
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 decodeUpdateScriptPolicyResponse(resp *http.Response) (res *UpdateScriptPolicyNoContent, _ error) {
switch resp.StatusCode {
case 204:
// Code 204.
return &UpdateScriptPolicyNoContent{}, 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
}
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 decodeUpdateSubmissionModelResponse(resp *http.Response) (res *UpdateSubmissionModelNoContent, _ error) {
switch resp.StatusCode {
case 204:
// Code 204.
return &UpdateSubmissionModelNoContent{}, nil
} }
// Convenient error response. // Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) { defRes, err := func() (res *ErrorStatusCode, err error) {

View File

@ -13,147 +13,63 @@ import (
ht "github.com/ogen-go/ogen/http" ht "github.com/ogen-go/ogen/http"
) )
func encodeActionSubmissionPublishResponse(response *ActionSubmissionPublishNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionPublishResponse(response *ActionSubmissionPublishOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionRejectResponse(response *ActionSubmissionRejectNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionRejectResponse(response *ActionSubmissionRejectOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequestChangesOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionRevokeResponse(response *ActionSubmissionRevokeNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionRevokeResponse(response *ActionSubmissionRevokeOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionSubmitResponse(response *ActionSubmissionSubmitNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionSubmitResponse(response *ActionSubmissionSubmitOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionTriggerPublishResponse(response *ActionSubmissionTriggerPublishNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionTriggerPublishResponse(response *ActionSubmissionTriggerPublishOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionTriggerValidateResponse(response *ActionSubmissionTriggerValidateNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionTriggerValidateResponse(response *ActionSubmissionTriggerValidateOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeActionSubmissionValidateResponse(response *ActionSubmissionValidateNoContent, w http.ResponseWriter, span trace.Span) error { func encodeActionSubmissionValidateResponse(response *ActionSubmissionValidateOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil
}
func encodeCreateScriptResponse(response *ID, 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 encodeCreateScriptPolicyResponse(response *ID, 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 return nil
} }
func encodeCreateSubmissionResponse(response *ID, w http.ResponseWriter, span trace.Span) error { func encodeCreateSubmissionResponse(response *ID, 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 encodeDeleteScriptResponse(response *DeleteScriptNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeDeleteScriptPolicyResponse(response *DeleteScriptPolicyNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeGetScriptResponse(response *Script, 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 encodeGetScriptPolicyResponse(response *ScriptPolicy, 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 encodeGetScriptPolicyFromHashResponse(response *ScriptPolicy, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200)) span.SetStatus(codes.Ok, http.StatusText(200))
@ -199,30 +115,16 @@ func encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter,
return nil return nil
} }
func encodeSetSubmissionCompletedResponse(response *SetSubmissionCompletedNoContent, w http.ResponseWriter, span trace.Span) error { func encodePatchSubmissionCompletedResponse(response *PatchSubmissionCompletedOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil return nil
} }
func encodeUpdateScriptResponse(response *UpdateScriptNoContent, w http.ResponseWriter, span trace.Span) error { func encodePatchSubmissionModelResponse(response *PatchSubmissionModelOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204) w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(204)) span.SetStatus(codes.Ok, http.StatusText(200))
return nil
}
func encodeUpdateScriptPolicyResponse(response *UpdateScriptPolicyNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateSubmissionModelResponse(response *UpdateSubmissionModelNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil return nil
} }

View File

@ -49,195 +49,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break break
} }
switch elem[0] { switch elem[0] {
case '/': // Prefix: "/s" case '/': // Prefix: "/submissions"
origElem := elem origElem := elem
if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" { if l := len("/submissions"); len(elem) >= l && elem[0:l] == "/submissions" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'c': // Prefix: "cript"
origElem := elem
if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case '-': // Prefix: "-policy"
origElem := elem
if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch r.Method {
case "POST":
s.handleCreateScriptPolicyRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'h': // Prefix: "hash/"
origElem := elem
if l := len("hash/"); len(elem) >= l && elem[0:l] == "hash/" {
elem = elem[l:]
} else {
break
}
// Param: "FromScriptHash"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "GET":
s.handleGetScriptPolicyFromHashRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
}
return
}
elem = origElem
case 'i': // Prefix: "id/"
origElem := elem
if l := len("id/"); len(elem) >= l && elem[0:l] == "id/" {
elem = elem[l:]
} else {
break
}
// Param: "ScriptPolicyID"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "DELETE":
s.handleDeleteScriptPolicyRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
case "GET":
s.handleGetScriptPolicyRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
case "POST":
s.handleUpdateScriptPolicyRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "DELETE,GET,POST")
}
return
}
elem = origElem
}
elem = origElem
}
elem = origElem
case 's': // Prefix: "s"
origElem := elem
if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch r.Method {
case "POST":
s.handleCreateScriptRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
// Param: "ScriptID"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "DELETE":
s.handleDeleteScriptRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
case "GET":
s.handleGetScriptRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
case "POST":
s.handleUpdateScriptRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "DELETE,GET,POST")
}
return
}
elem = origElem
}
elem = origElem
}
elem = origElem
case 'u': // Prefix: "ubmissions"
origElem := elem
if l := len("ubmissions"); len(elem) >= l && elem[0:l] == "ubmissions" {
elem = elem[l:] elem = elem[l:]
} else { } else {
break break
@ -309,12 +123,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleSetSubmissionCompletedRequest([1]string{ s.handlePatchSubmissionCompletedRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -332,12 +146,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleUpdateSubmissionModelRequest([1]string{ s.handlePatchSubmissionModelRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -356,6 +170,29 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
break break
} }
switch elem[0] { switch elem[0] {
case 'p': // Prefix: "publish"
origElem := elem
if l := len("publish"); len(elem) >= l && elem[0:l] == "publish" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "PATCH":
s.handleActionSubmissionPublishRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "PATCH")
}
return
}
elem = origElem
case 'r': // Prefix: "re" case 'r': // Prefix: "re"
origElem := elem origElem := elem
if l := len("re"); len(elem) >= l && elem[0:l] == "re" { if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
@ -379,12 +216,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionRejectRequest([1]string{ s.handleActionSubmissionRejectRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -402,12 +239,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionRequestChangesRequest([1]string{ s.handleActionSubmissionRequestChangesRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -425,12 +262,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionRevokeRequest([1]string{ s.handleActionSubmissionRevokeRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -451,12 +288,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionSubmitRequest([1]string{ s.handleActionSubmissionSubmitRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -486,12 +323,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionTriggerPublishRequest([1]string{ s.handleActionSubmissionTriggerPublishRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -509,12 +346,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionTriggerValidateRequest([1]string{ s.handleActionSubmissionTriggerValidateRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -524,21 +361,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
elem = origElem elem = origElem
case 'v': // Prefix: "validator-" case 'v': // Prefix: "validate"
origElem := elem origElem := elem
if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'p': // Prefix: "published"
origElem := elem
if l := len("published"); len(elem) >= l && elem[0:l] == "published" {
elem = elem[l:] elem = elem[l:]
} else { } else {
break break
@ -547,35 +372,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch r.Method { switch r.Method {
case "POST": case "PATCH":
s.handleActionSubmissionPublishRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "POST")
}
return
}
elem = origElem
case 'v': // Prefix: "validated"
origElem := elem
if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "POST":
s.handleActionSubmissionValidateRequest([1]string{ s.handleActionSubmissionValidateRequest([1]string{
args[0], args[0],
}, elemIsEscaped, w, r) }, elemIsEscaped, w, r)
default: default:
s.notAllowed(w, r, "POST") s.notAllowed(w, r, "PATCH")
} }
return return
@ -595,12 +397,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
elem = origElem elem = origElem
} }
elem = origElem
}
elem = origElem
}
} }
s.notFound(w, r) s.notFound(w, r)
} }
@ -680,225 +476,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break break
} }
switch elem[0] { switch elem[0] {
case '/': // Prefix: "/s" case '/': // Prefix: "/submissions"
origElem := elem origElem := elem
if l := len("/s"); len(elem) >= l && elem[0:l] == "/s" { if l := len("/submissions"); len(elem) >= l && elem[0:l] == "/submissions" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'c': // Prefix: "cript"
origElem := elem
if l := len("cript"); len(elem) >= l && elem[0:l] == "cript" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case '-': // Prefix: "-policy"
origElem := elem
if l := len("-policy"); len(elem) >= l && elem[0:l] == "-policy" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch method {
case "POST":
r.name = CreateScriptPolicyOperation
r.summary = "Create a new script policy"
r.operationID = "createScriptPolicy"
r.pathPattern = "/script-policy"
r.args = args
r.count = 0
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'h': // Prefix: "hash/"
origElem := elem
if l := len("hash/"); len(elem) >= l && elem[0:l] == "hash/" {
elem = elem[l:]
} else {
break
}
// Param: "FromScriptHash"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch method {
case "GET":
r.name = GetScriptPolicyFromHashOperation
r.summary = "Get the policy for the given hash of script source code"
r.operationID = "getScriptPolicyFromHash"
r.pathPattern = "/script-policy/hash/{FromScriptHash}"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
case 'i': // Prefix: "id/"
origElem := elem
if l := len("id/"); len(elem) >= l && elem[0:l] == "id/" {
elem = elem[l:]
} else {
break
}
// Param: "ScriptPolicyID"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch method {
case "DELETE":
r.name = DeleteScriptPolicyOperation
r.summary = "Delete the specified script policy by ID"
r.operationID = "deleteScriptPolicy"
r.pathPattern = "/script-policy/id/{ScriptPolicyID}"
r.args = args
r.count = 1
return r, true
case "GET":
r.name = GetScriptPolicyOperation
r.summary = "Get the specified script policy by ID"
r.operationID = "getScriptPolicy"
r.pathPattern = "/script-policy/id/{ScriptPolicyID}"
r.args = args
r.count = 1
return r, true
case "POST":
r.name = UpdateScriptPolicyOperation
r.summary = "Update the specified script policy by ID"
r.operationID = "updateScriptPolicy"
r.pathPattern = "/script-policy/id/{ScriptPolicyID}"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
}
elem = origElem
}
elem = origElem
case 's': // Prefix: "s"
origElem := elem
if l := len("s"); len(elem) >= l && elem[0:l] == "s" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch method {
case "POST":
r.name = CreateScriptOperation
r.summary = "Create a new script"
r.operationID = "createScript"
r.pathPattern = "/scripts"
r.args = args
r.count = 0
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
// Param: "ScriptID"
// Leaf parameter
args[0] = elem
elem = ""
if len(elem) == 0 {
// Leaf node.
switch method {
case "DELETE":
r.name = DeleteScriptOperation
r.summary = "Delete the specified script by ID"
r.operationID = "deleteScript"
r.pathPattern = "/scripts/{ScriptID}"
r.args = args
r.count = 1
return r, true
case "GET":
r.name = GetScriptOperation
r.summary = "Get the specified script by ID"
r.operationID = "getScript"
r.pathPattern = "/scripts/{ScriptID}"
r.args = args
r.count = 1
return r, true
case "POST":
r.name = UpdateScriptOperation
r.summary = "Update the specified script by ID"
r.operationID = "updateScript"
r.pathPattern = "/scripts/{ScriptID}"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
}
elem = origElem
}
elem = origElem
case 'u': // Prefix: "ubmissions"
origElem := elem
if l := len("ubmissions"); len(elem) >= l && elem[0:l] == "ubmissions" {
elem = elem[l:] elem = elem[l:]
} else { } else {
break break
@ -982,10 +562,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = SetSubmissionCompletedOperation r.name = PatchSubmissionCompletedOperation
r.summary = "Retrieve map with ID" r.summary = "Retrieve map with ID"
r.operationID = "setSubmissionCompleted" r.operationID = "patchSubmissionCompleted"
r.pathPattern = "/submissions/{SubmissionID}/completed" r.pathPattern = "/submissions/{SubmissionID}/completed"
r.args = args r.args = args
r.count = 1 r.count = 1
@ -1007,10 +587,10 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = UpdateSubmissionModelOperation r.name = PatchSubmissionModelOperation
r.summary = "Update model following role restrictions" r.summary = "Update model following role restrictions"
r.operationID = "updateSubmissionModel" r.operationID = "patchSubmissionModel"
r.pathPattern = "/submissions/{SubmissionID}/model" r.pathPattern = "/submissions/{SubmissionID}/model"
r.args = args r.args = args
r.count = 1 r.count = 1
@ -1033,6 +613,31 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
break break
} }
switch elem[0] { switch elem[0] {
case 'p': // Prefix: "publish"
origElem := elem
if l := len("publish"); len(elem) >= l && elem[0:l] == "publish" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "PATCH":
r.name = ActionSubmissionPublishOperation
r.summary = "Role Validator changes status from Publishing -> Published"
r.operationID = "actionSubmissionPublish"
r.pathPattern = "/submissions/{SubmissionID}/status/publish"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
case 'r': // Prefix: "re" case 'r': // Prefix: "re"
origElem := elem origElem := elem
if l := len("re"); len(elem) >= l && elem[0:l] == "re" { if l := len("re"); len(elem) >= l && elem[0:l] == "re" {
@ -1056,7 +661,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionRejectOperation r.name = ActionSubmissionRejectOperation
r.summary = "Role Reviewer changes status from Submitted -> Rejected" r.summary = "Role Reviewer changes status from Submitted -> Rejected"
r.operationID = "actionSubmissionReject" r.operationID = "actionSubmissionReject"
@ -1081,7 +686,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionRequestChangesOperation r.name = ActionSubmissionRequestChangesOperation
r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested" r.summary = "Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested"
r.operationID = "actionSubmissionRequestChanges" r.operationID = "actionSubmissionRequestChanges"
@ -1106,7 +711,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionRevokeOperation r.name = ActionSubmissionRevokeOperation
r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction" r.summary = "Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction"
r.operationID = "actionSubmissionRevoke" r.operationID = "actionSubmissionRevoke"
@ -1134,7 +739,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionSubmitOperation r.name = ActionSubmissionSubmitOperation
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted" r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
r.operationID = "actionSubmissionSubmit" r.operationID = "actionSubmissionSubmit"
@ -1171,7 +776,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionTriggerPublishOperation r.name = ActionSubmissionTriggerPublishOperation
r.summary = "Role Admin changes status from Validated -> Publishing" r.summary = "Role Admin changes status from Validated -> Publishing"
r.operationID = "actionSubmissionTriggerPublish" r.operationID = "actionSubmissionTriggerPublish"
@ -1196,7 +801,7 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionTriggerValidateOperation r.name = ActionSubmissionTriggerValidateOperation
r.summary = "Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating" r.summary = "Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating"
r.operationID = "actionSubmissionTriggerValidate" r.operationID = "actionSubmissionTriggerValidate"
@ -1213,21 +818,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
} }
elem = origElem elem = origElem
case 'v': // Prefix: "validator-" case 'v': // Prefix: "validate"
origElem := elem origElem := elem
if l := len("validator-"); len(elem) >= l && elem[0:l] == "validator-" { if l := len("validate"); len(elem) >= l && elem[0:l] == "validate" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'p': // Prefix: "published"
origElem := elem
if l := len("published"); len(elem) >= l && elem[0:l] == "published" {
elem = elem[l:] elem = elem[l:]
} else { } else {
break break
@ -1236,36 +829,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
if len(elem) == 0 { if len(elem) == 0 {
// Leaf node. // Leaf node.
switch method { switch method {
case "POST": case "PATCH":
r.name = ActionSubmissionPublishOperation
r.summary = "(Internal endpoint) Role Validator changes status from Publishing -> Published"
r.operationID = "actionSubmissionPublish"
r.pathPattern = "/submissions/{SubmissionID}/status/validator-published"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
case 'v': // Prefix: "validated"
origElem := elem
if l := len("validated"); len(elem) >= l && elem[0:l] == "validated" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "POST":
r.name = ActionSubmissionValidateOperation r.name = ActionSubmissionValidateOperation
r.summary = "(Internal endpoint) Role Validator changes status from Validating -> Validated" r.summary = "Role Validator changes status from Validating -> Validated"
r.operationID = "actionSubmissionValidate" r.operationID = "actionSubmissionValidate"
r.pathPattern = "/submissions/{SubmissionID}/status/validator-validated" r.pathPattern = "/submissions/{SubmissionID}/status/validate"
r.args = args r.args = args
r.count = 1 r.count = 1
return r, true return r, true
@ -1288,12 +856,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
elem = origElem elem = origElem
} }
elem = origElem
}
elem = origElem
}
} }
return r, false return r, false
} }

View File

@ -10,29 +10,29 @@ func (s *ErrorStatusCode) Error() string {
return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response) return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response)
} }
// ActionSubmissionPublishNoContent is response for ActionSubmissionPublish operation. // ActionSubmissionPublishOK is response for ActionSubmissionPublish operation.
type ActionSubmissionPublishNoContent struct{} type ActionSubmissionPublishOK struct{}
// ActionSubmissionRejectNoContent is response for ActionSubmissionReject operation. // ActionSubmissionRejectOK is response for ActionSubmissionReject operation.
type ActionSubmissionRejectNoContent struct{} type ActionSubmissionRejectOK struct{}
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation. // ActionSubmissionRequestChangesOK is response for ActionSubmissionRequestChanges operation.
type ActionSubmissionRequestChangesNoContent struct{} type ActionSubmissionRequestChangesOK struct{}
// ActionSubmissionRevokeNoContent is response for ActionSubmissionRevoke operation. // ActionSubmissionRevokeOK is response for ActionSubmissionRevoke operation.
type ActionSubmissionRevokeNoContent struct{} type ActionSubmissionRevokeOK struct{}
// ActionSubmissionSubmitNoContent is response for ActionSubmissionSubmit operation. // ActionSubmissionSubmitOK is response for ActionSubmissionSubmit operation.
type ActionSubmissionSubmitNoContent struct{} type ActionSubmissionSubmitOK struct{}
// ActionSubmissionTriggerPublishNoContent is response for ActionSubmissionTriggerPublish operation. // ActionSubmissionTriggerPublishOK is response for ActionSubmissionTriggerPublish operation.
type ActionSubmissionTriggerPublishNoContent struct{} type ActionSubmissionTriggerPublishOK struct{}
// ActionSubmissionTriggerValidateNoContent is response for ActionSubmissionTriggerValidate operation. // ActionSubmissionTriggerValidateOK is response for ActionSubmissionTriggerValidate operation.
type ActionSubmissionTriggerValidateNoContent struct{} type ActionSubmissionTriggerValidateOK struct{}
// ActionSubmissionValidateNoContent is response for ActionSubmissionValidate operation. // ActionSubmissionValidateOK is response for ActionSubmissionValidate operation.
type ActionSubmissionValidateNoContent struct{} type ActionSubmissionValidateOK struct{}
type CookieAuth struct { type CookieAuth struct {
APIKey string APIKey string
@ -48,12 +48,6 @@ func (s *CookieAuth) SetAPIKey(val string) {
s.APIKey = val s.APIKey = val
} }
// DeleteScriptNoContent is response for DeleteScript operation.
type DeleteScriptNoContent struct{}
// DeleteScriptPolicyNoContent is response for DeleteScriptPolicy operation.
type DeleteScriptPolicyNoContent struct{}
// Represents error object. // Represents error object.
// Ref: #/components/schemas/Error // Ref: #/components/schemas/Error
type Error struct { type Error struct {
@ -109,19 +103,65 @@ func (s *ErrorStatusCode) SetResponse(val Error) {
// Ref: #/components/schemas/Id // Ref: #/components/schemas/Id
type ID struct { type ID struct {
ID int64 `json:"ID"` ID OptInt64 `json:"ID"`
} }
// GetID returns the value of ID. // GetID returns the value of ID.
func (s *ID) GetID() int64 { func (s *ID) GetID() OptInt64 {
return s.ID return s.ID
} }
// SetID sets the value of ID. // SetID sets the value of ID.
func (s *ID) SetID(val int64) { func (s *ID) SetID(val OptInt64) {
s.ID = val s.ID = val
} }
// NewOptBool returns new OptBool with value set to v.
func NewOptBool(v bool) OptBool {
return OptBool{
Value: v,
Set: true,
}
}
// OptBool is optional bool.
type OptBool struct {
Value bool
Set bool
}
// IsSet returns true if OptBool was set.
func (o OptBool) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptBool) Reset() {
var v bool
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptBool) SetTo(v bool) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptBool) Get() (v bool, ok bool) {
if !o.Set {
return v, false
}
return o.Value, true
}
// Or returns value if set, or given parameter if does not.
func (o OptBool) Or(d bool) bool {
if v, ok := o.Get(); ok {
return v
}
return d
}
// NewOptInt32 returns new OptInt32 with value set to v. // NewOptInt32 returns new OptInt32 with value set to v.
func NewOptInt32(v int32) OptInt32 { func NewOptInt32(v int32) OptInt32 {
return OptInt32{ return OptInt32{
@ -260,6 +300,52 @@ func (o OptString) Or(d string) string {
return d return d
} }
// NewOptSubmissionCreate returns new OptSubmissionCreate with value set to v.
func NewOptSubmissionCreate(v SubmissionCreate) OptSubmissionCreate {
return OptSubmissionCreate{
Value: v,
Set: true,
}
}
// OptSubmissionCreate is optional SubmissionCreate.
type OptSubmissionCreate struct {
Value SubmissionCreate
Set bool
}
// IsSet returns true if OptSubmissionCreate was set.
func (o OptSubmissionCreate) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptSubmissionCreate) Reset() {
var v SubmissionCreate
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptSubmissionCreate) SetTo(v SubmissionCreate) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptSubmissionCreate) Get() (v SubmissionCreate, ok bool) {
if !o.Set {
return v, false
}
return o.Value, true
}
// Or returns value if set, or given parameter if does not.
func (o OptSubmissionCreate) Or(d SubmissionCreate) SubmissionCreate {
if v, ok := o.Get(); ok {
return v
}
return d
}
// NewOptSubmissionFilter returns new OptSubmissionFilter with value set to v. // NewOptSubmissionFilter returns new OptSubmissionFilter with value set to v.
func NewOptSubmissionFilter(v SubmissionFilter) OptSubmissionFilter { func NewOptSubmissionFilter(v SubmissionFilter) OptSubmissionFilter {
return OptSubmissionFilter{ return OptSubmissionFilter{
@ -332,322 +418,75 @@ func (s *Pagination) SetLimit(val int32) {
s.Limit = val s.Limit = val
} }
// Ref: #/components/schemas/Script // PatchSubmissionCompletedOK is response for PatchSubmissionCompleted operation.
type Script struct { type PatchSubmissionCompletedOK struct{}
ID int64 `json:"ID"`
Hash string `json:"Hash"`
Source string `json:"Source"`
SubmissionID int64 `json:"SubmissionID"`
}
// GetID returns the value of ID. // PatchSubmissionModelOK is response for PatchSubmissionModel operation.
func (s *Script) GetID() int64 { type PatchSubmissionModelOK struct{}
return s.ID
}
// GetHash returns the value of Hash.
func (s *Script) GetHash() string {
return s.Hash
}
// GetSource returns the value of Source.
func (s *Script) GetSource() string {
return s.Source
}
// GetSubmissionID returns the value of SubmissionID.
func (s *Script) GetSubmissionID() int64 {
return s.SubmissionID
}
// SetID sets the value of ID.
func (s *Script) SetID(val int64) {
s.ID = val
}
// SetHash sets the value of Hash.
func (s *Script) SetHash(val string) {
s.Hash = val
}
// SetSource sets the value of Source.
func (s *Script) SetSource(val string) {
s.Source = val
}
// SetSubmissionID sets the value of SubmissionID.
func (s *Script) SetSubmissionID(val int64) {
s.SubmissionID = val
}
// Ref: #/components/schemas/ScriptCreate
type ScriptCreate struct {
Source string `json:"Source"`
SubmissionID OptInt64 `json:"SubmissionID"`
}
// GetSource returns the value of Source.
func (s *ScriptCreate) GetSource() string {
return s.Source
}
// GetSubmissionID returns the value of SubmissionID.
func (s *ScriptCreate) GetSubmissionID() OptInt64 {
return s.SubmissionID
}
// SetSource sets the value of Source.
func (s *ScriptCreate) SetSource(val string) {
s.Source = val
}
// SetSubmissionID sets the value of SubmissionID.
func (s *ScriptCreate) SetSubmissionID(val OptInt64) {
s.SubmissionID = val
}
// Ref: #/components/schemas/ScriptPolicy
type ScriptPolicy struct {
ID int64 `json:"ID"`
FromScriptHash string `json:"FromScriptHash"`
ToScriptID int64 `json:"ToScriptID"`
Policy int32 `json:"Policy"`
}
// GetID returns the value of ID.
func (s *ScriptPolicy) GetID() int64 {
return s.ID
}
// GetFromScriptHash returns the value of FromScriptHash.
func (s *ScriptPolicy) GetFromScriptHash() string {
return s.FromScriptHash
}
// GetToScriptID returns the value of ToScriptID.
func (s *ScriptPolicy) GetToScriptID() int64 {
return s.ToScriptID
}
// GetPolicy returns the value of Policy.
func (s *ScriptPolicy) GetPolicy() int32 {
return s.Policy
}
// SetID sets the value of ID.
func (s *ScriptPolicy) SetID(val int64) {
s.ID = val
}
// SetFromScriptHash sets the value of FromScriptHash.
func (s *ScriptPolicy) SetFromScriptHash(val string) {
s.FromScriptHash = val
}
// SetToScriptID sets the value of ToScriptID.
func (s *ScriptPolicy) SetToScriptID(val int64) {
s.ToScriptID = val
}
// SetPolicy sets the value of Policy.
func (s *ScriptPolicy) SetPolicy(val int32) {
s.Policy = val
}
// Ref: #/components/schemas/ScriptPolicyCreate
type ScriptPolicyCreate struct {
FromScriptID int64 `json:"FromScriptID"`
ToScriptID int64 `json:"ToScriptID"`
Policy int32 `json:"Policy"`
}
// GetFromScriptID returns the value of FromScriptID.
func (s *ScriptPolicyCreate) GetFromScriptID() int64 {
return s.FromScriptID
}
// GetToScriptID returns the value of ToScriptID.
func (s *ScriptPolicyCreate) GetToScriptID() int64 {
return s.ToScriptID
}
// GetPolicy returns the value of Policy.
func (s *ScriptPolicyCreate) GetPolicy() int32 {
return s.Policy
}
// SetFromScriptID sets the value of FromScriptID.
func (s *ScriptPolicyCreate) SetFromScriptID(val int64) {
s.FromScriptID = val
}
// SetToScriptID sets the value of ToScriptID.
func (s *ScriptPolicyCreate) SetToScriptID(val int64) {
s.ToScriptID = val
}
// SetPolicy sets the value of Policy.
func (s *ScriptPolicyCreate) SetPolicy(val int32) {
s.Policy = val
}
// Ref: #/components/schemas/ScriptPolicyUpdate
type ScriptPolicyUpdate struct {
ID int64 `json:"ID"`
FromScriptID OptInt64 `json:"FromScriptID"`
ToScriptID OptInt64 `json:"ToScriptID"`
Policy OptInt32 `json:"Policy"`
}
// GetID returns the value of ID.
func (s *ScriptPolicyUpdate) GetID() int64 {
return s.ID
}
// GetFromScriptID returns the value of FromScriptID.
func (s *ScriptPolicyUpdate) GetFromScriptID() OptInt64 {
return s.FromScriptID
}
// GetToScriptID returns the value of ToScriptID.
func (s *ScriptPolicyUpdate) GetToScriptID() OptInt64 {
return s.ToScriptID
}
// GetPolicy returns the value of Policy.
func (s *ScriptPolicyUpdate) GetPolicy() OptInt32 {
return s.Policy
}
// SetID sets the value of ID.
func (s *ScriptPolicyUpdate) SetID(val int64) {
s.ID = val
}
// SetFromScriptID sets the value of FromScriptID.
func (s *ScriptPolicyUpdate) SetFromScriptID(val OptInt64) {
s.FromScriptID = val
}
// SetToScriptID sets the value of ToScriptID.
func (s *ScriptPolicyUpdate) SetToScriptID(val OptInt64) {
s.ToScriptID = val
}
// SetPolicy sets the value of Policy.
func (s *ScriptPolicyUpdate) SetPolicy(val OptInt32) {
s.Policy = val
}
// Ref: #/components/schemas/ScriptUpdate
type ScriptUpdate struct {
ID int64 `json:"ID"`
Source OptString `json:"Source"`
SubmissionID OptInt64 `json:"SubmissionID"`
}
// GetID returns the value of ID.
func (s *ScriptUpdate) GetID() int64 {
return s.ID
}
// GetSource returns the value of Source.
func (s *ScriptUpdate) GetSource() OptString {
return s.Source
}
// GetSubmissionID returns the value of SubmissionID.
func (s *ScriptUpdate) GetSubmissionID() OptInt64 {
return s.SubmissionID
}
// SetID sets the value of ID.
func (s *ScriptUpdate) SetID(val int64) {
s.ID = val
}
// SetSource sets the value of Source.
func (s *ScriptUpdate) SetSource(val OptString) {
s.Source = val
}
// SetSubmissionID sets the value of SubmissionID.
func (s *ScriptUpdate) SetSubmissionID(val OptInt64) {
s.SubmissionID = val
}
// SetSubmissionCompletedNoContent is response for SetSubmissionCompleted operation.
type SetSubmissionCompletedNoContent struct{}
// Ref: #/components/schemas/Submission // Ref: #/components/schemas/Submission
type Submission struct { type Submission struct {
ID int64 `json:"ID"` ID OptInt64 `json:"ID"`
DisplayName string `json:"DisplayName"` DisplayName OptString `json:"DisplayName"`
Creator string `json:"Creator"` Creator OptString `json:"Creator"`
GameID int32 `json:"GameID"` GameID OptInt32 `json:"GameID"`
CreatedAt int64 `json:"CreatedAt"` Date OptInt64 `json:"Date"`
UpdatedAt int64 `json:"UpdatedAt"` Submitter OptInt64 `json:"Submitter"`
Submitter int64 `json:"Submitter"` AssetID OptInt64 `json:"AssetID"`
AssetID int64 `json:"AssetID"` AssetVersion OptInt64 `json:"AssetVersion"`
AssetVersion int64 `json:"AssetVersion"` Completed OptBool `json:"Completed"`
Completed bool `json:"Completed"` SubmissionType OptInt32 `json:"SubmissionType"`
SubmissionType int32 `json:"SubmissionType"`
TargetAssetID OptInt64 `json:"TargetAssetID"` TargetAssetID OptInt64 `json:"TargetAssetID"`
StatusID int32 `json:"StatusID"` StatusID OptInt32 `json:"StatusID"`
} }
// GetID returns the value of ID. // GetID returns the value of ID.
func (s *Submission) GetID() int64 { func (s *Submission) GetID() OptInt64 {
return s.ID return s.ID
} }
// GetDisplayName returns the value of DisplayName. // GetDisplayName returns the value of DisplayName.
func (s *Submission) GetDisplayName() string { func (s *Submission) GetDisplayName() OptString {
return s.DisplayName return s.DisplayName
} }
// GetCreator returns the value of Creator. // GetCreator returns the value of Creator.
func (s *Submission) GetCreator() string { func (s *Submission) GetCreator() OptString {
return s.Creator return s.Creator
} }
// GetGameID returns the value of GameID. // GetGameID returns the value of GameID.
func (s *Submission) GetGameID() int32 { func (s *Submission) GetGameID() OptInt32 {
return s.GameID return s.GameID
} }
// GetCreatedAt returns the value of CreatedAt. // GetDate returns the value of Date.
func (s *Submission) GetCreatedAt() int64 { func (s *Submission) GetDate() OptInt64 {
return s.CreatedAt return s.Date
}
// GetUpdatedAt returns the value of UpdatedAt.
func (s *Submission) GetUpdatedAt() int64 {
return s.UpdatedAt
} }
// GetSubmitter returns the value of Submitter. // GetSubmitter returns the value of Submitter.
func (s *Submission) GetSubmitter() int64 { func (s *Submission) GetSubmitter() OptInt64 {
return s.Submitter return s.Submitter
} }
// GetAssetID returns the value of AssetID. // GetAssetID returns the value of AssetID.
func (s *Submission) GetAssetID() int64 { func (s *Submission) GetAssetID() OptInt64 {
return s.AssetID return s.AssetID
} }
// GetAssetVersion returns the value of AssetVersion. // GetAssetVersion returns the value of AssetVersion.
func (s *Submission) GetAssetVersion() int64 { func (s *Submission) GetAssetVersion() OptInt64 {
return s.AssetVersion return s.AssetVersion
} }
// GetCompleted returns the value of Completed. // GetCompleted returns the value of Completed.
func (s *Submission) GetCompleted() bool { func (s *Submission) GetCompleted() OptBool {
return s.Completed return s.Completed
} }
// GetSubmissionType returns the value of SubmissionType. // GetSubmissionType returns the value of SubmissionType.
func (s *Submission) GetSubmissionType() int32 { func (s *Submission) GetSubmissionType() OptInt32 {
return s.SubmissionType return s.SubmissionType
} }
@ -657,62 +496,57 @@ func (s *Submission) GetTargetAssetID() OptInt64 {
} }
// GetStatusID returns the value of StatusID. // GetStatusID returns the value of StatusID.
func (s *Submission) GetStatusID() int32 { func (s *Submission) GetStatusID() OptInt32 {
return s.StatusID return s.StatusID
} }
// SetID sets the value of ID. // SetID sets the value of ID.
func (s *Submission) SetID(val int64) { func (s *Submission) SetID(val OptInt64) {
s.ID = val s.ID = val
} }
// SetDisplayName sets the value of DisplayName. // SetDisplayName sets the value of DisplayName.
func (s *Submission) SetDisplayName(val string) { func (s *Submission) SetDisplayName(val OptString) {
s.DisplayName = val s.DisplayName = val
} }
// SetCreator sets the value of Creator. // SetCreator sets the value of Creator.
func (s *Submission) SetCreator(val string) { func (s *Submission) SetCreator(val OptString) {
s.Creator = val s.Creator = val
} }
// SetGameID sets the value of GameID. // SetGameID sets the value of GameID.
func (s *Submission) SetGameID(val int32) { func (s *Submission) SetGameID(val OptInt32) {
s.GameID = val s.GameID = val
} }
// SetCreatedAt sets the value of CreatedAt. // SetDate sets the value of Date.
func (s *Submission) SetCreatedAt(val int64) { func (s *Submission) SetDate(val OptInt64) {
s.CreatedAt = val s.Date = val
}
// SetUpdatedAt sets the value of UpdatedAt.
func (s *Submission) SetUpdatedAt(val int64) {
s.UpdatedAt = val
} }
// SetSubmitter sets the value of Submitter. // SetSubmitter sets the value of Submitter.
func (s *Submission) SetSubmitter(val int64) { func (s *Submission) SetSubmitter(val OptInt64) {
s.Submitter = val s.Submitter = val
} }
// SetAssetID sets the value of AssetID. // SetAssetID sets the value of AssetID.
func (s *Submission) SetAssetID(val int64) { func (s *Submission) SetAssetID(val OptInt64) {
s.AssetID = val s.AssetID = val
} }
// SetAssetVersion sets the value of AssetVersion. // SetAssetVersion sets the value of AssetVersion.
func (s *Submission) SetAssetVersion(val int64) { func (s *Submission) SetAssetVersion(val OptInt64) {
s.AssetVersion = val s.AssetVersion = val
} }
// SetCompleted sets the value of Completed. // SetCompleted sets the value of Completed.
func (s *Submission) SetCompleted(val bool) { func (s *Submission) SetCompleted(val OptBool) {
s.Completed = val s.Completed = val
} }
// SetSubmissionType sets the value of SubmissionType. // SetSubmissionType sets the value of SubmissionType.
func (s *Submission) SetSubmissionType(val int32) { func (s *Submission) SetSubmissionType(val OptInt32) {
s.SubmissionType = val s.SubmissionType = val
} }
@ -722,75 +556,97 @@ func (s *Submission) SetTargetAssetID(val OptInt64) {
} }
// SetStatusID sets the value of StatusID. // SetStatusID sets the value of StatusID.
func (s *Submission) SetStatusID(val int32) { func (s *Submission) SetStatusID(val OptInt32) {
s.StatusID = val s.StatusID = val
} }
// Ref: #/components/schemas/SubmissionCreate // Ref: #/components/schemas/SubmissionCreate
type SubmissionCreate struct { type SubmissionCreate struct {
DisplayName string `json:"DisplayName"` DisplayName OptString `json:"DisplayName"`
Creator string `json:"Creator"` Creator OptString `json:"Creator"`
GameID int32 `json:"GameID"` GameID OptInt32 `json:"GameID"`
AssetID int64 `json:"AssetID"` Submitter OptInt64 `json:"Submitter"`
AssetVersion int64 `json:"AssetVersion"` AssetID OptInt64 `json:"AssetID"`
AssetVersion OptInt64 `json:"AssetVersion"`
SubmissionType OptInt32 `json:"SubmissionType"`
TargetAssetID OptInt64 `json:"TargetAssetID"` TargetAssetID OptInt64 `json:"TargetAssetID"`
} }
// GetDisplayName returns the value of DisplayName. // GetDisplayName returns the value of DisplayName.
func (s *SubmissionCreate) GetDisplayName() string { func (s *SubmissionCreate) GetDisplayName() OptString {
return s.DisplayName return s.DisplayName
} }
// GetCreator returns the value of Creator. // GetCreator returns the value of Creator.
func (s *SubmissionCreate) GetCreator() string { func (s *SubmissionCreate) GetCreator() OptString {
return s.Creator return s.Creator
} }
// GetGameID returns the value of GameID. // GetGameID returns the value of GameID.
func (s *SubmissionCreate) GetGameID() int32 { func (s *SubmissionCreate) GetGameID() OptInt32 {
return s.GameID return s.GameID
} }
// GetSubmitter returns the value of Submitter.
func (s *SubmissionCreate) GetSubmitter() OptInt64 {
return s.Submitter
}
// GetAssetID returns the value of AssetID. // GetAssetID returns the value of AssetID.
func (s *SubmissionCreate) GetAssetID() int64 { func (s *SubmissionCreate) GetAssetID() OptInt64 {
return s.AssetID return s.AssetID
} }
// GetAssetVersion returns the value of AssetVersion. // GetAssetVersion returns the value of AssetVersion.
func (s *SubmissionCreate) GetAssetVersion() int64 { func (s *SubmissionCreate) GetAssetVersion() OptInt64 {
return s.AssetVersion return s.AssetVersion
} }
// GetSubmissionType returns the value of SubmissionType.
func (s *SubmissionCreate) GetSubmissionType() OptInt32 {
return s.SubmissionType
}
// GetTargetAssetID returns the value of TargetAssetID. // GetTargetAssetID returns the value of TargetAssetID.
func (s *SubmissionCreate) GetTargetAssetID() OptInt64 { func (s *SubmissionCreate) GetTargetAssetID() OptInt64 {
return s.TargetAssetID return s.TargetAssetID
} }
// SetDisplayName sets the value of DisplayName. // SetDisplayName sets the value of DisplayName.
func (s *SubmissionCreate) SetDisplayName(val string) { func (s *SubmissionCreate) SetDisplayName(val OptString) {
s.DisplayName = val s.DisplayName = val
} }
// SetCreator sets the value of Creator. // SetCreator sets the value of Creator.
func (s *SubmissionCreate) SetCreator(val string) { func (s *SubmissionCreate) SetCreator(val OptString) {
s.Creator = val s.Creator = val
} }
// SetGameID sets the value of GameID. // SetGameID sets the value of GameID.
func (s *SubmissionCreate) SetGameID(val int32) { func (s *SubmissionCreate) SetGameID(val OptInt32) {
s.GameID = val s.GameID = val
} }
// SetSubmitter sets the value of Submitter.
func (s *SubmissionCreate) SetSubmitter(val OptInt64) {
s.Submitter = val
}
// SetAssetID sets the value of AssetID. // SetAssetID sets the value of AssetID.
func (s *SubmissionCreate) SetAssetID(val int64) { func (s *SubmissionCreate) SetAssetID(val OptInt64) {
s.AssetID = val s.AssetID = val
} }
// SetAssetVersion sets the value of AssetVersion. // SetAssetVersion sets the value of AssetVersion.
func (s *SubmissionCreate) SetAssetVersion(val int64) { func (s *SubmissionCreate) SetAssetVersion(val OptInt64) {
s.AssetVersion = val s.AssetVersion = val
} }
// SetSubmissionType sets the value of SubmissionType.
func (s *SubmissionCreate) SetSubmissionType(val OptInt32) {
s.SubmissionType = val
}
// SetTargetAssetID sets the value of TargetAssetID. // SetTargetAssetID sets the value of TargetAssetID.
func (s *SubmissionCreate) SetTargetAssetID(val OptInt64) { func (s *SubmissionCreate) SetTargetAssetID(val OptInt64) {
s.TargetAssetID = val s.TargetAssetID = val
@ -798,14 +654,15 @@ func (s *SubmissionCreate) SetTargetAssetID(val OptInt64) {
// Ref: #/components/schemas/SubmissionFilter // Ref: #/components/schemas/SubmissionFilter
type SubmissionFilter struct { type SubmissionFilter struct {
ID int64 `json:"ID"` ID OptInt64 `json:"ID"`
DisplayName OptString `json:"DisplayName"` DisplayName OptString `json:"DisplayName"`
Creator OptString `json:"Creator"` Creator OptString `json:"Creator"`
GameID OptInt32 `json:"GameID"` GameID OptInt32 `json:"GameID"`
Date OptInt64 `json:"Date"`
} }
// GetID returns the value of ID. // GetID returns the value of ID.
func (s *SubmissionFilter) GetID() int64 { func (s *SubmissionFilter) GetID() OptInt64 {
return s.ID return s.ID
} }
@ -824,8 +681,13 @@ func (s *SubmissionFilter) GetGameID() OptInt32 {
return s.GameID return s.GameID
} }
// GetDate returns the value of Date.
func (s *SubmissionFilter) GetDate() OptInt64 {
return s.Date
}
// SetID sets the value of ID. // SetID sets the value of ID.
func (s *SubmissionFilter) SetID(val int64) { func (s *SubmissionFilter) SetID(val OptInt64) {
s.ID = val s.ID = val
} }
@ -844,11 +706,7 @@ func (s *SubmissionFilter) SetGameID(val OptInt32) {
s.GameID = val s.GameID = val
} }
// UpdateScriptNoContent is response for UpdateScript operation. // SetDate sets the value of Date.
type UpdateScriptNoContent struct{} func (s *SubmissionFilter) SetDate(val OptInt64) {
s.Date = val
// UpdateScriptPolicyNoContent is response for UpdateScriptPolicy operation. }
type UpdateScriptPolicyNoContent struct{}
// UpdateSubmissionModelNoContent is response for UpdateSubmissionModel operation.
type UpdateSubmissionModelNoContent struct{}

View File

@ -35,7 +35,7 @@ func findAuthorization(h http.Header, prefix string) (string, bool) {
func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) { func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {
var t CookieAuth var t CookieAuth
const parameterName = "session_id" const parameterName = "SESSIONID"
var value string var value string
switch cookie, err := req.Cookie(parameterName); { switch cookie, err := req.Cookie(parameterName); {
case err == nil: // if NO error case err == nil: // if NO error
@ -67,7 +67,7 @@ func (s *Client) securityCookieAuth(ctx context.Context, operationName Operation
return errors.Wrap(err, "security source \"CookieAuth\"") return errors.Wrap(err, "security source \"CookieAuth\"")
} }
req.AddCookie(&http.Cookie{ req.AddCookie(&http.Cookie{
Name: "session_id", Name: "SESSIONID",
Value: t.APIKey, Value: t.APIKey,
}) })
return nil return nil

View File

@ -10,100 +10,58 @@ import (
type Handler interface { type Handler interface {
// ActionSubmissionPublish implements actionSubmissionPublish operation. // ActionSubmissionPublish implements actionSubmissionPublish operation.
// //
// (Internal endpoint) Role Validator changes status from Publishing -> Published. // Role Validator changes status from Publishing -> Published.
// //
// POST /submissions/{SubmissionID}/status/validator-published // PATCH /submissions/{SubmissionID}/status/publish
ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error
// ActionSubmissionReject implements actionSubmissionReject operation. // ActionSubmissionReject implements actionSubmissionReject operation.
// //
// Role Reviewer changes status from Submitted -> Rejected. // Role Reviewer changes status from Submitted -> Rejected.
// //
// POST /submissions/{SubmissionID}/status/reject // PATCH /submissions/{SubmissionID}/status/reject
ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation. // ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
// //
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested. // Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
// //
// POST /submissions/{SubmissionID}/status/request-changes // PATCH /submissions/{SubmissionID}/status/request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionRevoke implements actionSubmissionRevoke operation. // ActionSubmissionRevoke implements actionSubmissionRevoke operation.
// //
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction. // Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
// //
// POST /submissions/{SubmissionID}/status/revoke // PATCH /submissions/{SubmissionID}/status/revoke
ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error
// ActionSubmissionSubmit implements actionSubmissionSubmit operation. // ActionSubmissionSubmit implements actionSubmissionSubmit operation.
// //
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted. // Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
// //
// POST /submissions/{SubmissionID}/status/submit // PATCH /submissions/{SubmissionID}/status/submit
ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error
// ActionSubmissionTriggerPublish implements actionSubmissionTriggerPublish operation. // ActionSubmissionTriggerPublish implements actionSubmissionTriggerPublish operation.
// //
// Role Admin changes status from Validated -> Publishing. // Role Admin changes status from Validated -> Publishing.
// //
// POST /submissions/{SubmissionID}/status/trigger-publish // PATCH /submissions/{SubmissionID}/status/trigger-publish
ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error
// ActionSubmissionTriggerValidate implements actionSubmissionTriggerValidate operation. // ActionSubmissionTriggerValidate implements actionSubmissionTriggerValidate operation.
// //
// Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating. // Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating.
// //
// POST /submissions/{SubmissionID}/status/trigger-validate // PATCH /submissions/{SubmissionID}/status/trigger-validate
ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error
// ActionSubmissionValidate implements actionSubmissionValidate operation. // ActionSubmissionValidate implements actionSubmissionValidate operation.
// //
// (Internal endpoint) Role Validator changes status from Validating -> Validated. // Role Validator changes status from Validating -> Validated.
// //
// POST /submissions/{SubmissionID}/status/validator-validated // PATCH /submissions/{SubmissionID}/status/validate
ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
CreateScript(ctx context.Context, req *ScriptCreate) (*ID, error)
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
CreateScriptPolicy(ctx context.Context, req *ScriptPolicyCreate) (*ID, error)
// CreateSubmission implements createSubmission operation. // CreateSubmission implements createSubmission operation.
// //
// Create new submission. // Create new submission.
// //
// POST /submissions // POST /submissions
CreateSubmission(ctx context.Context, req *SubmissionCreate) (*ID, error) CreateSubmission(ctx context.Context, req OptSubmissionCreate) (*ID, error)
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
//
// DELETE /scripts/{ScriptID}
DeleteScript(ctx context.Context, params DeleteScriptParams) error
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// DELETE /script-policy/id/{ScriptPolicyID}
DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
GetScript(ctx context.Context, params GetScriptParams) (*Script, error)
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/id/{ScriptPolicyID}
GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (*ScriptPolicy, error)
// GetScriptPolicyFromHash implements getScriptPolicyFromHash operation.
//
// Get the policy for the given hash of script source code.
//
// GET /script-policy/hash/{FromScriptHash}
GetScriptPolicyFromHash(ctx context.Context, params GetScriptPolicyFromHashParams) (*ScriptPolicy, error)
// GetSubmission implements getSubmission operation. // GetSubmission implements getSubmission operation.
// //
// Retrieve map with ID. // Retrieve map with ID.
@ -116,30 +74,18 @@ type Handler interface {
// //
// GET /submissions // GET /submissions
ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error) ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error)
// SetSubmissionCompleted implements setSubmissionCompleted operation. // PatchSubmissionCompleted implements patchSubmissionCompleted operation.
// //
// Retrieve map with ID. // Retrieve map with ID.
// //
// POST /submissions/{SubmissionID}/completed // PATCH /submissions/{SubmissionID}/completed
SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error
// UpdateScript implements updateScript operation. // PatchSubmissionModel implements patchSubmissionModel operation.
//
// Update the specified script by ID.
//
// POST /scripts/{ScriptID}
UpdateScript(ctx context.Context, req *ScriptUpdate, params UpdateScriptParams) error
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// POST /script-policy/id/{ScriptPolicyID}
UpdateScriptPolicy(ctx context.Context, req *ScriptPolicyUpdate, params UpdateScriptPolicyParams) error
// UpdateSubmissionModel implements updateSubmissionModel operation.
// //
// Update model following role restrictions. // Update model following role restrictions.
// //
// POST /submissions/{SubmissionID}/model // PATCH /submissions/{SubmissionID}/model
UpdateSubmissionModel(ctx context.Context, params UpdateSubmissionModelParams) error PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error
// NewError creates *ErrorStatusCode from error returned by handler. // NewError creates *ErrorStatusCode from error returned by handler.
// //
// Used for common default response. // Used for common default response.

View File

@ -15,9 +15,9 @@ var _ Handler = UnimplementedHandler{}
// ActionSubmissionPublish implements actionSubmissionPublish operation. // ActionSubmissionPublish implements actionSubmissionPublish operation.
// //
// (Internal endpoint) Role Validator changes status from Publishing -> Published. // Role Validator changes status from Publishing -> Published.
// //
// POST /submissions/{SubmissionID}/status/validator-published // PATCH /submissions/{SubmissionID}/status/publish
func (UnimplementedHandler) ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error { func (UnimplementedHandler) ActionSubmissionPublish(ctx context.Context, params ActionSubmissionPublishParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -26,7 +26,7 @@ func (UnimplementedHandler) ActionSubmissionPublish(ctx context.Context, params
// //
// Role Reviewer changes status from Submitted -> Rejected. // Role Reviewer changes status from Submitted -> Rejected.
// //
// POST /submissions/{SubmissionID}/status/reject // PATCH /submissions/{SubmissionID}/status/reject
func (UnimplementedHandler) ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error { func (UnimplementedHandler) ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -35,7 +35,7 @@ func (UnimplementedHandler) ActionSubmissionReject(ctx context.Context, params A
// //
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested. // Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
// //
// POST /submissions/{SubmissionID}/status/request-changes // PATCH /submissions/{SubmissionID}/status/request-changes
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error { func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -44,7 +44,7 @@ func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context,
// //
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction. // Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
// //
// POST /submissions/{SubmissionID}/status/revoke // PATCH /submissions/{SubmissionID}/status/revoke
func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error { func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -53,7 +53,7 @@ func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params A
// //
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted. // Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
// //
// POST /submissions/{SubmissionID}/status/submit // PATCH /submissions/{SubmissionID}/status/submit
func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error { func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -62,7 +62,7 @@ func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params A
// //
// Role Admin changes status from Validated -> Publishing. // Role Admin changes status from Validated -> Publishing.
// //
// POST /submissions/{SubmissionID}/status/trigger-publish // PATCH /submissions/{SubmissionID}/status/trigger-publish
func (UnimplementedHandler) ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error { func (UnimplementedHandler) ActionSubmissionTriggerPublish(ctx context.Context, params ActionSubmissionTriggerPublishParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
@ -71,89 +71,26 @@ func (UnimplementedHandler) ActionSubmissionTriggerPublish(ctx context.Context,
// //
// Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating. // Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating.
// //
// POST /submissions/{SubmissionID}/status/trigger-validate // PATCH /submissions/{SubmissionID}/status/trigger-validate
func (UnimplementedHandler) ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error { func (UnimplementedHandler) ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
// ActionSubmissionValidate implements actionSubmissionValidate operation. // ActionSubmissionValidate implements actionSubmissionValidate operation.
// //
// (Internal endpoint) Role Validator changes status from Validating -> Validated. // Role Validator changes status from Validating -> Validated.
// //
// POST /submissions/{SubmissionID}/status/validator-validated // PATCH /submissions/{SubmissionID}/status/validate
func (UnimplementedHandler) ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error { func (UnimplementedHandler) ActionSubmissionValidate(ctx context.Context, params ActionSubmissionValidateParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (UnimplementedHandler) CreateScript(ctx context.Context, req *ScriptCreate) (r *ID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
func (UnimplementedHandler) CreateScriptPolicy(ctx context.Context, req *ScriptPolicyCreate) (r *ID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateSubmission implements createSubmission operation. // CreateSubmission implements createSubmission operation.
// //
// Create new submission. // Create new submission.
// //
// POST /submissions // POST /submissions
func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *SubmissionCreate) (r *ID, _ error) { func (UnimplementedHandler) CreateSubmission(ctx context.Context, req OptSubmissionCreate) (r *ID, _ error) {
return r, ht.ErrNotImplemented
}
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
//
// DELETE /scripts/{ScriptID}
func (UnimplementedHandler) DeleteScript(ctx context.Context, params DeleteScriptParams) error {
return ht.ErrNotImplemented
}
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// DELETE /script-policy/id/{ScriptPolicyID}
func (UnimplementedHandler) DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error {
return ht.ErrNotImplemented
}
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
func (UnimplementedHandler) GetScript(ctx context.Context, params GetScriptParams) (r *Script, _ error) {
return r, ht.ErrNotImplemented
}
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/id/{ScriptPolicyID}
func (UnimplementedHandler) GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (r *ScriptPolicy, _ error) {
return r, ht.ErrNotImplemented
}
// GetScriptPolicyFromHash implements getScriptPolicyFromHash operation.
//
// Get the policy for the given hash of script source code.
//
// GET /script-policy/hash/{FromScriptHash}
func (UnimplementedHandler) GetScriptPolicyFromHash(ctx context.Context, params GetScriptPolicyFromHashParams) (r *ScriptPolicy, _ error) {
return r, ht.ErrNotImplemented return r, ht.ErrNotImplemented
} }
@ -175,39 +112,21 @@ func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubm
return r, ht.ErrNotImplemented return r, ht.ErrNotImplemented
} }
// SetSubmissionCompleted implements setSubmissionCompleted operation. // PatchSubmissionCompleted implements patchSubmissionCompleted operation.
// //
// Retrieve map with ID. // Retrieve map with ID.
// //
// POST /submissions/{SubmissionID}/completed // PATCH /submissions/{SubmissionID}/completed
func (UnimplementedHandler) SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error { func (UnimplementedHandler) PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }
// UpdateScript implements updateScript operation. // PatchSubmissionModel implements patchSubmissionModel operation.
//
// Update the specified script by ID.
//
// POST /scripts/{ScriptID}
func (UnimplementedHandler) UpdateScript(ctx context.Context, req *ScriptUpdate, params UpdateScriptParams) error {
return ht.ErrNotImplemented
}
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// POST /script-policy/id/{ScriptPolicyID}
func (UnimplementedHandler) UpdateScriptPolicy(ctx context.Context, req *ScriptPolicyUpdate, params UpdateScriptPolicyParams) error {
return ht.ErrNotImplemented
}
// UpdateSubmissionModel implements updateSubmissionModel operation.
// //
// Update model following role restrictions. // Update model following role restrictions.
// //
// POST /submissions/{SubmissionID}/model // PATCH /submissions/{SubmissionID}/model
func (UnimplementedHandler) UpdateSubmissionModel(ctx context.Context, params UpdateSubmissionModelParams) error { func (UnimplementedHandler) PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error {
return ht.ErrNotImplemented return ht.ErrNotImplemented
} }

View File

@ -124,7 +124,10 @@ func (s *Pagination) DecodeURI(d uri.Decoder) error {
// EncodeURI encodes SubmissionFilter as URI form. // EncodeURI encodes SubmissionFilter as URI form.
func (s *SubmissionFilter) EncodeURI(e uri.Encoder) error { func (s *SubmissionFilter) EncodeURI(e uri.Encoder) error {
if err := e.EncodeField("ID", func(e uri.Encoder) error { if err := e.EncodeField("ID", func(e uri.Encoder) error {
return e.EncodeValue(conv.Int64ToString(s.ID)) if val, ok := s.ID.Get(); ok {
return e.EncodeValue(conv.Int64ToString(val))
}
return nil
}); err != nil { }); err != nil {
return errors.Wrap(err, "encode field \"ID\"") return errors.Wrap(err, "encode field \"ID\"")
} }
@ -152,14 +155,23 @@ func (s *SubmissionFilter) EncodeURI(e uri.Encoder) error {
}); err != nil { }); err != nil {
return errors.Wrap(err, "encode field \"GameID\"") return errors.Wrap(err, "encode field \"GameID\"")
} }
if err := e.EncodeField("Date", func(e uri.Encoder) error {
if val, ok := s.Date.Get(); ok {
return e.EncodeValue(conv.Int64ToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"Date\"")
}
return nil return nil
} }
var uriFieldsNameOfSubmissionFilter = [4]string{ var uriFieldsNameOfSubmissionFilter = [5]string{
0: "ID", 0: "ID",
1: "DisplayName", 1: "DisplayName",
2: "Creator", 2: "Creator",
3: "GameID", 3: "GameID",
4: "Date",
} }
// DecodeURI decodes SubmissionFilter from URI form. // DecodeURI decodes SubmissionFilter from URI form.
@ -167,12 +179,12 @@ func (s *SubmissionFilter) DecodeURI(d uri.Decoder) error {
if s == nil { if s == nil {
return errors.New("invalid: unable to decode SubmissionFilter to nil") return errors.New("invalid: unable to decode SubmissionFilter to nil")
} }
var requiredBitSet [1]uint8
if err := d.DecodeFields(func(k string, d uri.Decoder) error { if err := d.DecodeFields(func(k string, d uri.Decoder) error {
switch k { switch k {
case "ID": case "ID":
requiredBitSet[0] |= 1 << 0 if err := func() error {
var sDotIDVal int64
if err := func() error { if err := func() error {
val, err := d.DecodeValue() val, err := d.DecodeValue()
if err != nil { if err != nil {
@ -184,7 +196,12 @@ func (s *SubmissionFilter) DecodeURI(d uri.Decoder) error {
return err return err
} }
s.ID = c sDotIDVal = c
return nil
}(); err != nil {
return err
}
s.ID.SetTo(sDotIDVal)
return nil return nil
}(); err != nil { }(); err != nil {
return errors.Wrap(err, "decode field \"ID\"") return errors.Wrap(err, "decode field \"ID\"")
@ -261,6 +278,30 @@ func (s *SubmissionFilter) DecodeURI(d uri.Decoder) error {
}(); err != nil { }(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"") return errors.Wrap(err, "decode field \"GameID\"")
} }
case "Date":
if err := func() error {
var sDotDateVal int64
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
sDotDateVal = c
return nil
}(); err != nil {
return err
}
s.Date.SetTo(sDotDateVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Date\"")
}
default: default:
return nil return nil
} }
@ -268,38 +309,6 @@ func (s *SubmissionFilter) DecodeURI(d uri.Decoder) error {
}); err != nil { }); err != nil {
return errors.Wrap(err, "decode SubmissionFilter") return errors.Wrap(err, "decode SubmissionFilter")
} }
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000001,
} {
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(uriFieldsNameOfSubmissionFilter) {
name = uriFieldsNameOfSubmissionFilter[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 return nil
} }

View File

@ -59,317 +59,3 @@ func (s *Pagination) Validate() error {
} }
return nil return nil
} }
func (s *Script) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 16,
MinLengthSet: true,
MaxLength: 16,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Hash)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Hash",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 1048576,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Source)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Source",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 1048576,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Source)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Source",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicy) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 16,
MinLengthSet: true,
MaxLength: 16,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.FromScriptHash)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "FromScriptHash",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptUpdate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if value, ok := s.Source.Get(); ok {
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 1048576,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(value)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Source",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *Submission) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *SubmissionCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *SubmissionFilter) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if value, ok := s.DisplayName.Get(); ok {
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(value)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if value, ok := s.Creator.Get(); ok {
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(value)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}

View File

@ -2,16 +2,15 @@ package cmds
import ( import (
"fmt" "fmt"
"git.itzana.me/strafesnet/go-grpc/auth"
"git.itzana.me/strafesnet/maps-service/pkg/api" "git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore" "git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore"
"git.itzana.me/strafesnet/maps-service/pkg/service" "git.itzana.me/strafesnet/maps-service/pkg/service"
"github.com/nats-io/nats.go"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
"net/http"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/credentials/insecure"
"net/http" "github.com/nats-io/nats.go"
) )
func NewServeCommand() *cli.Command { func NewServeCommand() *cli.Command {
@ -62,18 +61,6 @@ func NewServeCommand() *cli.Command {
Value: 8080, Value: 8080,
EnvVars: []string{"PORT"}, EnvVars: []string{"PORT"},
}, },
&cli.StringFlag{
Name: "auth-rpc-host",
Usage: "Host of auth rpc",
EnvVars: []string{"AUTH_RPC_HOST"},
Value: "auth-service:8090",
},
&cli.StringFlag{
Name: "nats-host",
Usage: "Host of nats",
EnvVars: []string{"NATS_HOST"},
Value: "nats:4222",
},
}, },
} }
} }
@ -83,35 +70,21 @@ func serve(ctx *cli.Context) error {
if err != nil { if err != nil {
log.WithError(err).Fatal("failed to connect database") log.WithError(err).Fatal("failed to connect database")
} }
nc, err := nats.Connect(ctx.String("nats-host")) nc, err := nats.Connect("nats:4222")
if err != nil { if err != nil {
log.WithError(err).Fatal("failed to connect nats") log.WithError(err).Fatal("failed to connect nats")
} }
js, err := nc.JetStream()
if err != nil {
log.WithError(err).Fatal("failed to start jetstream")
}
_, err = js.AddStream(&nats.StreamConfig{
Name: "maptest",
Subjects: []string{"maptest.>"},
Retention: nats.WorkQueuePolicy,
})
if err != nil {
log.WithError(err).Fatal("failed to add stream")
}
svc := &service.Service{ svc := &service.Service{
DB: db, DB: db,
Nats: js, Nats: nc,
} }
conn, err := grpc.Dial(ctx.String("auth-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.Dial("auth-service:8090", grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
sec := service.SecurityHandler{ sec := service.SecurityHandler{
Client: auth.NewAuthServiceClient(conn), Client: conn,
} }
srv, err := api.NewServer(svc, sec, api.WithPathPrefix("/v1")) srv, err := api.NewServer(svc, sec, api.WithPathPrefix("/v1"))

View File

@ -8,13 +8,10 @@ import (
var ( var (
ErrNotExist = errors.New("resource does not exist") ErrNotExist = errors.New("resource does not exist")
ErroNoRowsAffected = errors.New("query did not affect any rows")
) )
type Datastore interface { type Datastore interface {
Submissions() Submissions Submissions() Submissions
Scripts() Scripts
ScriptPolicy() ScriptPolicy
} }
type Submissions interface { type Submissions interface {
@ -23,22 +20,6 @@ type Submissions interface {
Create(ctx context.Context, smap model.Submission) (model.Submission, error) Create(ctx context.Context, smap model.Submission) (model.Submission, error)
Update(ctx context.Context, id int64, values OptionalMap) error Update(ctx context.Context, id int64, values OptionalMap) error
IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) error IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) error
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values OptionalMap) (model.Submission, error)
Delete(ctx context.Context, id int64) error Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Submission, error) List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Submission, error)
} }
type Scripts interface {
Get(ctx context.Context, id int64) (model.Script, error)
Create(ctx context.Context, smap model.Script) (model.Script, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
}
type ScriptPolicy interface {
Get(ctx context.Context, id int64) (model.ScriptPolicy, error)
GetFromHash(ctx context.Context, hash uint64) (model.ScriptPolicy, error)
Create(ctx context.Context, smap model.ScriptPolicy) (model.ScriptPolicy, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
}

View File

@ -30,11 +30,7 @@ func New(ctx *cli.Context) (datastore.Datastore, error) {
} }
if ctx.Bool("migrate") { if ctx.Bool("migrate") {
if err := db.AutoMigrate( if err := db.AutoMigrate(&model.Submission{}); err != nil {
&model.Submission{},
&model.Script{},
&model.ScriptPolicy{},
); err != nil {
log.WithError(err).Errorln("database migration failed") log.WithError(err).Errorln("database migration failed")
return nil, err return nil, err
} }

View File

@ -12,11 +12,3 @@ type Gormstore struct {
func (g Gormstore) Submissions() datastore.Submissions { func (g Gormstore) Submissions() datastore.Submissions {
return &Submissions{db: g.db} return &Submissions{db: g.db}
} }
func (g Gormstore) Scripts() datastore.Scripts {
return &Scripts{db: g.db}
}
func (g Gormstore) ScriptPolicy() datastore.ScriptPolicy {
return &ScriptPolicy{db: g.db}
}

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 ScriptPolicy struct {
db *gorm.DB
}
func (env *ScriptPolicy) Get(ctx context.Context, id int64) (model.ScriptPolicy, error) {
var mdl model.ScriptPolicy
if err := env.db.First(&mdl, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
}
return mdl, nil
}
func (env *ScriptPolicy) GetFromHash(ctx context.Context, hash uint64) (model.ScriptPolicy, error) {
var mdl model.ScriptPolicy
if err := env.db.Model(&model.ScriptPolicy{}).Where("hash = ?", hash).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
}
return mdl, nil
}
func (env *ScriptPolicy) Create(ctx context.Context, smap model.ScriptPolicy) (model.ScriptPolicy, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *ScriptPolicy) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.ScriptPolicy{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *ScriptPolicy) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.ScriptPolicy{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}

View File

@ -1,84 +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 Scripts struct {
db *gorm.DB
}
func (env *Scripts) Get(ctx context.Context, id int64) (model.Script, error) {
var mdl model.Script
if err := env.db.First(&mdl, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
}
return mdl, nil
}
func (env *Scripts) GetList(ctx context.Context, id []int64) ([]model.Script, error) {
var mapList []model.Script
if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
return mapList, err
}
return mapList, nil
}
func (env *Scripts) Create(ctx context.Context, smap model.Script) (model.Script, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Scripts) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Script{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
// the update can only occur if the status matches one of the provided values.
func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Script{}).Where("id = ?", id).Where("status IN ?", statuses).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Scripts) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Script{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Scripts) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.Script, error) {
var maps []model.Script
if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
return nil, err
}
return maps, nil
}

View File

@ -7,7 +7,6 @@ import (
"git.itzana.me/strafesnet/maps-service/pkg/datastore" "git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model" "git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm" "gorm.io/gorm"
"gorm.io/gorm/clause"
) )
type Submissions struct { type Submissions struct {
@ -54,7 +53,7 @@ func (env *Submissions) Update(ctx context.Context, id int64, values datastore.O
// the update can only occur if the status matches one of the provided values. // the update can only occur if the status matches one of the provided values.
func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error { func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Submission{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map()).Error; err != nil { if err := env.db.Model(&model.Submission{}).Where("id = ?", id).Where("status IN ?",statuses).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist return datastore.ErrNotExist
} }
@ -64,29 +63,6 @@ func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, status
return nil return nil
} }
// the update can only occur if the status matches one of the provided values.
// returns the updated value
func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.Status, values datastore.OptionalMap) (model.Submission, error) {
var submission model.Submission
result := env.db.Model(&submission).
Clauses(clause.Returning{}).
Where("id = ?", id).
Where("status_id IN ?", statuses).
Updates(values.Map())
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return submission, datastore.ErrNotExist
}
return submission, result.Error
}
if result.RowsAffected == 0 {
return submission, datastore.ErroNoRowsAffected
}
return submission, nil
}
func (env *Submissions) Delete(ctx context.Context, id int64) error { func (env *Submissions) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Submission{}, id).Error; err != nil { if err := env.db.Delete(&model.Submission{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound { if err == gorm.ErrRecordNotFound {

View File

@ -1,32 +0,0 @@
package model
// These represent the information needed in the nats message
// to perform the operation, they are encoded to json
// Requests are sent from maps-service to validator
type ValidateRequest struct {
// submission_id is passed back in the response message
SubmissionID int64
ModelID uint64
ModelVersion uint64
ValidatedModelID uint64 // optional value
}
// Create a new map
type PublishNewRequest struct {
SubmissionID int64
ModelID uint64
ModelVersion uint64
Creator string
DisplayName string
GameID uint32
//games HashSet<GameID>
}
type PublishFixRequest struct {
SubmissionID int64
ModelID uint64
ModelVersion uint64
TargetAssetID uint64
}

View File

@ -1,27 +0,0 @@
package model
import "time"
type Policy int32
const (
ScriptPolicyAllowed Policy = 0
ScriptPolicyBlocked Policy = 1
ScriptPolicyDelete Policy = 2
ScriptPolicyReplace Policy = 3
)
type ScriptPolicy struct {
ID int64 `gorm:"primaryKey"`
// Hash of the source code that leads to this policy.
// If this is a replacement mapping, the original source may not be pointed to by any policy.
// The original source should still exist in the scripts table, which can be located by the same hash.
FromScriptHash uint64
// The ID of the replacement source (ScriptPolicyReplace)
// or verbatim source (ScriptPolicyAllowed)
// or 0 (other)
ToScriptID int64
Policy Policy
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@ -1,12 +0,0 @@
package model
import "time"
type Script struct {
ID int64 `gorm:"primaryKey"`
Hash uint64
Source string
SubmissionID int64 // which submission did this script first appear in
CreatedAt time.Time
UpdatedAt time.Time
}

View File

@ -4,31 +4,30 @@ import "time"
type Status int32 type Status int32
const ( const(
StatusPublished Status = 8 StatusPublished Status=8
StatusRejected Status = 7 StatusRejected Status=7
StatusPublishing Status = 6 StatusPublishing Status=6
StatusValidated Status = 5 StatusValidated Status=5
StatusValidating Status = 4 StatusValidating Status=4
StatusAccepted Status = 3 StatusAccepted Status=3
StatusChangesRequested Status = 2 StatusChangesRequested Status=2
StatusSubmitted Status = 1 StatusSubmitted Status=1
StatusUnderConstruction Status = 0 StatusUnderConstruction Status=0
) )
type Submission struct { type Submission struct {
ID int64 `gorm:"primaryKey"` ID int64
DisplayName string DisplayName string
Creator string Creator string
GameID int32 GameID int32
CreatedAt time.Time Date time.Time
UpdatedAt time.Time Submitter int64 // UserID
Submitter uint64 // UserID AssetID int64
AssetID uint64 AssetVersion int64
AssetVersion uint64 Completed bool
Completed bool // Has this version of the map been completed at least once on maptest TargetAssetID int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
TargetAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
StatusID Status StatusID Status
} }

View File

@ -1,156 +0,0 @@
package service
import (
"context"
"fmt"
"strconv"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
func (svc *Service) CreateScriptPolicy(ctx context.Context, req *api.ScriptPolicyCreate) (*api.ID, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return nil, ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return nil, ErrPermissionDenied
}
from_script, err := svc.DB.Scripts().Get(ctx, req.FromScriptID)
if err != nil {
return nil, err
}
// the existence of ToScriptID does not need to be validated because it's checked by a foreign key constraint.
script, err := svc.DB.ScriptPolicy().Create(ctx, model.ScriptPolicy{
ID: 0,
FromScriptHash: from_script.Hash,
ToScriptID: req.ToScriptID,
Policy: model.Policy(req.Policy),
})
if err != nil {
return nil, err
}
return &api.ID{
ID: script.ID,
}, nil
}
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// DELETE /script-policy/id/{ScriptPolicyID}
func (svc *Service) DeleteScriptPolicy(ctx context.Context, params api.DeleteScriptPolicyParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return ErrPermissionDenied
}
return svc.DB.ScriptPolicy().Delete(ctx, params.ScriptPolicyID)
}
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/id/{ScriptPolicyID}
func (svc *Service) GetScriptPolicy(ctx context.Context, params api.GetScriptPolicyParams) (*api.ScriptPolicy, error) {
_, ok := ctx.Value("UserInfo").(UserInfo)
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
}
return &api.ScriptPolicy{
ID: policy.ID,
FromScriptHash: fmt.Sprintf("%x", policy.FromScriptHash),
ToScriptID: policy.ToScriptID,
Policy: int32(policy.Policy),
}, nil
}
// GetScriptPolicyFromHash implements getScriptPolicyFromHash operation.
//
// Get the policy for the given hash of script source code.
//
// GET /script-policy/hash/{FromScriptHash}
func (svc *Service) GetScriptPolicyFromHash(ctx context.Context, params api.GetScriptPolicyFromHashParams) (*api.ScriptPolicy, error) {
_, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return nil, ErrUserInfo
}
// Read permission for script policy only requires you to be logged in
// parse hash from hex
hash, err := strconv.ParseUint(params.FromScriptHash, 16, 64)
if err != nil {
return nil, err
}
policy, err := svc.DB.ScriptPolicy().GetFromHash(ctx, hash)
if err != nil {
return nil, err
}
return &api.ScriptPolicy{
ID: policy.ID,
FromScriptHash: fmt.Sprintf("%x", policy.FromScriptHash),
ToScriptID: policy.ToScriptID,
Policy: int32(policy.Policy),
}, nil
}
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// PATCH /script-policy/id/{ScriptPolicyID}
func (svc *Service) UpdateScriptPolicy(ctx context.Context, req *api.ScriptPolicyUpdate, params api.UpdateScriptPolicyParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return ErrPermissionDenied
}
pmap := datastore.Optional()
if from_script_id, ok := req.FromScriptID.Get(); ok {
from_script, err := svc.DB.Scripts().Get(ctx, from_script_id)
if err != nil {
return err
}
pmap.Add("from_script_hash", from_script.Hash)
}
if to_script_id, ok := req.ToScriptID.Get(); ok {
pmap.Add("to_script_id", to_script_id)
}
if policy, ok := req.Policy.Get(); ok {
pmap.Add("policy", policy)
}
return svc.DB.ScriptPolicy().Update(ctx, req.ID, pmap)
}

View File

@ -1,111 +0,0 @@
package service
import (
"context"
"fmt"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"github.com/dchest/siphash"
)
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (svc *Service) CreateScript(ctx context.Context, req *api.ScriptCreate) (*api.ID, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return nil, ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return nil, ErrPermissionDenied
}
script, err := svc.DB.Scripts().Create(ctx, model.Script{
ID: 0,
Hash: siphash.Hash(0, 0, []byte(req.Source)),
Source: req.Source,
SubmissionID: req.SubmissionID.Or(0),
})
if err != nil {
return nil, err
}
return &api.ID{
ID: script.ID,
}, nil
}
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
//
// DELETE /scripts/{ScriptID}
func (svc *Service) DeleteScript(ctx context.Context, params api.DeleteScriptParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return ErrPermissionDenied
}
return svc.DB.Scripts().Delete(ctx, params.ScriptID)
}
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
func (svc *Service) GetScript(ctx context.Context, params api.GetScriptParams) (*api.Script, error) {
_, ok := ctx.Value("UserInfo").(UserInfo)
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
}
return &api.Script{
ID: script.ID,
Hash: fmt.Sprintf("%x", script.Hash),
Source: script.Source,
SubmissionID: script.SubmissionID,
}, nil
}
// UpdateScript implements updateScript operation.
//
// Update the specified script by ID.
//
// PATCH /scripts/{ScriptID}
func (svc *Service) UpdateScript(ctx context.Context, req *api.ScriptUpdate, params api.UpdateScriptParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo)
if !ok {
return ErrUserInfo
}
if !userInfo.Roles.ScriptWrite {
return ErrPermissionDenied
}
pmap := datastore.Optional()
if source, ok := req.Source.Get(); ok {
pmap.Add("source", source)
pmap.Add("hash", siphash.Hash(0, 0, []byte(source)))
}
if SubmissionID, ok := req.SubmissionID.Get(); ok {
pmap.Add("submission_id", SubmissionID)
}
return svc.DB.Scripts().Update(ctx, req.ID, pmap)
}

View File

@ -1,10 +1,11 @@
package service package service
import ( import (
"context"
"errors" "errors"
"git.itzana.me/strafesnet/go-grpc/auth" "context"
"git.itzana.me/strafesnet/maps-service/pkg/api" "git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/go-grpc/auth"
"google.golang.org/grpc"
) )
var ( var (
@ -15,80 +16,77 @@ var (
) )
var ( var (
// has SubmissionPublish RoleAdmin = 128
RoleMapAdmin int32 = 128 RoleReviewer = 64
// has SubmissionReview
RoleMapCouncil int32 = 64
) )
type Roles struct { type Roles struct {
// human roles Admin bool
SubmissionPublish bool Reviewer bool
SubmissionReview bool
ScriptWrite bool
// automated roles
Maptest bool Maptest bool
Validator bool Validator bool
} }
type UserInfo struct { type UserInfo struct {
Roles Roles Roles Roles
UserID uint64 UserID int64
} }
func (usr UserInfo) IsSubmitter(submitter uint64) bool { func (usr UserInfo) IsSubmitter(submitter int64) bool{
return usr.UserID == submitter return usr.UserID == submitter
} }
type SecurityHandler struct { type SecurityHandler struct {
Client auth.AuthServiceClient Client *grpc.ClientConn
} }
func (svc SecurityHandler) HandleCookieAuth(ctx context.Context, operationName api.OperationName, t api.CookieAuth) (context.Context, error) { func (svc SecurityHandler) HandleCookieAuth(ctx context.Context, operationName api.OperationName, t api.CookieAuth) (context.Context, error){
sessionId := t.GetAPIKey() sessionId := t.GetAPIKey()
if sessionId == "" { if sessionId == "" {
return nil, ErrMissingSessionID return nil, ErrMissingSessionID
} }
session, err := svc.Client.GetSessionUser(ctx, &auth.IdMessage{ client := auth.NewAuthServiceClient(svc.Client)
session, err := client.GetSessionUser(ctx, &auth.IdMessage{
SessionID: sessionId, SessionID: sessionId,
}) })
if err != nil { if err != nil{
return nil, err return nil, err
} }
role, err := svc.Client.GetGroupRole(ctx, &auth.IdMessage{ role, err := client.GetGroupRole(ctx, &auth.IdMessage{
SessionID: sessionId, SessionID: sessionId,
}) })
if err != nil { if err != nil{
return nil, err return nil, err
} }
validate, err := svc.Client.ValidateSession(ctx, &auth.IdMessage{ validate, err := client.ValidateSession(ctx, &auth.IdMessage{
SessionID: sessionId, SessionID: sessionId,
}) })
if err != nil { if err != nil{
return nil, err return nil, err
} }
if !validate.Valid { if !validate.Valid{
return nil, ErrInvalidSession return nil, ErrInvalidSession
} }
roles := Roles{} roles := Roles{}
// fix this when roblox udpates group roles // fix this when roblox udpates group roles
for _, r := range role.Roles { for r := range role.Roles{
if RoleMapAdmin <= r.Rank { if RoleAdmin<=r{
roles.SubmissionPublish = true roles.Admin = true
} }
if RoleMapCouncil <= r.Rank { if RoleReviewer<=r{
roles.SubmissionReview = true roles.Reviewer = true
} }
} }
newCtx := context.WithValue(ctx, "UserInfo", UserInfo{ newCtx := context.WithValue(ctx, "UserInfo", UserInfo{
Roles: roles, Roles: roles,
UserID: session.UserID, UserID: int64(session.UserID),
}) })
return newCtx, nil return newCtx, nil

View File

@ -2,40 +2,22 @@ package service
import ( import (
"context" "context"
"errors"
"git.itzana.me/strafesnet/maps-service/pkg/api" "git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore" "git.itzana.me/strafesnet/maps-service/pkg/datastore"
"github.com/nats-io/nats.go" "github.com/nats-io/nats.go"
) )
var (
// ErrPermissionDenied caller does not have the required role
ErrPermissionDenied = errors.New("Permission denied")
// ErrUserInfo user info is missing for some reason
ErrUserInfo = errors.New("Missing user info")
)
type Service struct { type Service struct {
DB datastore.Datastore DB datastore.Datastore
Nats nats.JetStreamContext Nats *nats.Conn
} }
// NewError creates *ErrorStatusCode from error returned by handler. // NewError creates *ErrorStatusCode from error returned by handler.
// //
// Used for common default response. // Used for common default response.
func (svc *Service) NewError(ctx context.Context, err error) *api.ErrorStatusCode { func (svc *Service) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
status := 500
if errors.Is(err, ErrPermissionDenied) {
status = 403
}
if errors.Is(err, ErrUserInfo) {
status = 401
}
return &api.ErrorStatusCode{ return &api.ErrorStatusCode{
StatusCode: status, StatusCode: 500,
Response: api.Error{ Response: api.Error{Message: err.Error()},
Code: int64(status),
Message: err.Error(),
},
} }
} }

View File

@ -1,38 +1,48 @@
package service package service
import ( import (
"time"
"errors"
"context" "context"
"encoding/json"
"git.itzana.me/strafesnet/maps-service/pkg/api" "git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model" "git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
)
var (
// ErrInvalidSourceStatus current submission status cannot change to destination status
ErrInvalidSourceStatus = errors.New("Invalid source status")
// ErrPermissionDenied caller does not have the required role
ErrPermissionDenied = errors.New("Permission denied")
// ErrUserInfo user info is missing for some reason
ErrUserInfo = errors.New("Missing user info")
) )
// POST /submissions // POST /submissions
func (svc *Service) CreateSubmission(ctx context.Context, request *api.SubmissionCreate) (*api.ID, error) { func (svc *Service) CreateSubmission(ctx context.Context, request api.OptSubmissionCreate) (*api.ID, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return nil, ErrUserInfo return nil, ErrUserInfo
} }
submission, err := svc.DB.Submissions().Create(ctx, model.Submission{ submission, err := svc.DB.Submissions().Create(ctx, model.Submission{
ID: 0, ID: 0,
DisplayName: request.DisplayName, DisplayName: request.Value.DisplayName.Value,
Creator: request.Creator, Creator: request.Value.Creator.Value,
GameID: request.GameID, GameID: request.Value.GameID.Value,
Submitter: userInfo.UserID, Date: time.Now(),
AssetID: uint64(request.AssetID), Submitter: int64(userInfo.UserID),
AssetVersion: uint64(request.AssetVersion), AssetID: request.Value.AssetID.Value,
AssetVersion: request.Value.AssetVersion.Value,
Completed: false, Completed: false,
TargetAssetID: uint64(request.TargetAssetID.Value), TargetAssetID: request.Value.TargetAssetID.Value,
StatusID: model.StatusUnderConstruction, StatusID: model.StatusUnderConstruction,
}) })
if err != nil { if err != nil{
return nil, err return nil, err
} }
return &api.ID{ return &api.ID{
ID: submission.ID, ID:api.NewOptInt64(submission.ID),
}, nil }, nil
} }
@ -43,22 +53,21 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
// GET /submissions/{SubmissionID} // GET /submissions/{SubmissionID}
func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionParams) (*api.Submission, error) { func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionParams) (*api.Submission, error) {
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil { if err != nil{
return nil, err return nil, err
} }
return &api.Submission{ return &api.Submission{
ID: submission.ID, ID: api.NewOptInt64(submission.ID),
DisplayName: submission.DisplayName, DisplayName: api.NewOptString(submission.DisplayName),
Creator: submission.Creator, Creator: api.NewOptString(submission.Creator),
GameID: submission.GameID, GameID: api.NewOptInt32(submission.GameID),
CreatedAt: submission.CreatedAt.Unix(), Date: api.NewOptInt64(submission.Date.Unix()),
UpdatedAt: submission.UpdatedAt.Unix(), Submitter: api.NewOptInt64(submission.Submitter),
Submitter: int64(submission.Submitter), AssetID: api.NewOptInt64(submission.AssetID),
AssetID: int64(submission.AssetID), AssetVersion: api.NewOptInt64(submission.AssetVersion),
AssetVersion: int64(submission.AssetVersion), Completed: api.NewOptBool(submission.Completed),
Completed: submission.Completed, TargetAssetID: api.NewOptInt64(submission.TargetAssetID),
TargetAssetID: api.NewOptInt64(int64(submission.TargetAssetID)), StatusID: api.NewOptInt32(int32(submission.StatusID)),
StatusID: int32(submission.StatusID),
}, nil }, nil
} }
@ -80,25 +89,24 @@ func (svc *Service) ListSubmissions(ctx context.Context, request api.ListSubmiss
Number: request.Page.GetPage(), Number: request.Page.GetPage(),
Size: request.Page.GetLimit(), Size: request.Page.GetLimit(),
}) })
if err != nil { if err != nil{
return nil, err return nil, err
} }
var resp []api.Submission var resp []api.Submission
for i := 0; i < len(items); i++ { for i := 0; i < len(items); i++ {
resp = append(resp, api.Submission{ resp = append(resp, api.Submission{
ID: items[i].ID, ID: api.NewOptInt64(items[i].ID),
DisplayName: items[i].DisplayName, DisplayName: api.NewOptString(items[i].DisplayName),
Creator: items[i].Creator, Creator: api.NewOptString(items[i].Creator),
GameID: items[i].GameID, GameID: api.NewOptInt32(items[i].GameID),
CreatedAt: items[i].CreatedAt.Unix(), Date: api.NewOptInt64(items[i].Date.Unix()),
UpdatedAt: items[i].UpdatedAt.Unix(), Submitter: api.NewOptInt64(items[i].Submitter),
Submitter: int64(items[i].Submitter), AssetID: api.NewOptInt64(items[i].AssetID),
AssetID: int64(items[i].AssetID), AssetVersion: api.NewOptInt64(items[i].AssetVersion),
AssetVersion: int64(items[i].AssetVersion), Completed: api.NewOptBool(items[i].Completed),
Completed: items[i].Completed, TargetAssetID: api.NewOptInt64(items[i].TargetAssetID),
TargetAssetID: api.NewOptInt64(int64(items[i].TargetAssetID)), StatusID: api.NewOptInt32(int32(items[i].StatusID)),
StatusID: int32(items[i].StatusID),
}) })
} }
@ -109,15 +117,15 @@ func (svc *Service) ListSubmissions(ctx context.Context, request api.ListSubmiss
// //
// Retrieve map with ID. // Retrieve map with ID.
// //
// POST /submissions/{SubmissionID}/completed // PATCH /submissions/{SubmissionID}/completed
func (svc *Service) SetSubmissionCompleted(ctx context.Context, params api.SetSubmissionCompletedParams) error { func (svc *Service) PatchSubmissionCompleted(ctx context.Context, params api.PatchSubmissionCompletedParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// check if caller has MaptestGame role (request must originate from a maptest roblox game) // check if caller has MaptestGame role (request must originate from a maptest roblox game)
if !userInfo.Roles.Maptest { if !userInfo.Roles.Maptest{
return ErrPermissionDenied return ErrPermissionDenied
} }
@ -131,21 +139,21 @@ func (svc *Service) SetSubmissionCompleted(ctx context.Context, params api.SetSu
// //
// Update model following role restrictions. // Update model following role restrictions.
// //
// POST /submissions/{SubmissionID}/model // PATCH /submissions/{SubmissionID}/model
func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.UpdateSubmissionModelParams) error { func (svc *Service) PatchSubmissionModel(ctx context.Context, params api.PatchSubmissionModelParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// read submission (this could be done with a transaction WHERE clause) // read submission (this could be done with a transaction WHERE clause)
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil { if err != nil{
return err return err
} }
// check if caller is the submitter // check if caller is the submitter
if !userInfo.IsSubmitter(submission.Submitter) { if !userInfo.IsSubmitter(submission.Submitter){
return ErrPermissionDenied return ErrPermissionDenied
} }
@ -154,237 +162,201 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
pmap.AddNotNil("asset_id", params.ModelID) pmap.AddNotNil("asset_id", params.ModelID)
pmap.AddNotNil("asset_version", params.VersionID) pmap.AddNotNil("asset_version", params.VersionID)
//always reset completed when model changes //always reset completed when model changes
pmap.Add("completed", false) pmap.Add("completed",false)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusChangesRequested, model.StatusSubmitted, model.StatusUnderConstruction}, pmap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusChangesRequested,model.StatusSubmitted,model.StatusUnderConstruction}, pmap)
} }
// ActionSubmissionPublish invokes actionSubmissionPublish operation. // ActionSubmissionPublish invokes actionSubmissionPublish operation.
// //
// Role Validator changes status from Publishing -> Published. // Role Validator changes status from Publishing -> Published.
// //
// POST /submissions/{SubmissionID}/status/publish // PATCH /submissions/{SubmissionID}/status/publish
func (svc *Service) ActionSubmissionPublish(ctx context.Context, params api.ActionSubmissionPublishParams) error { func (svc *Service) ActionSubmissionPublish(ctx context.Context, params api.ActionSubmissionPublishParams) error {
println("[ActionSubmissionPublish] Implicit Validator permission granted!") userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok{
return ErrUserInfo
}
// check if caller has required role
if !userInfo.Roles.Validator{
return ErrPermissionDenied
}
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusPublished) smap.Add("status_id",model.StatusPublished)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusPublishing}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusPublishing}, smap)
} }
// ActionSubmissionReject invokes actionSubmissionReject operation. // ActionSubmissionReject invokes actionSubmissionReject operation.
// //
// Role Reviewer changes status from Submitted -> Rejected. // Role Reviewer changes status from Submitted -> Rejected.
// //
// POST /submissions/{SubmissionID}/status/reject // PATCH /submissions/{SubmissionID}/status/reject
func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.ActionSubmissionRejectParams) error { func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.ActionSubmissionRejectParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// check if caller has required role // check if caller has required role
if !userInfo.Roles.SubmissionReview { if !userInfo.Roles.Reviewer{
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusRejected) smap.Add("status_id",model.StatusRejected)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted}, smap)
} }
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation. // ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
// //
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested. // Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
// //
// POST /submissions/{SubmissionID}/status/request-changes // PATCH /submissions/{SubmissionID}/status/request-changes
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params api.ActionSubmissionRequestChangesParams) error { func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params api.ActionSubmissionRequestChangesParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// check if caller has required role // check if caller has required role
if !userInfo.Roles.SubmissionReview { if !userInfo.Roles.Reviewer{
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusChangesRequested) smap.Add("status_id",model.StatusChangesRequested)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidated, model.StatusAccepted, model.StatusSubmitted}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidated,model.StatusAccepted,model.StatusSubmitted}, smap)
} }
// ActionSubmissionRevoke invokes actionSubmissionRevoke operation. // ActionSubmissionRevoke invokes actionSubmissionRevoke operation.
// //
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction. // Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
// //
// POST /submissions/{SubmissionID}/status/revoke // PATCH /submissions/{SubmissionID}/status/revoke
func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.ActionSubmissionRevokeParams) error { func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.ActionSubmissionRevokeParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// read submission (this could be done with a transaction WHERE clause) // read submission (this could be done with a transaction WHERE clause)
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil { if err != nil{
return err return err
} }
// check if caller is the submitter // check if caller is the submitter
if !userInfo.IsSubmitter(submission.Submitter) { if !userInfo.IsSubmitter(submission.Submitter){
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusUnderConstruction) smap.Add("status_id",model.StatusUnderConstruction)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted, model.StatusChangesRequested}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted,model.StatusChangesRequested}, smap)
} }
// ActionSubmissionSubmit invokes actionSubmissionSubmit operation. // ActionSubmissionSubmit invokes actionSubmissionSubmit operation.
// //
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted. // Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
// //
// POST /submissions/{SubmissionID}/status/submit // PATCH /submissions/{SubmissionID}/status/submit
func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.ActionSubmissionSubmitParams) error { func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.ActionSubmissionSubmitParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// read submission (this could be done with a transaction WHERE clause) // read submission (this could be done with a transaction WHERE clause)
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID) submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil { if err != nil{
return err return err
} }
// check if caller is the submitter // check if caller is the submitter
if !userInfo.IsSubmitter(submission.Submitter) { if !userInfo.IsSubmitter(submission.Submitter){
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusSubmitted) smap.Add("status_id",model.StatusSubmitted)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUnderConstruction, model.StatusChangesRequested}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusUnderConstruction,model.StatusChangesRequested}, smap)
} }
// ActionSubmissionTriggerPublish invokes actionSubmissionTriggerPublish operation. // ActionSubmissionTriggerPublish invokes actionSubmissionTriggerPublish operation.
// //
// Role Admin changes status from Validated -> Publishing. // Role Admin changes status from Validated -> Publishing.
// //
// POST /submissions/{SubmissionID}/status/trigger-publish // PATCH /submissions/{SubmissionID}/status/trigger-publish
func (svc *Service) ActionSubmissionTriggerPublish(ctx context.Context, params api.ActionSubmissionTriggerPublishParams) error { func (svc *Service) ActionSubmissionTriggerPublish(ctx context.Context, params api.ActionSubmissionTriggerPublishParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// check if caller has required role // check if caller has required role
if !userInfo.Roles.SubmissionPublish { if !userInfo.Roles.Admin{
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusPublishing) smap.Add("status_id",model.StatusPublishing)
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap) err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidated}, smap)
if err != nil { if err != nil{
return err return err
} }
// sentinel value because we are not using rust svc.Nats.Publish("publish", []byte(params.SubmissionID))
if submission.TargetAssetID == 0 {
// this is a new map
publish_new_request := model.PublishNewRequest{
SubmissionID: submission.ID,
ModelID: submission.AssetID,
ModelVersion: submission.AssetVersion,
Creator: submission.Creator,
DisplayName: submission.DisplayName,
GameID: uint32(submission.GameID),
}
j, err := json.Marshal(publish_new_request)
if err != nil {
return err
}
svc.Nats.Publish("maptest.submissions.publishnew", []byte(j))
} else {
// this is a map fix
publish_fix_request := model.PublishFixRequest{
SubmissionID: submission.ID,
ModelID: submission.AssetID,
ModelVersion: submission.AssetVersion,
TargetAssetID: submission.TargetAssetID,
}
j, err := json.Marshal(publish_fix_request)
if err != nil {
return err
}
svc.Nats.Publish("maptest.submissions.publishfix", []byte(j))
}
return nil return nil
} }
// ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation. // ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation.
// //
// Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating. // Role Reviewer triggers validation and changes status from Submitted|Accepted -> Validating.
// //
// POST /submissions/{SubmissionID}/status/trigger-validate // PATCH /submissions/{SubmissionID}/status/trigger-validate
func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params api.ActionSubmissionTriggerValidateParams) error { func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params api.ActionSubmissionTriggerValidateParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfo) userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok { if !ok{
return ErrUserInfo return ErrUserInfo
} }
// check if caller has required role // check if caller has required role
if !userInfo.Roles.SubmissionReview { if !userInfo.Roles.Reviewer{
return ErrPermissionDenied return ErrPermissionDenied
} }
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusValidating) smap.Add("status_id",model.StatusValidating)
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted, model.StatusAccepted}, smap) err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusSubmitted,model.StatusAccepted}, smap)
if err != nil { if err != nil{
return err return err
} }
validate_request := model.ValidateRequest{ svc.Nats.Publish("validate", []byte(params.SubmissionID))
SubmissionID: submission.ID,
ModelID: submission.AssetID,
ModelVersion: submission.AssetVersion,
ValidatedModelID: 0, //TODO: reuse velidation models
}
j, err := json.Marshal(validate_request)
if err != nil {
return err
}
svc.Nats.Publish("maptest.submissions.validate", []byte(j))
return nil return nil
} }
// ActionSubmissionValidate invokes actionSubmissionValidate operation. // ActionSubmissionValidate invokes actionSubmissionValidate operation.
// //
// Role Validator changes status from Validating -> Validated. // Role Validator changes status from Validating -> Validated.
// //
// POST /submissions/{SubmissionID}/status/validate // PATCH /submissions/{SubmissionID}/status/validate
func (svc *Service) ActionSubmissionValidate(ctx context.Context, params api.ActionSubmissionValidateParams) error { func (svc *Service) ActionSubmissionValidate(ctx context.Context, params api.ActionSubmissionValidateParams) error {
println("[ActionSubmissionValidate] Implicit Validator permission granted!") userInfo, ok := ctx.Value("UserInfo").(*UserInfo)
if !ok{
return ErrUserInfo
}
// check if caller has required role
if !userInfo.Roles.Validator{
return ErrPermissionDenied
}
// transaction // transaction
smap := datastore.Optional() smap := datastore.Optional()
smap.Add("status_id", model.StatusValidated) smap.Add("status_id",model.StatusValidated)
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap) return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.Status{model.StatusValidating}, smap)
} }

View File

@ -1,2 +0,0 @@
[registries.strafesnet]
index = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"

1123
validation/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -4,17 +4,13 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
api = { path = "api" }
async-nats = "0.38.0" async-nats = "0.38.0"
futures = "0.3.31" futures = "0.3.31"
rbx_asset = { version = "0.2.5", registry = "strafesnet" } rbx_asset = { version = "0.2.3", registry = "strafesnet" }
rbx_binary = { version = "0.7.4", registry = "strafesnet"} rbx_binary = { version = "0.7.4", registry = "strafesnet"}
rbx_dom_weak = { version = "2.9.0", 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"} rbx_xml = { version = "0.13.3", registry = "strafesnet"}
rust-grpc = { version = "1.0.3", registry = "strafesnet" }
serde = { version = "1.0.215", features = ["derive"] } serde = { version = "1.0.215", features = ["derive"] }
serde_json = "1.0.133" serde_json = "1.0.133"
siphasher = "1.0.1" sqlx = "0.8.2"
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread", "fs", "signal"] } tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread", "fs"] }
tonic = "0.12.3"

View File

@ -1,24 +0,0 @@
# Using the `rust-musl-builder` as base image, instead of
# the official Rust toolchain
FROM docker.io/clux/muslrust:stable AS chef
USER root
RUN cargo install cargo-chef
WORKDIR /app
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
FROM chef AS builder
COPY --from=planner /app/recipe.json recipe.json
COPY api ./api
# Notice that we are specifying the --target flag!
RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl --bin maps-validation
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
ENTRYPOINT ["/usr/local/bin/maps-validation"]

View File

@ -1,17 +0,0 @@
[package]
name = "api"
version = "0.1.0"
edition = "2021"
publish = ["strafesnet"]
repository = "https://git.itzana.me/StrafesNET/maps-service"
license = "MIT OR Apache-2.0"
description = "Browse and manage map submissions in the staging pipeline."
authors = ["Rhys Lloyd <krakow20@gmail.com>"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
reqwest = { version = "0", features = ["json"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
url = "2"

View File

@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -1,23 +0,0 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,130 +0,0 @@
#[derive(Debug)]
pub enum Error{
ParseError(url::ParseError),
Reqwest(reqwest::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{}
#[derive(serde::Deserialize)]
pub struct ScriptID(i64);
#[allow(nonstandard_style)]
pub struct GetScriptRequest{
pub ScriptID:ScriptID,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptResponse{
pub ID:i64,
pub Hash:String,
pub Source:String,
pub SubmissionID:i64,
}
#[derive(serde::Deserialize)]
#[repr(i32)]
pub enum Policy{
Allowed=0,
Blocked=1,
Delete=2,
Replace=3,
}
pub struct ScriptPolicyHashRequest{
pub hash:String,
}
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct ScriptPolicyResponse{
pub ID:i64,
pub FromScriptHash:String,
pub ToScriptID:ScriptID,
pub Policy:Policy
}
#[allow(nonstandard_style)]
pub struct UpdateSubmissionModelRequest{
pub ID:i64,
pub ModelID:u64,
pub ModelVersion:u64,
}
pub struct SubmissionID(pub i64);
#[derive(Clone)]
pub struct Context{
base_url:String,
client:reqwest::Client,
}
pub type ReqwestError=reqwest::Error;
// there are lots of action endpoints and they all follow the same pattern
macro_rules! action{
($fname:ident,$action:expr)=>{
pub async fn $fname(&self,config:SubmissionID)->Result<(),Error>{
let url_raw=format!(concat!("{}/submissions/{}/status/",$action),self.base_url,config.0);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.post(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?;
Ok(())
}
};
}
impl Context{
pub fn new(mut base_url:String)->reqwest::Result<Self>{
base_url+="/v1";
Ok(Self{
base_url,
client:reqwest::Client::new(),
})
}
async fn get(&self,url:impl reqwest::IntoUrl)->Result<reqwest::Response,reqwest::Error>{
self.client.get(url)
.send().await
}
async fn post(&self,url:impl reqwest::IntoUrl)->Result<reqwest::Response,reqwest::Error>{
self.client.post(url)
.send().await
}
pub async fn get_script(&self,config:GetScriptRequest)->Result<ScriptResponse,Error>{
let url_raw=format!("{}/scripts/{}",self.base_url,config.ScriptID.0);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn get_script_policy_from_hash(&self,config:ScriptPolicyHashRequest)->Result<ScriptPolicyResponse,Error>{
let url_raw=format!("{}/script-policy/hash/{}",self.base_url,config.hash);
let url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
self.get(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?
.json().await.map_err(Error::Reqwest)
}
pub async fn update_submission_model(&self,config:UpdateSubmissionModelRequest)->Result<(),Error>{
let url_raw=format!("{}/submissions/{}/model",self.base_url,config.ID);
let mut url=reqwest::Url::parse(url_raw.as_str()).map_err(Error::ParseError)?;
{
url.query_pairs_mut()
.append_pair("ModelID",config.ModelID.to_string().as_str())
.append_pair("ModelVersion",config.ModelVersion.to_string().as_str());
}
self.post(url).await.map_err(Error::Reqwest)?
.error_for_status().map_err(Error::Reqwest)?;
Ok(())
}
action!(action_submission_validate,"validator-validated");
action!(action_submission_publish,"validator-published");
}

View File

@ -1,20 +1,12 @@
use futures::StreamExt;
mod nats_types; mod nats_types;
mod publisher;
mod validator; mod validator;
mod publish_new;
mod publish_fix;
mod message_handler;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum StartupError{ enum StartupError{
API(api::ReqwestError), Connect(async_nats::ConnectError),
NatsConnect(async_nats::ConnectError), Subscribe(async_nats::SubscribeError),
NatsGetStream(async_nats::jetstream::context::GetStreamError),
NatsConsumer(async_nats::jetstream::stream::ConsumerError),
NatsStream(async_nats::jetstream::consumer::StreamError),
GRPCConnect(tonic::transport::Error),
} }
impl std::fmt::Display for StartupError{ impl std::fmt::Display for StartupError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@ -23,76 +15,26 @@ impl std::fmt::Display for StartupError{
} }
impl std::error::Error for StartupError{} impl std::error::Error for StartupError{}
// annoying mile-long type
pub type MapsServiceClient=rust_grpc::maps::maps_service_client::MapsServiceClient<tonic::transport::channel::Channel>;
pub const GROUP_STRAFESNET:u64=6980477;
pub const PARALLEL_REQUESTS:usize=16;
#[tokio::main] #[tokio::main]
async fn main()->Result<(),StartupError>{ async fn main()->Result<(),StartupError>{
// talk to roblox through STRAFESNET_CI2 account // cookies and clouds
let cookie=std::env::var("RBXCOOKIE").expect("RBXCOOKIE env required"); let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new("".to_owned()));
let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new(cookie)); let cloud_context=rbx_asset::cloud::CloudContext::new(rbx_asset::cloud::ApiKey::new("".to_owned()));
// maps-service api
let api_host=std::env::var("API_HOST").expect("API_HOST env required");
let api=api::Context::new(api_host).map_err(StartupError::API)?;
// nats // nats
let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required"); let nasty=async_nats::connect("nats").await.map_err(StartupError::Connect)?;
let nats_fut=async{
let nasty=async_nats::connect(nats_host).await.map_err(StartupError::NatsConnect)?;
// use nats jetstream
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.submissions.>".to_owned(),
..Default::default()
}).await.map_err(StartupError::NatsConsumer)?
.messages().await.map_err(StartupError::NatsStream)
};
// data-service grpc for creating map entries // connect to nats
let data_host=std::env::var("DATA_HOST").expect("DATA_HOST env required"); let (publisher,validator)=tokio::try_join!(
let message_handler_fut=async{ publisher::Publisher::new(nasty.clone(),cookie_context.clone(),cloud_context),
let maps_grpc=crate::MapsServiceClient::connect(data_host).await.map_err(StartupError::GRPCConnect)?; validator::Validator::new(nasty,cookie_context)
Ok(message_handler::MessageHandler::new(cookie_context,api,maps_grpc)) ).map_err(StartupError::Subscribe)?;
};
// Create a signal listener for SIGTERM // publisher thread
let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener"); tokio::spawn(publisher.run());
// run futures // run validator on the main thread indefinitely
let (mut messages,message_handler)=tokio::try_join!(nats_fut,message_handler_fut)?; validator.run().await;
// process up to PARALLEL_REQUESTS in parallel
let main_loop=async move{
static SEM:tokio::sync::Semaphore=tokio::sync::Semaphore::const_new(PARALLEL_REQUESTS);
// use memory leak to make static lifetime
let message_handler=Box::leak(Box::new(message_handler));
// acquire a permit before attempting to receive a message, exit if either fails
while let (Ok(permit),Some(message_result))=(SEM.acquire().await,messages.next().await){
// handle the message on a new thread (mainly to decode the model file)
tokio::spawn(async{
match message_handler.handle_message_result(message_result).await{
Ok(())=>println!("[Validation] Success, hooray!"),
Err(e)=>println!("[Validation] There was an error, oopsie! {e}"),
}
// explicitly call drop to make the move semantics and permit release more obvious
core::mem::drop(permit);
});
}
};
// race sigkill and main loop termination and then die
tokio::select!{
_=sig_term.recv()=>(),
_=main_loop=>(),
};
Ok(()) Ok(())
} }

View File

@ -1,48 +0,0 @@
#[allow(dead_code)]
#[derive(Debug)]
pub enum HandleMessageError{
Messages(async_nats::jetstream::consumer::pull::MessagesError),
DoubleAck(async_nats::Error),
UnknownSubject(String),
PublishNew(crate::publish_new::PublishError),
PublishFix(crate::publish_fix::PublishError),
Validation(crate::validator::ValidateError),
}
impl std::fmt::Display for HandleMessageError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for HandleMessageError{}
pub type MessageResult=Result<async_nats::jetstream::Message,async_nats::jetstream::consumer::pull::MessagesError>;
pub struct MessageHandler{
publish_new:crate::publish_new::Publisher,
publish_fix:crate::publish_fix::Publisher,
validator:crate::validator::Validator,
}
impl MessageHandler{
pub fn new(
cookie_context:rbx_asset::cookie::CookieContext,
api:api::Context,
maps_grpc:crate::MapsServiceClient,
)->Self{
Self{
publish_new:crate::publish_new::Publisher::new(cookie_context.clone(),api.clone(),maps_grpc),
publish_fix:crate::publish_fix::Publisher::new(cookie_context.clone(),api.clone()),
validator:crate::validator::Validator::new(cookie_context,api),
}
}
pub async fn handle_message_result(&self,message_result:MessageResult)->Result<(),HandleMessageError>{
let message=message_result.map_err(HandleMessageError::Messages)?;
message.double_ack().await.map_err(HandleMessageError::DoubleAck)?;
match message.subject.as_str(){
"maptest.submissions.publishnew"=>self.publish_new.publish(message).await.map_err(HandleMessageError::PublishNew),
"maptest.submissions.publishfix"=>self.publish_fix.publish(message).await.map_err(HandleMessageError::PublishFix),
"maptest.submissions.validate"=>self.validator.validate(message).await.map_err(HandleMessageError::Validation),
other=>Err(HandleMessageError::UnknownSubject(other.to_owned()))
}
}
}

View File

@ -2,36 +2,46 @@
// to perform the operation, not necessarily the over-the-wire format // to perform the operation, not necessarily the over-the-wire format
// Requests are sent from maps-service to validator // Requests are sent from maps-service to validator
// Validation invokes the REST api to update the submissions // Responses are sent from validator to maps-service
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct ValidateRequest{ pub struct ValidateRequest{
// submission_id is passed back in the response message // submission_id is passed back in the response message
pub SubmissionID:i64, pub submission_id:u64,
pub ModelID:u64, pub model_id:u64,
pub ModelVersion:u64, pub model_version:u64,
pub ValidatedModelID:Option<u64>, }
pub struct ValidateResponse{
pub submission_id:u64,
// model id will be changed if scripts were replaced
pub model_id:u64,
pub model_version:u64,
}
// an invalidate is sent instead if validation fails
pub struct InvalidateResponse{
pub submission_id:u64,
} }
// Create a new map // Create a new map
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct PublishNewRequest{ pub struct PublishNewRequest{
pub SubmissionID:i64, pub submission_id:u64,
pub ModelID:u64, pub model_id:u64,
pub ModelVersion:u64, pub model_version:u64,
pub Creator:String, pub creator:String,
pub DisplayName:String, pub display_name:String,
pub GameID:u32,
//games:HashSet<GameID>, //games:HashSet<GameID>,
} }
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct PublishFixRequest{ pub struct PublishFixRequest{
pub SubmissionID:i64, pub submission_id:u64,
pub ModelID:u64, pub model_id:u64,
pub ModelVersion:u64, pub model_version:u64,
pub TargetAssetID:u64, pub target_asset_id:u64,
}
pub struct PublishResponse{
pub submission_id:u64,
pub success:bool,
} }

View File

@ -1,62 +0,0 @@
use crate::nats_types::PublishFixRequest;
#[allow(dead_code)]
#[derive(Debug)]
pub enum PublishError{
Get(rbx_asset::cookie::GetError),
Json(serde_json::Error),
Upload(rbx_asset::cookie::UploadError),
ApiActionSubmissionPublish(api::Error),
}
impl std::fmt::Display for PublishError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for PublishError{}
pub struct Publisher{
roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context,
}
impl Publisher{
pub const fn new(
roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context,
)->Self{
Self{
roblox_cookie,
api,
}
}
pub async fn publish(&self,message:async_nats::jetstream::Message)->Result<(),PublishError>{
println!("publish_fix {:?}",message.message.payload);
// decode json
let publish_info:PublishFixRequest=serde_json::from_slice(&message.payload).map_err(PublishError::Json)?;
// download the map model version
let model_data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:publish_info.ModelID,
version:Some(publish_info.ModelVersion),
}).await.map_err(PublishError::Get)?;
// upload the map to the strafesnet group
let _upload_response=self.roblox_cookie.upload(rbx_asset::cookie::UploadRequest{
assetid:publish_info.TargetAssetID,
groupId:Some(crate::GROUP_STRAFESNET),
name:None,
description:None,
ispublic:None,
allowComments:None,
},model_data).await.map_err(PublishError::Upload)?;
// that's it, the database entry does not need to be changed.
// mark submission as published
self.api.action_submission_publish(
api::SubmissionID(publish_info.SubmissionID)
).await.map_err(PublishError::ApiActionSubmissionPublish)?;
Ok(())
}
}

View File

@ -1,83 +0,0 @@
use crate::nats_types::PublishNewRequest;
#[allow(dead_code)]
#[derive(Debug)]
pub enum PublishError{
Get(rbx_asset::cookie::GetError),
Json(serde_json::Error),
Create(rbx_asset::cookie::CreateError),
SystemTime(std::time::SystemTimeError),
MapCreate(tonic::Status),
ApiActionSubmissionPublish(api::Error),
}
impl std::fmt::Display for PublishError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for PublishError{}
pub struct Publisher{
roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context,
maps_grpc:crate::MapsServiceClient,
}
impl Publisher{
pub const fn new(
roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context,
maps_grpc:crate::MapsServiceClient,
)->Self{
Self{
roblox_cookie,
api,
maps_grpc,
}
}
pub async fn publish(&self,message:async_nats::jetstream::Message)->Result<(),PublishError>{
println!("publish_new {:?}",message.message.payload);
// decode json
let publish_info:PublishNewRequest=serde_json::from_slice(&message.payload).map_err(PublishError::Json)?;
// download the map model version
let model_data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:publish_info.ModelID,
version:Some(publish_info.ModelVersion),
}).await.map_err(PublishError::Get)?;
// upload the map to the strafesnet group
let upload_response=self.roblox_cookie.create(rbx_asset::cookie::CreateRequest{
name:publish_info.DisplayName.clone(),
description:"".to_owned(),
ispublic:false,
allowComments:false,
groupId:Some(crate::GROUP_STRAFESNET),
},model_data).await.map_err(PublishError::Create)?;
// create the map entry in the game database, including release date
self.maps_grpc.clone().create(rust_grpc::maps::MapRequest{
id:upload_response.AssetId as i64,
display_name:Some(publish_info.DisplayName),
creator:Some(publish_info.Creator),
game_id:Some(publish_info.GameID as i32),
// TODO: scheduling algorithm
date:Some(
// Publish one week from now
(
std::time::SystemTime::now()
+std::time::Duration::from_secs(7*24*60*60)
)
.duration_since(std::time::SystemTime::UNIX_EPOCH)
.map_err(PublishError::SystemTime)?
.as_secs() as i64
),
}).await.map_err(PublishError::MapCreate)?;
// mark submission as published
self.api.action_submission_publish(
api::SubmissionID(publish_info.SubmissionID)
).await.map_err(PublishError::ApiActionSubmissionPublish)?;
Ok(())
}
}

View File

@ -0,0 +1,40 @@
use futures::StreamExt;
#[derive(Debug)]
enum PublishError{
}
impl std::fmt::Display for PublishError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{self:?}")
}
}
impl std::error::Error for PublishError{}
pub struct Publisher{
nats:async_nats::Client,
subscriber:async_nats::Subscriber,
roblox_cookie:rbx_asset::cookie::CookieContext,
roblox_cloud:rbx_asset::cloud::CloudContext,
}
impl Publisher{
pub async fn new(
nats:async_nats::Client,
roblox_cookie:rbx_asset::cookie::CookieContext,
roblox_cloud:rbx_asset::cloud::CloudContext,
)->Result<Self,async_nats::SubscribeError>{
Ok(Self{
subscriber:nats.subscribe("publish").await?,
nats,
roblox_cookie,
roblox_cloud,
})
}
pub async fn run(mut self){
while let Some(message)=self.subscriber.next().await{
self.publish(message).await
}
}
async fn publish(&self,message:async_nats::Message){
println!("publish {:?}",message);
}
}

View File

@ -1,31 +1,22 @@
use futures::TryStreamExt; use futures::StreamExt;
use crate::nats_types::ValidateRequest; use crate::nats_types::ValidateRequest;
const SCRIPT_CONCURRENCY:usize=16; struct ModelVersion{
model_id:u64,
model_version:u64,
}
enum Policy{ enum Valid{
Allowed, Untouched,
Blocked, Modified(ModelVersion),
Delete,
Replace(String),
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum ValidateError{ enum ValidateError{
Blocked,
NotAllowed,
Get(rbx_asset::cookie::GetError), Get(rbx_asset::cookie::GetError),
Json(serde_json::Error), Json(serde_json::Error),
ReadDom(ReadDomError), ReadDom(ReadDomError),
ApiGetScriptPolicy(api::Error),
ApiGetScript(api::Error),
ApiUpdateSubmissionModel(api::Error),
ApiActionSubmissionValidate(api::Error),
WriteDom(rbx_binary::EncodeError),
Upload(rbx_asset::cookie::UploadError),
Create(rbx_asset::cookie::CreateError),
} }
impl std::fmt::Display for ValidateError{ impl std::fmt::Display for ValidateError{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@ -35,152 +26,63 @@ impl std::fmt::Display for ValidateError{
impl std::error::Error for ValidateError{} impl std::error::Error for ValidateError{}
pub struct Validator{ pub struct Validator{
nats:async_nats::Client,
subscriber:async_nats::Subscriber,
roblox_cookie:rbx_asset::cookie::CookieContext, roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context,
} }
impl Validator{ impl Validator{
pub const fn new( pub async fn new(
nats:async_nats::Client,
roblox_cookie:rbx_asset::cookie::CookieContext, roblox_cookie:rbx_asset::cookie::CookieContext,
api:api::Context, )->Result<Self,async_nats::SubscribeError>{
)->Self{ Ok(Self{
Self{ subscriber:nats.subscribe("validate").await?,
nats,
roblox_cookie, roblox_cookie,
api, })
}
pub async fn run(mut self){
while let Some(message)=self.subscriber.next().await{
self.validate_supress_error(message).await
} }
} }
pub async fn validate(&self,message:async_nats::jetstream::Message)->Result<(),ValidateError>{ async fn validate_supress_error(&self,message:async_nats::Message){
println!("validate {:?}",message.message.payload); match self.validate(message).await{
Ok(valid)=>{
unimplemented!();
// self.nats.publish("validated","yo it validated".into()).await.unwrap();
},
Err(e)=>{
println!("there was an error, oopsie! {e}");
}
}
}
async fn validate(&self,message:async_nats::Message)->Result<Valid,ValidateError>{
println!("validate {:?}",message);
// decode json // decode json
let validate_info:ValidateRequest=serde_json::from_slice(&message.payload).map_err(ValidateError::Json)?; let validate_info:ValidateRequest=serde_json::from_slice(&message.payload).map_err(ValidateError::Json)?;
// download map // download map
let data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{ let data=self.roblox_cookie.get_asset(rbx_asset::cookie::GetAssetRequest{
asset_id:validate_info.ModelID, asset_id:validate_info.model_id,
version:Some(validate_info.ModelVersion), version:Some(validate_info.model_version),
}).await.map_err(ValidateError::Get)?; }).await.map_err(ValidateError::Get)?;
// decode dom (slow!) // decode dom (slow!)
let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::ReadDom)?; let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::ReadDom)?;
/* VALIDATE MAP */ // validate map
// validate(dom)
// collect unique scripts // reply with validity
let script_refs=get_script_refs(&dom); Ok(Valid::Untouched)
let mut script_map=std::collections::HashMap::<String,Policy>::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"){
script_map.insert(source.clone(),Policy::Blocked);
}
}
}
// send all script hashes to REST endpoint and retrieve the replacements
futures::stream::iter(script_map.iter_mut().map(Ok))
.try_for_each_concurrent(Some(SCRIPT_CONCURRENCY),|(source,replacement)|async{
// get the hash
let mut hasher=siphasher::sip::SipHasher::new();
std::hash::Hasher::write(&mut hasher,source.as_bytes());
let hash=std::hash::Hasher::finish(&hasher);
// fetch the script policy
let script_policy=self.api.get_script_policy_from_hash(api::ScriptPolicyHashRequest{
hash:format!("{:x}",hash),
}).await.map_err(ValidateError::ApiGetScriptPolicy)?;
// write the policy to the script_map, fetching the replacement code if necessary
*replacement=match script_policy.Policy{
api::Policy::Allowed=>Policy::Allowed,
api::Policy::Blocked=>Policy::Blocked,
api::Policy::Delete=>Policy::Delete,
api::Policy::Replace=>{
let script=self.api.get_script(api::GetScriptRequest{
ScriptID:script_policy.ToScriptID,
}).await.map_err(ValidateError::ApiGetScript)?;
Policy::Replace(script.Source)
},
};
Ok(())
})
.await?;
// make the replacements
let mut modified=false;
for &script_ref in &script_refs{
if let Some(script)=dom.get_by_ref_mut(script_ref){
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut("Source"){
match script_map.get(source.as_str()){
Some(Policy::Blocked)=>return Err(ValidateError::Blocked),
None=>return Err(ValidateError::NotAllowed),
Some(Policy::Allowed)=>(),
Some(Policy::Delete)=>{
modified=true;
// delete script
dom.destroy(script_ref);
},
Some(Policy::Replace(replacement))=>{
modified=true;
*source=replacement.clone();
},
}
}
}
}
// if the model was validated, the submission must be changed to use the modified model
if modified{
// serialize model (slow!)
let mut data=Vec::new();
rbx_binary::to_writer(&mut data,&dom,dom.root().children()).map_err(ValidateError::WriteDom)?;
// upload a model lol
let model_id=if let Some(model_id)=validate_info.ValidatedModelID{
// upload to existing id
let response=self.roblox_cookie.upload(rbx_asset::cookie::UploadRequest{
assetid:model_id,
name:None,
description:None,
ispublic:None,
allowComments:None,
groupId:None,
},data).await.map_err(ValidateError::Upload)?;
response.AssetId
}else{
// create new model
let response=self.roblox_cookie.create(rbx_asset::cookie::CreateRequest{
name:dom.root().name.clone(),
description:"".to_owned(),
ispublic:true,
allowComments:true,
groupId:None,
},data).await.map_err(ValidateError::Create)?;
response.AssetId
};
// update the submission to use the validated model
self.api.update_submission_model(api::UpdateSubmissionModelRequest{
ID:validate_info.SubmissionID,
ModelID:model_id,
ModelVersion:1, //TODO
}).await.map_err(ValidateError::ApiUpdateSubmissionModel)?;
};
// update the submission model status to validated
self.api.action_submission_validate(
api::SubmissionID(validate_info.SubmissionID)
).await.map_err(ValidateError::ApiActionSubmissionValidate)?;
Ok(())
} }
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum ReadDomError{ enum ReadDomError{
Binary(rbx_binary::DecodeError), Binary(rbx_binary::DecodeError),
Xml(rbx_xml::DecodeError), Xml(rbx_xml::DecodeError),
Read(std::io::Error), Read(std::io::Error),
@ -209,33 +111,3 @@ fn read_dom<R:std::io::Read+std::io::Seek>(input:&mut R)->Result<rbx_dom_weak::W
_=>Err(ReadDomError::UnknownFormat(first_8)), _=>Err(ReadDomError::UnknownFormat(first_8)),
} }
} }
fn class_is_a(class:&str,superclass:&str)->bool{
if class==superclass{
return true
}
let class_descriptor=rbx_reflection_database::get().classes.get(class);
if let Some(descriptor)=&class_descriptor{
if let Some(class_super)=&descriptor.superclass{
return class_is_a(&class_super,superclass)
}
}
false
}
fn 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_script_refs(dom:&rbx_dom_weak::WeakDom)->Vec<rbx_dom_weak::types::Ref>{
let mut scripts=std::vec::Vec::new();
recursive_collect_superclass(&mut scripts,dom,dom.root(),"LuaSourceContainer");
scripts
}

View File

@ -1,3 +0,0 @@
node_modules
build
bun.lockb

40
web/.gitignore vendored
View File

@ -1,40 +0,0 @@
bun.lockb
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@ -1,13 +0,0 @@
FROM oven/bun:latest
WORKDIR /app
COPY . .
EXPOSE 3000
ENV NEXT_TELEMETRY_DISABLED=1
RUN bun install
RUN bun run build
ENTRYPOINT ["bun", "run", "start"]

View File

@ -1,16 +0,0 @@
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;

View File

@ -1,16 +0,0 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
distDir: "build",
output: "standalone",
rewrites: async () => {
return [
{
source: "/v1/submissions/:submissionid/status/:statustype",
destination: "http://mapsservice:8082/v1/submissions/:submissionid/status/:statustype"
}
]
}
};
export default nextConfig;

View File

@ -1,30 +0,0 @@
{
"name": "map-service-web",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000",
"build": "next build",
"start": "next start -p 3000",
"lint": "next lint"
},
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.1.10",
"@mui/material": "^6.1.10",
"next": "^15.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"sass": "^1.82.0"
},
"devDependencies": {
"typescript": "^5.7.2",
"@types/node": "^20.17.9",
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.2",
"eslint": "^9.16.0",
"eslint-config-next": "15.1.0",
"@eslint/eslintrc": "^3.2.0"
}
}

View File

@ -1,31 +0,0 @@
import Link from "next/link"
import "./styles/header.scss"
interface HeaderButton {
name: string,
href: string
}
function HeaderButton(header: HeaderButton) {
return (
<Link href={header.href}>
<button>{header.name}</button>
</Link>
)
}
export default function Header() {
return (
<header className="header-bar">
<nav className="left">
<HeaderButton name="Maps" href=""/>
</nav>
<nav className="right">
<HeaderButton name="Home" href=""/>
<HeaderButton name="Need" href=""/>
<HeaderButton name="Menu" href=""/>
<HeaderButton name="Items" href=""/>
</nav>
</header>
)
}

View File

@ -1,38 +0,0 @@
.header-bar {
display: flex;
justify-content: space-between;
align-items: center;
width: 100vw;
height: 60px;
background: var(--header-grad-left);
background: linear-gradient(180deg, var(--header-grad-left) 0%, var(--header-grad-right) 100%);
button {
background-color: transparent;
border: 0;
color: var(--header-button-left);
}
.left {
margin-left: 15px;
button {
font-size: 1.2rem;
}
}
.right {
display: flex;
gap: 7px;
margin-right: 50px;
button {
font-size: 1rem;
color: var(--header-button-right);
&:hover {
color: var(--header-button-hover)
}
}
}
}

View File

@ -1,8 +0,0 @@
import Header from "./header";
export default function Webpage({children}: Readonly<{children?: React.ReactNode}>) {
return (<>
<Header/>
{children}
</>)
}

View File

@ -1,54 +0,0 @@
$review-border: 1px solid var(--review-border);
@mixin border-with-radius {
border: $review-border {
radius: 5px;
}
}
:root {
color-scheme: light dark;
--page: white;
--header-grad-left: #363b40;
--header-grad-right: #353a40;
--header-button-left: white;
--header-button-right: #b4b4b4;
--header-button-hover: white;
--review-border: #c8c8c8;
--text-color: #1e1e1e;
--anchor-link-review: #008fd6;
--window-header: #f5f5f5;
--comment-highlighted: #ffffd7;
--comment-area: white;
@media (prefers-color-scheme: dark) {
--page: rgb(15,15,15);
--header-grad-left: #363b40;
--header-grad-right: #353a40;
--header-button-left: white;
--header-button-right: #b4b4b4;
--header-button-hover: white;
--review-border: rgb(50,50,50);
--text-color: rgb(230,230,230);
--anchor-link-review: #008fd6;
--window-header: rgb(10,10,10);
--comment-highlighted: #ffffd7;
--comment-area: rgb(20,20,20);
}
}
body {
font-family: -apple-system, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", "Twemoji Mozilla";
box-sizing: border-box;
margin: 0;
background-color: var(--page);
}
button {
cursor: pointer;
}
a:active, a:link, a:hover {
text-decoration: none;
}

View File

@ -1,9 +0,0 @@
import "./globals.scss";
export default function RootLayout({children}: Readonly<{children: React.ReactNode}>) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@ -1,7 +0,0 @@
import Webpage from "./_components/webpage";
export default function Home() {
return (
<Webpage></Webpage>
);
}

View File

@ -1,26 +0,0 @@
@forward "./page/commentWindow.scss";
@forward "./page/reviewStatus.scss";
@forward "./page/ratingWindow.scss";
@forward "./page/reviewButtons.scss";
@forward "./page/comments.scss";
@forward "./page/review.scss";
@forward "./page/map.scss";
@use "../../../globals.scss";
.map-page-main {
display: flex;
justify-content: center;
width: 100vw;
}
.spacer {
display: block;
width: 100%;
height: 1px;
background-color: var(--review-border);
}
.by-creator {
margin-top: 10px;
}

View File

@ -1,56 +0,0 @@
@use "../../../../globals.scss";
#comment-text-field {
@include globals.border-with-radius;
resize: none;
width: 100%;
height: 100px;
background-color: var(--comment-area)
}
.leave-comment-window {
@include globals.border-with-radius;
width: 100%;
height: 230px;
margin-top: 35px;
.rating-type {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
gap: 35%;
.rating-right {
display: grid;
> span {
margin: 6px 0 6px 0;
}
}
p {
margin: 15px 0 15px 0;
}
}
header {
display: flex;
align-items: center;
background-color: var(--window-header);
border-bottom: globals.$review-border;
height: 45px;
p {
font-weight: bold;
margin: 0 0 0 20px;
}
}
main {
padding: 20px;
button {
margin-top: 9px;
}
}
}

View File

@ -1,49 +0,0 @@
$comments-size: 60px;
.comments {
display: grid;
gap: 25px;
margin-top: 20px;
.no-comments {
text-align: center;
margin: 0;
}
.commenter {
display: flex;
height: $comments-size;
//BhopMaptest comment
&[data-highlighted="true"] {
background-color: var(--comment-highlighted);
}
> img {
border-radius: 50%;
}
.name {
font: {
weight: 500;
size: 1.3em;
};
}
.date {
font-size: .8em;
margin: 0 0 0 5px;
color: #646464
}
.details {
display: grid;
margin-left: 10px;
header {
display: flex;
align-items: center;
}
p:not(.date) {
margin: 0;
}
}
}
}

View File

@ -1,15 +0,0 @@
@use "../../../../globals.scss";
.map-image-area {
@include globals.border-with-radius;
display: flex;
justify-content: center;
align-items: center;
width: 350px;
height: 350px;
> p {
text-align: center;
margin: 0;
}
}

View File

@ -1,43 +0,0 @@
@use "../../../../globals.scss";
.rating-window {
@include globals.border-with-radius;
width: 100%;
.rating-type {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
gap: 35%;
.rating-right {
display: grid;
> span {
margin: 6px 0 6px 0;
}
}
p {
margin: 15px 0 15px 0;
}
}
header {
display: flex;
align-items: center;
background-color: var(--window-header);
border-bottom: globals.$review-border;
height: 45px;
p {
font-weight: bold;
margin: 0 0 0 20px;
}
}
main {
display: grid;
place-items: center;
}
}

View File

@ -1,47 +0,0 @@
@use "../../../../globals.scss";
.review-info {
width: 650px;
height: 100%;
> div {
display: flex;
justify-content: space-between;
align-items: center;
}
p, h1 {
color: var(--text-color);
}
h1 {
font: {
weight: 500;
size: 1.8rem
};
margin: 0;
}
a {
color: var(--anchor-link-review);
&:hover {
text-decoration: underline;
}
}
}
.review-section {
display: flex;
gap: 50px;
margin-top: 20px;
}
.review-area {
display: grid;
justify-content: center;
gap: 25px;
img {
width: 100%;
height: 350px;
object-fit: contain
}
}

View File

@ -1,13 +0,0 @@
@use "../../../../globals.scss";
.review-set {
@include globals.border-with-radius;
display: grid;
align-items: center;
gap: 10px;
padding: 10px;
button {
width: 100%;
}
}

View File

@ -1,73 +0,0 @@
$Published: "0";
$Rejected: "1";
$Publishing: "2";
$Validated: "3";
$Validating: "4";
$Accepted: "5";
$ChangesRequested: "6";
$Submitted: "7";
$UnderConstruction: "8";
.review-status {
border-radius: 5px;
p {
margin: 3px 25px 3px 25px;
font-weight: bold;
}
&[data-review-status="#{$Published}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Rejected}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Publishing}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Validated}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Validating}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Accepted}"] {
background-color: rgb(2, 162, 2);
p {
color: white;
}
}
&[data-review-status="#{$ChangesRequested}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$Submitted}"] {
background-color: orange;
p {
color: white;
}
}
&[data-review-status="#{$UnderConstruction}"] {
background-color: orange;
p {
color: white;
}
}
}

View File

@ -1,66 +0,0 @@
import type { SubmissionInfo } from "@/app/ts/Submission";
import { Button } from "@mui/material"
import Window from "./_window";
import SendIcon from '@mui/icons-material/Send';
import Image from "next/image";
interface CommentersProps {
comments_data: CreatorAndReviewStatus
}
interface CreatorAndReviewStatus {
creator: SubmissionInfo["DisplayName"],
review: SubmissionInfo["StatusID"],
comments: Comment[],
name: string
}
interface Comment {
picture?: string, //TEMP
comment: string,
date: string,
name: string
}
function AddComment(comment: Comment) {
const IsBhopMaptest = comment.name == "BhopMaptest" //Highlighted commenter
return (
<div className="commenter" data-highlighted={IsBhopMaptest}>
<Image src={comment.picture as string} alt={`${comment.name}'s comment`}/>
<div className="details">
<header>
<p className="name">{comment.name}</p>
<p className="date">{comment.date}</p>
</header>
<p className="comment">{comment.comment}</p>
</div>
</div>
);
}
function LeaveAComment() {
return (
<Window title="Leave a Comment:" className="leave-comment-window">
<textarea name="comment-box" id="comment-text-field"></textarea>
<Button variant="outlined" endIcon={<SendIcon/>}>Submit</Button>
</Window>
)
}
export default function Comments(stats: CommentersProps) {
return (<>
<section className="comments">
{stats.comments_data.comments.length===0
&& <p className="no-comments">There are no comments.</p>
|| stats.comments_data.comments.map(comment => (
<AddComment key={comment.name} name={comment.name} date={comment.date} comment={comment.comment}/>
))}
</section>
<LeaveAComment/>
</>)
}
export {
type CreatorAndReviewStatus
}

View File

@ -1,27 +0,0 @@
"use client"
import { useState, useEffect } from "react"
import { SubmissionInfo } from "@/app/ts/Submission"
import { AssetImage } from "@/app/ts/Roblox"
import Image from "next/image"
interface AssetID {
id: SubmissionInfo["AssetID"]
}
function MapImage(asset: AssetID) {
const [assetImage, setAssetImage] = useState("");
useEffect(() => {
AssetImage(asset.id, "420x420").then(image => setAssetImage(image))
}, [asset.id]);
if (!assetImage) {
return <p>Fetching map image...</p>;
}
return <Image src={assetImage} alt="Map Image"/>
}
export {
type AssetID,
MapImage
}

View File

@ -1,35 +0,0 @@
import { Button, ButtonOwnProps } from "@mui/material";
type Review = "Completed" | "Submit" | "Reject" | "Revoke" | "Accept" | "Publish"
type Action = "completed" | "submit" | "reject" | "revoke" | "trigger-validate" | "trigger-publish"
interface ReviewButton {
name: Review,
action: Action,
color: ButtonOwnProps["color"]
}
function ReviewButtonClicked(action: Action) {
const post = fetch(`http://localhost:3000/v1/submissions/1/status/${action}`, {
method: "POST",
headers: {
"Content-type": "application/json",
}
})
}
function ReviewButton(props: ReviewButton) {
return <Button color={props.color} variant="contained" onClick={() => { ReviewButtonClicked(props.action) }}>{props.name}</Button>
}
export default function ReviewButtons() {
return (
<section className="review-set">
<ReviewButton color="info" name="Submit" action="submit"/>
<ReviewButton color="info" name="Revoke" action="revoke"/>
<ReviewButton color="info" name="Accept" action="trigger-validate"/>
<ReviewButton color="error" name="Reject" action="reject"/>
<ReviewButton color="info" name="Publish" action="trigger-publish"/>
<ReviewButton color="info" name="Completed" action="completed"/>
</section>
)
}

View File

@ -1,20 +0,0 @@
interface WindowStruct {
className: string,
title: string,
children: React.ReactNode
}
export default function Window(window: WindowStruct) {
return (
<section className={window.className}>
<header>
<p>{window.title}</p>
</header>
<main>{window.children}</main>
</section>
)
}
export {
type WindowStruct
}

View File

@ -1,80 +0,0 @@
"use client"
import { SubmissionStatus, SubmissionStatusToString } from "@/app/ts/Submission";
import type { CreatorAndReviewStatus } from "./_comments";
import { MapImage, type AssetID } from "./_map";
import { useParams } from "next/navigation";
import ReviewButtons from "./_reviewButtons";
import { Rating } from "@mui/material";
import Comments from "./_comments";
import Webpage from "@/app/_components/webpage";
import Window from "./_window";
import Link from "next/link";
import "./(styles)/page.scss";
function Ratings() {
return (
<Window className="rating-window" title="Rating">
<section className="rating-type">
<aside className="rating-left">
<p>Quality</p>
<p>Difficulty</p>
<p>Fun</p>
<p>Length</p>
</aside>
<aside className="rating-right">
<Rating defaultValue={2.5} precision={0.5}/>
<Rating defaultValue={2.5} precision={0.5}/>
<Rating defaultValue={2.5} precision={0.5}/>
<Rating defaultValue={2.5} precision={0.5}/>
</aside>
</section>
</Window>
)
}
function RatingArea(asset: AssetID) {
return (
<aside className="review-area">
<section className="map-image-area">
<MapImage id={asset.id}/>
</section>
<Ratings/>
<ReviewButtons/>
</aside>
)
}
function TitleAndComments(stats: CreatorAndReviewStatus) {
const Review = SubmissionStatusToString(stats.review)
return (
<main className="review-info">
<div>
<h1>{stats.name}</h1>
<aside data-review-status={stats.review} className="review-status">
<p>{Review}</p>
</aside>
</div>
<p className="by-creator">by <Link href="" target="_blank">{stats.creator}</Link></p>
<span className="spacer"></span>
<Comments comments_data={stats}/>
</main>
)
}
export default function SubmissionInfoPage() {
const dynamicId = useParams<{submissionId: string}>()
return (
<Webpage>
<main className="map-page-main">
<section className="review-section">
<RatingArea id={432}/>
<TitleAndComments name={dynamicId.submissionId} creator="Quaternions" review={SubmissionStatus.Accepted} comments={[]}/>
</section>
</main>
</Webpage>
)
}

View File

@ -1,48 +0,0 @@
const FALLBACK_IMAGE = ""
type thumbsizes = "420" | "720"
type thumbsize<S extends thumbsizes> = `${S}x${S}`
type ParsedJson<A> = {
errors: A,
data: {
[0]: {
state: string,
imageUrl: string,
}
}
}
function Parse<A>(json: ParsedJson<A>): string {
if (json.errors) {
console.warn(json.errors)
return FALLBACK_IMAGE
}
if (json.data) {
const data = json.data[0]
if (!data) { //For whatever reason roblox will sometimes return an empty array instead of an error message
console.warn("Roblox gave us no data,", data)
return FALLBACK_IMAGE
}
if (data.state === "Completed") {
return data.imageUrl
}
console.warn(data)
return FALLBACK_IMAGE
}
return FALLBACK_IMAGE
}
async function AvatarHeadshot<S extends thumbsizes>(userid: number, size: thumbsize<S>): Promise<string> {
const avatarthumb_api = fetch(`https://thumbnails.roproxy.com/v1/users/avatar-headshot?userIds=${userid}&size=${size}&format=Png&isCircular=false`)
return avatarthumb_api.then(res => res.json()).then(json => Parse(json))
}
async function AssetImage<S extends thumbsizes>(assetid: number, size: thumbsize<S>): Promise<string> {
const avatarthumb_api = fetch(`https://thumbnails.roblox.com/v1/assets?assetIds=${assetid}&returnPolicy=PlaceHolder&size=${size}&format=Png&isCircular=false`)
return avatarthumb_api.then(res => res.json()).then(json => Parse(json))
}
export {
AvatarHeadshot,
AssetImage
}

View File

@ -1,56 +0,0 @@
const enum SubmissionStatus {
Published,
Rejected,
Publishing,
Validated,
Validating,
Accepted,
ChangesRequested,
Submitted,
UnderConstruction
}
interface SubmissionInfo {
readonly ID: number,
readonly DisplayName: string,
readonly Creator: string,
readonly GameID: number,
readonly Date: number,
readonly Submitter: number,
readonly AssetID: number,
readonly AssetVersion: number,
readonly Completed: boolean,
readonly TargetAssetID: number,
readonly StatusID: SubmissionStatus
}
function SubmissionStatusToString(submission_status: SubmissionStatus): string {
switch (submission_status) {
case SubmissionStatus.Published:
return "PUBLISHED"
case SubmissionStatus.Rejected:
return "REJECTED"
case SubmissionStatus.Publishing:
return "PUBLISHING"
case SubmissionStatus.Validated:
return "VALIDATED"
case SubmissionStatus.Validating:
return "VALIDATING"
case SubmissionStatus.Accepted:
return "ACCEPTED"
case SubmissionStatus.ChangesRequested:
return "CHANGES REQUESTED"
case SubmissionStatus.Submitted:
return "SUBMITTED"
case SubmissionStatus.UnderConstruction:
return "UNDER CONSTRUCTION"
default:
return "UNKNOWN"
}
}
export {
SubmissionStatus,
SubmissionStatusToString,
type SubmissionInfo
}

View File

@ -1,42 +0,0 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"noImplicitAny": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": [
"./src/*"
]
}
},
"include": [
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
"next-env.d.ts",
"build/types/**/*.ts"
],
"exclude": [
"node_modules"
]
}