238 Commits

Author SHA1 Message Date
b31b3bed5f Merge pull request 'Deploy workflow timeline' (#302) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #302
2025-12-27 08:28:42 +00:00
7eaa84a0ed Change Timeline Text (#301)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Some tweaks to the descriptions.  Evidently I didn't read carefully enough.

Reviewed-on: #301
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-12-27 08:19:17 +00:00
cf0cf9da7a Add workflow timeline (#300)
All checks were successful
continuous-integration/drone/push Build is passing
Closes !232

<img width="763" alt="image.png" src="attachments/559715f5-630e-4029-a19b-c9f4cf4c7270">

Reviewed-on: #300
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-27 08:04:02 +00:00
34cd1c7c26 Merge pull request 'Deploy dashboard update' (#299) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #299
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
2025-12-27 05:41:53 +00:00
74565e567a Fix "0" displaying in "Review Dashboard" button on user dashboard (#298)
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
The review dashboard link only shows when the user has the correct roles. A normal user would not see the button but instead the text "0".

Reviewed-on: #298
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-27 05:39:33 +00:00
ea65794255 Cycle before and after images every 1.5 seconds (#295)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
The images should auto cycle now that the thumbnails are working.

I don't know how to test this!  This is what I tried:
```
bun install
bun run build
VITE_API_HOST=https://maps.staging.strafes.net/v1 bun run preview
```
but the mapfixes page won't load the mapfixes.

Reviewed-on: #295
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-12-27 05:26:04 +00:00
58706a5687 Add user/reviewer dashboard (#297)
All checks were successful
continuous-integration/drone/push Build is passing
Adds "at a glance" dashboard so life is less painful.

![image.png](/attachments/43e83777-7196-4274-9adc-e1268e43bc0f)
![image.png](/attachments/1cbe99ab-50b8-443a-aa48-ad9107ccfb1e)

Reviewed-on: #297
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-27 05:20:45 +00:00
efeb525e19 Merge pull request 'Add mapfix history on maps page' (#294) from feature/mapfix-list into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #294
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
2025-12-27 04:51:03 +00:00
5a1fe60a7b fix quat docker
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-26 19:13:03 -08:00
01cfe67848 Just exclude rejected and released for active list
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-12-26 20:38:18 -05:00
a19bc4d380 Add mapfix history on maps page
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-26 20:32:55 -05:00
ae006565d6 Merge pull request 'Fix overflow on mapfix/submission' (#293) from fix/overflow into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #293
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
2025-12-27 00:44:26 +00:00
57bca99109 Fix overflow
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-12-26 19:42:36 -05:00
058455efd2 Merge pull request 'Deploy updates' (#291) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #291
2025-12-26 04:46:53 +00:00
cd09c9b18e Populate username for map fixes by author id
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is passing
2025-12-25 20:42:22 -08:00
e48cbaff72 Make maps behave like normal link 2025-12-25 20:42:22 -08:00
140d58b808 Make comments support newlines 2025-12-25 20:42:22 -08:00
ba761549b8 Force dark theme 2025-12-25 20:42:22 -08:00
86643fef8d Merge branch 'master' into staging 2025-12-25 20:42:18 -08:00
96af864c5e Deploy staging to prod (#286)
All checks were successful
continuous-integration/drone/push Build is passing
Pull in validator changes and full ui rework to remove nextjs.

Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Reviewed-on: #286
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-26 03:30:36 +00:00
7db89fd99b Fix bun lock file
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-12-25 22:10:29 -05:00
f2bb1b078d Fix content width and standardize on skeleton loading
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-12-25 21:37:23 -05:00
66878fba4e Switch loading text to skeleton
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 21:02:15 -05:00
bda99550be Fix submission icon 2025-12-25 21:00:28 -05:00
8a216c7e82 Add username api
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 20:55:15 -05:00
e5277c05a1 Avatar image loading
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 20:38:17 -05:00
e4af76cfd4 Fix api endpoint
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 20:22:24 -05:00
30db1cc375 Fix the build issues
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 19:52:01 -05:00
b50c84f8cf Use port 3000
Some checks failed
continuous-integration/drone/push Build is failing
2025-12-25 19:49:52 -05:00
7589ef7df6 Fix dockerfile for spa
Some checks failed
continuous-integration/drone/push Build was killed
2025-12-25 19:49:06 -05:00
8ab8c441b0 Home page and header fixes
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-25 19:45:16 -05:00
a26b228ebe Add 404 page 2025-12-25 19:45:16 -05:00
3654755540 Thumbnail/nav cleanup 2025-12-25 19:45:16 -05:00
c2b50ffab2 Cleanup home/nav 2025-12-25 19:45:16 -05:00
75756917b1 some theming 2025-12-25 19:45:16 -05:00
8989c08857 theme 2025-12-25 19:45:16 -05:00
b2232f4177 Initial work to nuke nextjs 2025-12-25 19:45:16 -05:00
7d1c4d2b6c Add stats endpoint
Some checks failed
continuous-integration/drone Build was killed
continuous-integration/drone/push Build is passing
2025-12-25 18:58:52 -05:00
ca401d4b96 Add batch thumbnail endpoint (#285)
All checks were successful
continuous-integration/drone/push Build is passing
Step 1 of eliminating nextjs is adding a way to query thumbnails from roblox since nextjs handles that. This implements a batch endpoint and caching to do that. Bonus: thumbnails will actually work once we start using this.

Reviewed-on: #285
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-25 22:56:59 +00:00
9ab80931bf remove unfulfilled lints
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-09 14:34:39 -08:00
09022e7292 change allow to expect 2025-12-09 14:34:16 -08:00
3400056c23 submissions-api: v0.10.1 audit events
All checks were successful
continuous-integration/drone/push Build is passing
2025-12-08 18:10:32 -08:00
57501d446f submissions-api: add audit events 2025-12-08 18:09:54 -08:00
47c0fff0ec Merge pull request 'Update javascript' (#283) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #283
2025-12-06 04:48:21 +00:00
e6ef4e33ac mui
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-12-05 20:44:16 -08:00
aeba355d6c format
Some checks failed
continuous-integration/drone/push Build is failing
2025-12-05 20:27:02 -08:00
8ad94bcdc8 bug 2025-12-05 20:27:02 -08:00
66f02a2f45 docker: update bun
Some checks failed
continuous-integration/drone/push Build is failing
2025-12-05 20:16:51 -08:00
c6a685310e bun update
Some checks failed
continuous-integration/drone/push Build is failing
2025-12-05 20:14:19 -08:00
72b95ae271 drone: update bun 2025-12-05 20:13:51 -08:00
7c04cc5c23 drone: update rust
All checks were successful
continuous-integration/drone/push Build is passing
2025-11-27 16:36:25 -08:00
a3bf111b4e update deps
Some checks failed
continuous-integration/drone/push Build is failing
2025-11-27 15:56:03 -08:00
d82f44e9d2 remove unused type
All checks were successful
continuous-integration/drone/push Build is passing
2025-11-09 09:30:03 -08:00
4c5a8c39c1 update deps
All checks were successful
continuous-integration/drone/push Build is passing
2025-11-09 06:00:03 -08:00
4e55b1d665 drop lazy_regex dep 2025-11-09 05:56:58 -08:00
63d7bec3a3 validation: fix variable names
All checks were successful
continuous-integration/drone/push Build is passing
2025-11-07 10:00:16 -08:00
b7c28616ad Merge pull request 'submissions: Fix Maps.Update Date + Release Date Mixup' (#282) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #282
2025-09-29 02:14:51 +00:00
ce9b26378c submissions: Fix Maps.Update Date
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-09-28 19:09:59 -07:00
df8f6463da bruh
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-23 17:26:03 -07:00
6ccc56cc55 submissions: fix release date mixup
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-23 16:31:50 -07:00
89ab25dfb9 Merge pull request 'deploy fixes' (#279) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #279
2025-09-23 22:41:35 +00:00
ffa1308e73 update deps
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-09-23 15:33:11 -07:00
b5a367e159 Return OperationID from release-submissions (#278)
The release-submissions endpoint creates an operation, but does not return it.

Reviewed-on: #278
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-09-23 15:31:34 -07:00
6b05836a56 openapi: increase max script path length
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-23 15:12:20 -07:00
8abee39d15 web: do not show Admin Submit button on mapfixes
All checks were successful
continuous-integration/drone/push Build is passing
2025-09-17 14:24:25 -07:00
b0b5ff0725 Merge pull request 'web: add missing button lost in refactor' (#275) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #275
2025-09-17 00:12:15 +00:00
456b62104b web: add missing button lost in refactor
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
This was lost in 8f2a0b53e4
2025-09-16 16:56:31 -07:00
574a05424d update readme
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-18 15:54:46 -07:00
0532965d37 Merge pull request 'Maps Metadata Maintenance' (#267) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #267
2025-08-16 06:24:19 +00:00
51ba05df69 backend: remove mapfixes migrate endpoint
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-08-15 23:20:08 -07:00
30b594b345 backend: fix completely wrong gorm thing
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 23:05:40 -07:00
ab361dffd1 backend: fix completely wrong gorm thing
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 23:01:37 -07:00
d30a94e42d backend: add mission interface method
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 22:34:22 -07:00
dae378a188 backend: update go-grpc 2025-08-15 22:31:26 -07:00
cd912d683e validation: remove table from luau execution script
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 22:23:29 -07:00
f5dfd5a163 Revert "validation: spend way to much time saving 1 microsecond"
This reverts commit 18d51af7ca.
2025-08-15 22:19:17 -07:00
18d51af7ca validation: spend way to much time saving 1 microsecond
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 22:17:54 -07:00
a45aa700d8 make: frontend image builds from scratch
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 20:13:01 -07:00
907b6d2034 web: fix Releasing statusChip 2025-08-15 20:08:02 -07:00
a454ea01b6 web: fix unknown status
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-15 19:59:17 -07:00
7f8c9210a5 docker: move auth so non-editor-searchable location 2025-08-15 19:57:47 -07:00
f76f8cd136 Merge pull request 'Mapfix Release' (#264) from mapfix-release into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #264
2025-08-16 02:47:28 +00:00
55b79b8f9b backend: typo
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-08-15 19:40:24 -07:00
1ce09e3f9b docker: add env vars to compose.yml
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 19:35:39 -07:00
2878467cbf backend: add forgotten permission 2025-08-15 19:35:28 -07:00
2639abc7c8 submissions-api-rs: v0.9.1 fixes
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 19:02:00 -07:00
231c11632b openapi: add missing fields 2025-08-15 19:01:20 -07:00
877f5c024f submissions-api-rs: fix MapfixResponse 2025-08-15 19:01:20 -07:00
18ca6de7d3 submissions-api-rs: v0.9.0 get_mapfixes
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 18:41:04 -07:00
6ee8816eed submissions-api-rs: add get_mapfixes endpoint
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 18:39:43 -07:00
de6163093f backend: add missing list query 2025-08-15 18:39:43 -07:00
d7456d500b backend: create mapfixes migration code UPLOADED -> RELEASED
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-15 17:48:45 -07:00
1a558f35cf openapi: generate 2025-08-15 17:14:05 -07:00
b5b07ec1ce openapi: create migration endpoint 2025-08-15 17:13:59 -07:00
efd60f45df validator: respond correctly to upload failure
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-14 19:48:08 -07:00
10507c62ab openapi: generate 2025-08-14 19:48:07 -07:00
0d18167b03 remove SubmissionStatusReleasing 2025-08-14 19:48:07 -07:00
e90cc425ba validator: perform unnecessary allocation to appease borrow checker 2025-08-14 19:48:07 -07:00
76512bec0d validator: update deps 2025-08-14 19:48:07 -07:00
412dadfc3e validator: add mapfix and submission release 2025-08-14 19:48:07 -07:00
31cca0d450 validator: update rust-grpc 2025-08-14 19:48:07 -07:00
cfb7461c5a validator: remove implicit map update 2025-08-14 19:48:07 -07:00
0cb419430a backend: make release pipeline internals 2025-08-14 19:48:07 -07:00
807d394646 web: add release buttons 2025-08-12 17:46:42 -07:00
3c9d04d637 openapi: generate 2025-08-12 16:18:15 -07:00
94ad0ff774 openapi: add new status endpoints 2025-08-12 16:18:01 -07:00
25f6c9e086 backend: tweak status sets to reflect new statuses
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-12 16:05:33 -07:00
a62a231b0a backend: new statuses for mapfix and submission 2025-08-12 16:05:13 -07:00
468204b299 validator: dedicated api key for luau execution
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-12 15:48:59 -07:00
63458aee09 Merge pull request 'Update Metadata on Mapfix' (#263) from metadata-maintenance into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #263
2025-08-12 21:56:07 +00:00
8297ed165b readme: document env vars
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-11 17:50:39 -07:00
c98c3fe47e validator: update modes on mapfix
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-08-11 17:40:14 -07:00
9c1e1e4347 validator: move count_sequential fn 2025-08-11 17:40:02 -07:00
d37a8b9030 validator: call Luau Execution API to get LoadAssetVersion
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-11 17:02:44 -07:00
75682a2375 validator: connect to maps_extended 2025-08-11 17:02:28 -07:00
8f6012c7ef validator: remove MessageHandler constructor (too many arguments) 2025-08-11 16:33:37 -07:00
f59979987f Merge pull request 'Deploy Public API' (#256) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #256
2025-08-08 22:07:37 +00:00
295b1d842b Sequential Modes Check (#260)
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
Closes #242

Reviewed-on: #260
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-08-07 19:48:16 -07:00
93147060d6 drone: re-sign pipeline after self-inflicted catastrophe
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2025-08-07 19:22:12 -07:00
fe539bf190 move rust submissions api 2025-08-07 17:37:15 -07:00
759ac08aef swagger: generate 2025-08-07 16:13:42 -07:00
34bc623ce6 make UserInfoHandle.HasRoles public 2025-08-07 16:08:47 -07:00
9999d1ff87 fix docs redirect
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2025-08-06 20:15:53 -07:00
8a0cd50b68 fix public api
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2025-08-06 20:04:33 -07:00
08753d36b4 Cut Down Maps Fields (#257)
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
Remove usages of Creator & Date, add Thumbnail.

Reviewed-on: #257
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-08-07 02:32:22 +00:00
5dce0f2017 docker: do not run build-frontend on push
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2025-08-05 23:08:21 -07:00
d196da949c Public API (#253)
Closes #229

This is a MVP and only includes maps.

Reviewed-on: #253
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-08-05 23:08:18 -07:00
b0c723be1b docker: fix validator context 2025-08-05 22:58:41 -07:00
48314f5d18 Refactor Docker (#254)
Some checks failed
continuous-integration/drone/push Build is failing
Refactor docker to use makefile build commands

Reviewed-on: #254
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-08-06 05:49:30 +00:00
1e4e513dc1 web: update deps
All checks were successful
continuous-integration/drone/push Build is passing
2025-08-05 22:16:31 -07:00
f9455e7317 validator: update deps
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-08-05 21:30:44 -07:00
69ebef5fb8 validator: use rustls 2025-08-05 21:30:44 -07:00
a9258136da Merge pull request 'Remove Migration Code' (#251) from rm-migrate into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #251
2025-07-28 12:04:50 +00:00
ac05f4acdc submissions: remove migration operation
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-25 23:09:03 -07:00
061b7b2a01 openapi: generate 2025-07-25 23:08:07 -07:00
b4a0041fb5 openapi: remove migration operation 2025-07-25 23:07:50 -07:00
a232269d54 Merge pull request 'Extend Web API Maps With New Fields' (#250) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #250
2025-07-26 03:29:09 +00:00
692c915af8 Merge pull request 'Extend Maps With New Fields' (#249) from webapi-maps into staging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #249
2025-07-26 02:31:24 +00:00
d35c331b76 submissions: fill out new fields
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-25 19:19:39 -07:00
9ce8b75f0f openapi: generate
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-25 19:16:21 -07:00
f5d41ab672 openapi: extend Map with new fields 2025-07-25 19:15:12 -07:00
a7c4ca4b49 Merge pull request 'Implement Maps' (#248) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #248
2025-07-26 01:26:26 +00:00
2578a74ddb submissions: use unsigned ints in maps struct
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-23 23:18:54 -07:00
45a58145ed Merge pull request 'Fix Null Pointer Deref' (#246) from maps into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #246
2025-07-24 05:21:14 +00:00
a4cefd263d submissions: maps: guard against null pointers
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-23 22:19:42 -07:00
1b18649cb6 Merge pull request 'Implement Maps' (#241) from maps into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #241
2025-07-24 04:29:01 +00:00
bdfd1a0b23 submissions: temporary migration endpoint
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-23 20:04:39 -07:00
859004f264 openapi: generate 2025-07-23 20:04:39 -07:00
89ef254b72 openapi: maps migration endpoint 2025-07-23 20:04:39 -07:00
36f9e2db5f submissions: grpc controller 2025-07-23 20:04:39 -07:00
ce4e37dc64 submissions: update go-grpc for maps_extended 2025-07-23 20:04:32 -07:00
f417111bcf submissions: switch maps to maps-service 2025-07-23 20:04:32 -07:00
1826a51ebd submissions: maps db 2025-07-23 20:03:55 -07:00
ca9f82a5aa Merge pull request 'Set Download File Name' (#245) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #245
2025-07-23 09:32:27 +00:00
76903656c2 Merge pull request 'Change to Proxy Download' (#208) from pr1 into staging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #208
2025-07-23 09:17:21 +00:00
3e353b2ec6 web: change to proxy download
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-23 02:10:37 -07:00
749ea7e57d submissions: change to proxy download 2025-07-23 02:10:37 -07:00
03ec0b0183 openapi: generate 2025-07-23 01:55:21 -07:00
cc93776c25 openapi: change to proxy download 2025-07-23 01:55:21 -07:00
a8ad9f7de0 ai thinking Rust while doing golang lol 2025-07-23 01:55:21 -07:00
d5d794703b submissions: missing inner service AuditEvent functions
All checks were successful
continuous-integration/drone/push Build is passing
currently unused
2025-07-23 01:54:04 -07:00
e1a2f6f075 Merge pull request 'Fix gRPC' (#244) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #244
2025-07-23 04:53:29 +00:00
70bbba6003 submissions: fix gRPC (the code is completely wrong)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
I blame the programming language, wouldn't have happened in Rust
2025-07-22 21:42:14 -07:00
39ba12edd9 web: add missing ResetSubmitting review button
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-22 21:30:33 -07:00
1cfdb3668a validator: connect_lazy
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-22 21:01:39 -07:00
dad904cd86 Merge pull request 'Convert Validator API to gRPC' (#239) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #239
2025-07-22 04:32:04 +00:00
740e6368b1 Merge pull request 'Convert Internal API to gRPC' (#238) from grpc into staging
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Reviewed-on: #238
2025-07-22 02:25:12 +00:00
746ac8e8a7 validator: convert to gRPC
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-19 04:07:28 -07:00
bdfe16ed39 validator: extend grpc 2025-07-19 04:07:28 -07:00
3c21d8948a validator: grpc 2025-07-19 04:07:28 -07:00
eaa8f704ea validator: add rust-grpc dep 2025-07-19 04:07:28 -07:00
d50ae0e664 submissions-api: remove internal api 2025-07-19 04:07:28 -07:00
f95d8b1665 validator: bump edition 2025-07-19 04:07:28 -07:00
524c56b6b5 submissions: convert validator backend to gRPC 2025-07-19 04:07:28 -07:00
ad7117a69c Merge pull request 'Scream Test Backend Overhaul' (#237) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #237
2025-07-18 06:28:18 +00:00
e05f69ef7d submissions: delete internal api 2025-07-17 23:13:22 -07:00
a45fbb370c submissions: rename services
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-17 20:51:03 -07:00
27a646c006 openapi: fix up tags
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-17 19:28:02 -07:00
dde6f3ebdb submissions: rename services
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-17 19:07:59 -07:00
3d08b144b1 submissions: move Roles to model
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-16 20:27:04 -07:00
63b701eb72 submissions: rename services 2025-07-16 20:27:04 -07:00
07e08af5ed De-monolithificate Services (#236)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #204.

The branch is called dedup but the patch adds code...

- Services both use an inner service that implements the underlying operations
- Struct fields are made private, preventing code cross-contamination
- Filter & Update structures are clearly defined, gaining clarity and type safety

Reviewed-on: #236
Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Co-committed-by: Rhys Lloyd <krakow20@gmail.com>
2025-07-17 03:18:01 +00:00
d566591ea6 Merge pull request 'Fix Audit Event Order + Check Unanchored Parts' (#234) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #234
2025-07-16 06:47:29 +00:00
391a0fe6f9 Maps Data Model (#233)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Create a data model to be used for maps.

Reviewed-on: #233
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-15 04:37:20 +00:00
0e06d00c21 validation: check for unanchored parts (#230)
All checks were successful
continuous-integration/drone/push Build is passing
Unanchored parts are always invalid.  Make a check to detect them.

Reviewed-on: #230
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-08 00:07:27 +00:00
cd0bfbaeb2 validation: check: use &Instance instead of &str
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-07 16:33:17 -07:00
70cb80ab9b submissions: order audit events by id ascending
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-07-05 06:07:50 -07:00
6d0af22485 submissions-api: v0.8.2 derive Hash for ID newtypes
All checks were successful
continuous-integration/drone/push Build is passing
2025-07-05 02:16:09 -07:00
c08fdddf36 submissions-api: add Hash,Eq,PartialEq to ID newtypes 2025-07-05 02:15:22 -07:00
424ef6238b Merge pull request 'Prevent Mapfix Duplicates + Correctly Report Transaction Errors' (#221) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #221
2025-07-01 12:40:26 +00:00
727b823fef update rbx_asset
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-07-01 04:57:29 -07:00
efefaa5e62 submissions: check rows affected (#220)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #218.

Reviewed-on: #220
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-01 11:37:29 +00:00
c6ce9b8f82 submissions: Check for duplicate mapfix (#219)
All checks were successful
continuous-integration/drone/push Build is passing
Mapfixes should check to see if you already have a mapfix for the target asset upon creation.

Reviewed-on: #219
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-01 11:31:06 +00:00
0f0ab4d3e0 Merge pull request 'Update Roblox Api + Update Deps' (#217) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #217
2025-07-01 08:47:27 +00:00
ca008f8fcf Update Roblox Api (#216)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Same api different language

Reviewed-on: #216
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-01 08:40:03 +00:00
e9affea859 Update Roblox Api + Update Deps (#215)
All checks were successful
continuous-integration/drone/push Build is passing
Roblox api changed, see 9f1bdd6a1f

Reviewed-on: #215
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-07-01 08:19:50 +00:00
3e2d782289 Merge pull request 'QoL Web Changes + Map Download Permission Fix' (#214) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #214
2025-06-30 10:20:03 +00:00
a31a92f131 Merge pull request 'submissions: check role for map location' (#213) from pr2 into staging
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #213
2025-06-30 09:46:50 +00:00
a5187be8a6 submissions: check role for map location
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-30 02:42:19 -07:00
825b2aa91a Clickable titles and show active mapfix (#211)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #144

Co-authored-by: ic3w0lf <bob@ic3.space>
Reviewed-on: #211
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: ic3w0lf22 <ic3w0lf22@noreply@itzana.me>
Co-committed-by: ic3w0lf22 <ic3w0lf22@noreply@itzana.me>
2025-06-29 19:06:52 +00:00
6f9cd952d4 Taking care of some issues & QOL changes (#209)
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Co-authored-by: ic3w0lf <bob@ic3.space>
Reviewed-on: #209
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
Co-authored-by: ic3w0lf22 <ic3w0lf22@noreply@itzana.me>
Co-committed-by: ic3w0lf22 <ic3w0lf22@noreply@itzana.me>
2025-06-28 07:44:59 +00:00
abb3cf3076 web: remove cursed ai code
All checks were successful
continuous-integration/drone/push Build is passing
2025-06-24 05:07:03 -07:00
dc446c545f Fix Bypass Submit + Audit Checklist + Map Download Button (#207)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #207
2025-06-24 06:41:56 +00:00
e234a87d05 Replace Bypass Submit With Submit Unchecked + Error Endpoint (#200)
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: #200
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-23 23:39:18 -07:00
40b0af0063 Revert "Validation: Make Assets Loadable on Maptest (#198)"
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
This reverts commit abd233ce65.
2025-06-23 23:34:58 -07:00
976adf2b66 Move Download Button Below Title (#206)
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Senior itzaname envisioned the button existing elsewhere.

Reviewed-on: #206
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-24 06:05:50 +00:00
53cc4b9e9e Map Download Button (#201)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #145.

All the backend should be implemented here, ~~I just don't know how to make a download button on the frontend.~~ I made a button, we'll see if it works.

- [x] ~~Add asset download api key to infra~~ this was never required

Reviewed-on: #201
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-24 05:09:51 +00:00
51f62f039b submissions-api: report script IDs not the whole thing
All checks were successful
continuous-integration/drone/push Build is passing
2025-06-18 03:55:03 -07:00
42cc783887 validation: fixups
All checks were successful
continuous-integration/drone/push Build is passing
2025-06-13 22:04:25 -07:00
ed7109270f Audit Event CheckList (#181)
Some checks failed
continuous-integration/drone/push Build is failing
Depends on #160, #196, #197.

Closes #147.

This introduces a new type of audit event: the CheckList.  This is a list of map checks that the validator performed.  The intention is to update the web interface to display  check marks for every check passed and  for every check failed, and also include the summary of why the check failed.  ~~The `Details` field would be the complete internal structure of the check in json, but I'm thinking it's unnecessary and should just be omitted.~~ The `Details` field has been removed.

```go
type Check struct {
	Name    string `json:"name"`
	Summary string `json:"summary"`
	Passed  bool   `json:"passed"`
}

type AuditEventDataCheckList struct {
	CheckList []Check `json:"check_list"`
}
```

This is created instead of the Error audit event when the validator requests changes, but the Error audit event can still be created for other purposes.

- [x] Make a proper error instead of hijacking a CheckList

Reviewed-on: #181
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-14 02:33:19 +00:00
abd233ce65 Validation: Make Assets Loadable on Maptest (#198)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #43.

This is a very bare bones implementation, but gets us started on https://git.itzana.me/StrafesNET/maps-service/milestone/3

This will break production as written!  A proper implementation requires a separate api key since the maptest places are to be hosted on a different group.

Edit: It will actually not break, because it is using cookie access. The staging cookie has permission to edit StrafesNET Maptest asset permissions via StrafesNET_CI3, while prod also has access via StrafesNET_CI2.  Both staging and prod versions of the website will add maptest asset access to the same places on StrafesNET Maptest.
Reviewed-on: #198
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-13 03:58:01 +00:00
215c39000b Replace bypass-submit with trigger-submit-unchecked (#199)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Bypassing the submit process means that the map revision is not updated.  Change the endpoint and include a flag to skip the map checks but update the revision.

Reviewed-on: #199
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-13 00:15:16 +00:00
c4d97b6537 Change Error to Explicit Endpoint (#197)
All checks were successful
continuous-integration/drone/push Build is passing
This changes the way that the internal api works.  The backend used to implicitly create an error for specifc endpoints, but now the validator explicitly creates the error itself.

Reviewed-on: #197
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-12 00:55:09 +00:00
0834400c05 Compartmentalize Monolith (#196)
All checks were successful
continuous-integration/drone/push Build is passing
This isn't the full job, notably Operations are still sprinkled about, and having some code sharing between `service` and `service_internal` would be nice, but that is sketchy without the explicitness of Rust's traits.

Reviewed-on: #196
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-12 00:19:56 +00:00
463d14d2b5 submissions-api: type all ids (#195)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #195
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-11 05:11:14 +00:00
6a52166901 submissions-api: Add Releaser Endpoints (#194)
All checks were successful
continuous-integration/drone/push Build is passing
Also uses enums over ints for GameID.

Reviewed-on: #194
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-11 04:11:21 +00:00
8ab772ea81 Validate Asset Version + Website QoL + Script Names Fix (#193)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #193
2025-06-10 23:53:07 +00:00
d7c2ad3dde submissions: actually fix script names (#192)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Actually closes #165.

Reviewed-on: #192
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-10 04:15:27 +00:00
f54bf1dc34 submissions: fix script names (#191)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #165.

Reviewed-on: #191
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-10 04:08:32 +00:00
644c04c133 First wave of QOL impovementss (#190)
All checks were successful
continuous-integration/drone/push Build is passing
- Updated all avatars/thumbnails to just 307 to the roblox cdn
- Moved data loading for submissions and mapfixes into a common hook
- Data will now auto refresh every 5 seconds if state Validating, Submitting, Uploading (ing Statuses) #102
- A loading icon will also show when on a "ing" status
- You don't have to be logged in to see the submissions/mapfixes
- Added text if there are no comments
- Hide comment box if not logged in

Reviewed-on: #190
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-06-10 02:18:55 +00:00
8006e3efbc validation: refuse to validate if model has updates (#188)
All checks were successful
continuous-integration/drone/push Build is passing
Closes #187.

Reviewed-on: #188
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-09 03:04:33 +00:00
9b58b1d26a Frontend Rework (#185)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #185
2025-06-09 01:09:17 +00:00
b60d2b6186 Submissions: Fix Comments (#184)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Closes #163.

Reviewed-on: #184
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-06-09 01:03:55 +00:00
8f2a0b53e4 Refactor remaining frontend pages (#183)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #183
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-06-09 00:33:27 +00:00
70dd8502f4 Merge pull request 'submissions: add missing audit even when requesting changes for a mapfix' (#180) from pr2 into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #180
2025-06-08 05:49:28 +00:00
5b977289e7 Merge pull request 'validation: include more details in duplicates error' (#179) from dupes into staging
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: #179
2025-06-08 05:49:11 +00:00
7b3af95f3d Merge pull request 'Remove class_is_a' (#178) from pr1 into staging
Some checks are pending
continuous-integration/drone/push Build is running
Reviewed-on: #178
2025-06-08 05:48:55 +00:00
4d78a9b2c5 submissions: add missing audit even when requesting changes for a mapfix
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-07 22:42:39 -07:00
ec59a83379 validation: include more details in duplicates error
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-07 22:34:57 -07:00
54bf3f55a0 Rework submission/mapfix/maps list views (#173)
All checks were successful
continuous-integration/drone/push Build is passing
Refactored maps/landing/mapfix/submission and navbar

Reviewed-on: #173
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-06-08 03:41:36 +00:00
14f404ffe3 Merge pull request 'Openapi: Document Enum Fields' (#177) from openapi-doc into staging
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #177
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
2025-06-08 00:21:21 +00:00
0e1d2fe50a openapi: generate
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-07 17:09:51 -07:00
ada8c322da openapi: add descriptions to enum fields
All checks were successful
continuous-integration/drone/push Build is passing
2025-06-07 17:07:47 -07:00
84d2bfef20 remove class_is_a
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-06-07 16:29:06 -07:00
7689001e74 Merge pull request '404 / 500 Thumbnails + Fix Regex Capture Groups' (#168) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #168
2025-06-07 04:02:26 +00:00
e89abed3d5 Merge pull request 'Thumbnail Fixes + Bypass Submit Button' (#161) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #161
2025-06-05 01:34:35 +00:00
b792d33164 Merge pull request 'Update Rust Dependencies (Roblox Format Zstd Support)' (#142) from staging into master
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #142
2025-06-01 23:13:58 +00:00
929b5949f0 Merge pull request 'Snapshot "Working" Code' (#139) from staging into master
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #139
2025-04-27 21:21:05 +00:00
246 changed files with 34629 additions and 27959 deletions

View File

@@ -7,7 +7,45 @@ platform:
arch: amd64
steps:
- name: api
- name: build-backend
image: golang:1.24.0
environment:
GIT_USER:
from_secret: GIT_USER
GIT_PASS:
from_secret: GIT_PASS
commands:
- echo "machine git.itzana.me login $${GIT_USER} password $${GIT_PASS}" > ~/.netrc
- chmod 600 ~/.netrc
- make build-backend
when:
branch:
- master
- staging
- name: build-validator
image: clux/muslrust:1.91.0-stable
commands:
- make build-validator
when:
branch:
- master
- staging
- name: build-frontend
image: oven/bun:1.3.3
commands:
- apt-get update
- apt-get install make
- make build-frontend
when:
branch:
- master
- staging
event:
- pull_request
- name: image-backend
image: plugins/docker
settings:
registry: registry.itzana.me
@@ -19,8 +57,10 @@ steps:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
dockerfile: Containerfile
dockerfile: Dockerfile
context: .
depends_on:
- build-backend
when:
branch:
- master
@@ -28,7 +68,7 @@ steps:
event:
- push
- name: frontend
- name: image-frontend
image: plugins/docker
settings:
registry: registry.itzana.me
@@ -49,7 +89,7 @@ steps:
event:
- push
- name: validator
- name: image-validator
image: plugins/docker
settings:
registry: registry.itzana.me
@@ -62,7 +102,9 @@ steps:
password:
from_secret: REGISTRY_PASS
dockerfile: validation/Containerfile
context: validation
context: .
depends_on:
- build-validator
when:
branch:
- master
@@ -83,9 +125,9 @@ steps:
PASSWORD:
from_secret: ARGO_PASS
depends_on:
- api
- frontend
- validator
- image-backend
- image-frontend
- image-validator
when:
branch:
- master
@@ -94,64 +136,19 @@ steps:
- push
# pr dry run
- name: api-pr
image: plugins/docker
settings:
registry: registry.itzana.me
repo: registry.itzana.me/strafesnet/maptest-validator
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
dockerfile: Containerfile
context: .
dry_run: true
when:
event:
- pull_request
- name: frontend-pr
image: plugins/docker
settings:
registry: registry.itzana.me
repo: registry.itzana.me/strafesnet/maptest-validator
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
dockerfile: web/Containerfile
context: web
dry_run: true
when:
event:
- pull_request
- name: validator-pr
image: plugins/docker
settings:
registry: registry.itzana.me
repo: registry.itzana.me/strafesnet/maptest-validator
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
dockerfile: validation/Containerfile
context: validation
dry_run: true
when:
event:
- pull_request
- name: build-pr
image: alpine
commands:
- echo "Success!"
depends_on:
- api-pr
- frontend-pr
- validator-pr
- build-backend
- build-validator
- build-frontend
when:
event:
- pull_request
---
kind: signature
hmac: 11e6d7f1eb839d3798fdcb642ca5523c011bd14c1f3a0343a9c3106bab9ef142
hmac: 6de9d4b91f14b30561856daf275d1fd523e1ce7a5a3651b660f0d8907b4692fb
...

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
build
.idea
/target

1424
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[workspace]
members = [
"validation",
"validation/api",
"submissions-api-rs",
]
resolver = "2"

View File

@@ -1,33 +0,0 @@
# Stage 1: Build
FROM registry.itzana.me/docker-proxy/golang:1.24 AS builder
# Set the working directory in the container
WORKDIR /app
# Copy go.mod and go.sum files
COPY go.mod go.sum ./
# 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 registry.itzana.me/docker-proxy/alpine:3.21
# 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"]

3
Dockerfile Normal file
View File

@@ -0,0 +1,3 @@
FROM alpine
COPY build/server /
ENTRYPOINT ["/server"]

View File

@@ -1,12 +1,41 @@
submissions:
DOCKER_BUILDKIT=1 docker build . -f Containerfile -t maps-service-submissions
clean:
rm -rf build
rm -rf web/build
web:
docker build web -f web/Containerfile -t maps-service-web
# build
build-backend:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o build/server cmd/maps-service/service.go
validation:
docker build validation -f validation/Containerfile -t maps-service-validation
build-validator:
cargo build --release --target x86_64-unknown-linux-musl --bin maps-validation
all: submissions web validation
build-frontend:
rm -rf web/build
cd web && bun install --frozen-lockfile
cd web && bun run build
.PHONY: submissions web validation
build: build-backend build-validator build-frontend
# image
image-backend:
docker build . -t maptest-api
image-validator:
docker build . -f validation/Containerfile -t maptest-validator
image-frontend:
docker build web -f web/Containerfile -t maptest-frontend
# docker
docker-backend:
make build-backend
make image-backend
docker-validator:
make build-validator
make image-validator
docker-frontend:
make image-frontend
docker: docker-backend docker-validator docker-frontend
.PHONY: clean build-backend build-validator build-frontend build image-backend image-validator image-frontend docker-backend docker-validator docker-frontend docker

View File

@@ -13,11 +13,11 @@ 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).
```bash
go generate -run "go run github.com/ogen-go/ogen/cmd/ogen@latest --target api --clean openapi.yaml"
go generate
```
2. Build the project.
```bash
go build git.itzana.me/strafesnet/maps-service
make build-backend
```
By default, the project opens at `localhost:8080`.
@@ -47,14 +47,16 @@ AUTH_HOST="http://localhost:8083/"
Prerequisite: rust installed
1. `cd validation`
2. `cargo run --release`
1. `cargo run --release -p maps-validation`
Environment Variables:
- ROBLOX_GROUP_ID
- RBXCOOKIE
- RBX_API_KEY
- API_HOST_INTERNAL
- NATS_HOST
- LOAD_ASSET_VERSION_PLACE_ID
- LOAD_ASSET_VERSION_UNIVERSE_ID
#### License

View File

@@ -7,6 +7,16 @@ import (
"os"
)
// @title StrafesNET Maps API
// @version 1.0
// @description Obtain an api key at https://dev.strafes.net
// @description Requires Maps:Read permission
// @BasePath /public-api/v1
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name X-API-Key
func main() {
log.SetLevel(log.InfoLevel)
log.SetFormatter(&log.JSONFormatter{})
@@ -15,6 +25,7 @@ func main() {
app := cmds.NewApp()
app.Commands = []*cli.Command{
cmds.NewServeCommand(),
cmds.NewApiCommand(),
}
if err := app.Run(os.Args); err != nil {

View File

@@ -13,7 +13,7 @@ services:
submissions:
image:
maps-service-submissions
maptest-api
container_name: submissions
command: [
# debug
@@ -33,6 +33,8 @@ services:
"--auth-rpc-host","authrpc:8081",
"--data-rpc-host","dataservice:9000",
]
env_file:
- /home/quat/auth-compose/strafesnet_staging.env
depends_on:
- authrpc
- nats
@@ -43,7 +45,7 @@ services:
web:
image:
maps-service-web
maptest-frontend
networks:
- maps-service-network
ports:
@@ -54,14 +56,16 @@ services:
validation:
image:
maps-service-validation
maptest-validator
container_name: validation
env_file:
- ../auth-compose/strafesnet_staging.env
- /home/quat/auth-compose/strafesnet_staging.env
environment:
- ROBLOX_GROUP_ID=17032139 # "None" is special case string value
- API_HOST_INTERNAL=http://submissions:8083/v1
- NATS_HOST=nats:4222
- LOAD_ASSET_VERSION_PLACE_ID=14001440964
- LOAD_ASSET_VERSION_UNIVERSE_ID=4850603885
depends_on:
- nats
# note: this races the submissions which creates a nats stream
@@ -101,7 +105,7 @@ services:
- REDIS_ADDR=authredis:6379
- RBX_GROUP_ID=17032139
env_file:
- ../auth-compose/auth-service.env
- /home/quat/auth-compose/auth-service.env
depends_on:
- authredis
networks:
@@ -115,7 +119,7 @@ services:
environment:
- REDIS_ADDR=authredis:6379
env_file:
- ../auth-compose/auth-service.env
- /home/quat/auth-compose/auth-service.env
depends_on:
- authredis
networks:

242
docs/docs.go Normal file
View File

@@ -0,0 +1,242 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs
import "github.com/swaggo/swag"
const docTemplate = `{
"schemes": {{ marshal .Schemes }},
"swagger": "2.0",
"info": {
"description": "{{escape .Description}}",
"title": "{{.Title}}",
"contact": {},
"version": "{{.Version}}"
},
"host": "{{.Host}}",
"basePath": "{{.BasePath}}",
"paths": {
"/map": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a list of maps",
"produces": [
"application/json"
],
"tags": [
"maps"
],
"summary": "List maps",
"parameters": [
{
"maximum": 100,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Page size (max 100)",
"name": "page_size",
"in": "query"
},
{
"minimum": 1,
"type": "integer",
"default": 1,
"description": "Page number",
"name": "page_number",
"in": "query"
},
{
"type": "integer",
"name": "game_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/PagedResponse-Map"
}
},
"default": {
"description": "General error response",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/map/{id}": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a specific map by its ID",
"produces": [
"application/json"
],
"tags": [
"maps"
],
"summary": "Get map by ID",
"parameters": [
{
"type": "integer",
"description": "Map ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Response-Map"
}
},
"404": {
"description": "Map not found",
"schema": {
"$ref": "#/definitions/Error"
}
},
"default": {
"description": "General error response",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Error": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"Map": {
"type": "object",
"properties": {
"asset_version": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"creator": {
"type": "string"
},
"date": {
"type": "string"
},
"display_name": {
"type": "string"
},
"game_id": {
"type": "integer"
},
"id": {
"type": "integer"
},
"load_count": {
"type": "integer"
},
"modes": {
"type": "integer"
},
"submitter": {
"type": "integer"
},
"thumbnail": {
"type": "integer"
},
"updated_at": {
"type": "string"
}
}
},
"PagedResponse-Map": {
"type": "object",
"properties": {
"data": {
"description": "Data contains the actual response payload",
"type": "array",
"items": {
"$ref": "#/definitions/Map"
}
},
"pagination": {
"description": "Pagination contains information about paging",
"allOf": [
{
"$ref": "#/definitions/Pagination"
}
]
}
}
},
"Pagination": {
"type": "object",
"properties": {
"page": {
"description": "Current page number",
"type": "integer"
},
"page_size": {
"description": "Number of items per page",
"type": "integer"
}
}
},
"Response-Map": {
"type": "object",
"properties": {
"data": {
"description": "Data contains the actual response payload",
"allOf": [
{
"$ref": "#/definitions/Map"
}
]
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
}
}`
// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "1.0",
Host: "",
BasePath: "/public-api/v1",
Schemes: []string{},
Title: "StrafesNET Maps API",
Description: "Obtain an api key at https://dev.strafes.net\nRequires Maps:Read permission",
InfoInstanceName: "swagger",
SwaggerTemplate: docTemplate,
LeftDelim: "{{",
RightDelim: "}}",
}
func init() {
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
}

217
docs/swagger.json Normal file
View File

@@ -0,0 +1,217 @@
{
"swagger": "2.0",
"info": {
"description": "Obtain an api key at https://dev.strafes.net\nRequires Maps:Read permission",
"title": "StrafesNET Maps API",
"contact": {},
"version": "1.0"
},
"basePath": "/public-api/v1",
"paths": {
"/map": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a list of maps",
"produces": [
"application/json"
],
"tags": [
"maps"
],
"summary": "List maps",
"parameters": [
{
"maximum": 100,
"minimum": 1,
"type": "integer",
"default": 10,
"description": "Page size (max 100)",
"name": "page_size",
"in": "query"
},
{
"minimum": 1,
"type": "integer",
"default": 1,
"description": "Page number",
"name": "page_number",
"in": "query"
},
{
"type": "integer",
"name": "game_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/PagedResponse-Map"
}
},
"default": {
"description": "General error response",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
},
"/map/{id}": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get a specific map by its ID",
"produces": [
"application/json"
],
"tags": [
"maps"
],
"summary": "Get map by ID",
"parameters": [
{
"type": "integer",
"description": "Map ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/Response-Map"
}
},
"404": {
"description": "Map not found",
"schema": {
"$ref": "#/definitions/Error"
}
},
"default": {
"description": "General error response",
"schema": {
"$ref": "#/definitions/Error"
}
}
}
}
}
},
"definitions": {
"Error": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"Map": {
"type": "object",
"properties": {
"asset_version": {
"type": "integer"
},
"created_at": {
"type": "string"
},
"creator": {
"type": "string"
},
"date": {
"type": "string"
},
"display_name": {
"type": "string"
},
"game_id": {
"type": "integer"
},
"id": {
"type": "integer"
},
"load_count": {
"type": "integer"
},
"modes": {
"type": "integer"
},
"submitter": {
"type": "integer"
},
"thumbnail": {
"type": "integer"
},
"updated_at": {
"type": "string"
}
}
},
"PagedResponse-Map": {
"type": "object",
"properties": {
"data": {
"description": "Data contains the actual response payload",
"type": "array",
"items": {
"$ref": "#/definitions/Map"
}
},
"pagination": {
"description": "Pagination contains information about paging",
"allOf": [
{
"$ref": "#/definitions/Pagination"
}
]
}
}
},
"Pagination": {
"type": "object",
"properties": {
"page": {
"description": "Current page number",
"type": "integer"
},
"page_size": {
"description": "Number of items per page",
"type": "integer"
}
}
},
"Response-Map": {
"type": "object",
"properties": {
"data": {
"description": "Data contains the actual response payload",
"allOf": [
{
"$ref": "#/definitions/Map"
}
]
}
}
}
},
"securityDefinitions": {
"ApiKeyAuth": {
"type": "apiKey",
"name": "X-API-Key",
"in": "header"
}
}
}

141
docs/swagger.yaml Normal file
View File

@@ -0,0 +1,141 @@
basePath: /public-api/v1
definitions:
Error:
properties:
error:
type: string
type: object
Map:
properties:
asset_version:
type: integer
created_at:
type: string
creator:
type: string
date:
type: string
display_name:
type: string
game_id:
type: integer
id:
type: integer
load_count:
type: integer
modes:
type: integer
submitter:
type: integer
thumbnail:
type: integer
updated_at:
type: string
type: object
PagedResponse-Map:
properties:
data:
description: Data contains the actual response payload
items:
$ref: '#/definitions/Map'
type: array
pagination:
allOf:
- $ref: '#/definitions/Pagination'
description: Pagination contains information about paging
type: object
Pagination:
properties:
page:
description: Current page number
type: integer
page_size:
description: Number of items per page
type: integer
type: object
Response-Map:
properties:
data:
allOf:
- $ref: '#/definitions/Map'
description: Data contains the actual response payload
type: object
info:
contact: {}
description: |-
Obtain an api key at https://dev.strafes.net
Requires Maps:Read permission
title: StrafesNET Maps API
version: "1.0"
paths:
/map:
get:
description: Get a list of maps
parameters:
- default: 10
description: Page size (max 100)
in: query
maximum: 100
minimum: 1
name: page_size
type: integer
- default: 1
description: Page number
in: query
minimum: 1
name: page_number
type: integer
- in: query
name: game_id
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/PagedResponse-Map'
default:
description: General error response
schema:
$ref: '#/definitions/Error'
security:
- ApiKeyAuth: []
summary: List maps
tags:
- maps
/map/{id}:
get:
description: Get a specific map by its ID
parameters:
- description: Map ID
in: path
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/Response-Map'
"404":
description: Map not found
schema:
$ref: '#/definitions/Error'
default:
description: General error response
schema:
$ref: '#/definitions/Error'
security:
- ApiKeyAuth: []
summary: Get map by ID
tags:
- maps
securityDefinitions:
ApiKeyAuth:
in: header
name: X-API-Key
type: apiKey
swagger: "2.0"

View File

@@ -1,4 +1,4 @@
package main
//go:generate swag init -g ./cmd/maps-service/service.go
//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target pkg/api --clean openapi.yaml
//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target pkg/internal --clean openapi-internal.yaml

99
go.mod
View File

@@ -1,64 +1,105 @@
module git.itzana.me/strafesnet/maps-service
go 1.22
go 1.24.0
toolchain go1.23.3
toolchain go1.24.5
require (
git.itzana.me/strafesnet/go-grpc v0.0.0-20241129081229-9e166b3d11f7
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628052121-92af8193b5ed
git.itzana.me/strafesnet/go-grpc v0.0.0-20250815013325-1c84f73bdcb1
git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9
github.com/dchest/siphash v1.2.3
github.com/gin-gonic/gin v1.10.1
github.com/go-faster/errors v0.7.1
github.com/go-faster/jx v1.1.0
github.com/go-faster/jx v1.2.0
github.com/nats-io/nats.go v1.37.0
github.com/ogen-go/ogen v1.2.1
github.com/ogen-go/ogen v1.18.0
github.com/redis/go-redis/v9 v9.10.0
github.com/sirupsen/logrus v1.9.3
github.com/urfave/cli/v2 v2.27.5
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/metric v1.32.0
go.opentelemetry.io/otel/trace v1.32.0
github.com/swaggo/files v1.0.1
github.com/swaggo/gin-swagger v1.6.0
github.com/swaggo/swag v1.16.6
github.com/urfave/cli/v2 v2.27.6
go.opentelemetry.io/otel v1.39.0
go.opentelemetry.io/otel/metric v1.39.0
go.opentelemetry.io/otel/trace v1.39.0
google.golang.org/grpc v1.48.0
gorm.io/driver/postgres v1.5.10
gorm.io/gorm v1.25.10
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.25.12
)
require (
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/spec v0.20.4 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.5.5 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.17.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.18.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/crypto v0.23.0 // indirect
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.46.0 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/tools v0.40.0 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.28.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
require (
github.com/dlclark/regexp2 v1.11.0 // indirect
github.com/fatih/color v1.17.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-faster/yaml v0.4.6 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
// github.com/golang/protobuf v1.5.4 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/segmentio/asm v1.2.0 // indirect
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
github.com/segmentio/asm v1.2.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/text v0.32.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

250
go.sum
View File

@@ -1,14 +1,36 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.itzana.me/strafesnet/go-grpc v0.0.0-20241129081229-9e166b3d11f7 h1:5XzWd3ZZjSw1M60IfHuILty2vRPBYiqM0FZ+E7uHCi8=
git.itzana.me/strafesnet/go-grpc v0.0.0-20241129081229-9e166b3d11f7/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs=
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628052121-92af8193b5ed h1:eGWIQx2AOrSsLC2dieuSs8MCliRE60tvpZnmxsTBtKc=
git.itzana.me/StrafesNET/dev-service v0.0.0-20250628052121-92af8193b5ed/go.mod h1:KJal0K++M6HEzSry6JJ2iDPZtOQn5zSstNlDbU3X4Jg=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250815013325-1c84f73bdcb1 h1:imXibfeYcae6og0TTDUFRQ3CQtstGjIoLbCn+pezD2o=
git.itzana.me/strafesnet/go-grpc v0.0.0-20250815013325-1c84f73bdcb1/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs=
git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9 h1:7lU6jyR7S7Rhh1dnUp7GyIRHUTBXZagw8F4n4hOyxLw=
git.itzana.me/strafesnet/utils v0.0.0-20220716194944-d8ca164052f9/go.mod h1:uyYerSieEt4v0MJCdPLppG0LtJ4Yj035vuTetWGsxjY=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
@@ -17,13 +39,18 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/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/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
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.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
github.com/dlclark/regexp2 v1.11.5/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.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -32,19 +59,51 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4=
github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg=
github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg=
github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI=
github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE=
github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I=
github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -68,8 +127,9 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -77,66 +137,125 @@ github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.17.6 h1:60eq2E/jlfwQXtvZEeBUYADs+BwKBWURIY+Gj2eRGjI=
github.com/klauspost/compress v1.17.6/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM=
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/ogen-go/ogen v1.2.1 h1:C5A0lvUMu2wl+eWIxnpXMWnuOJ26a2FyzR1CIC2qG0M=
github.com/ogen-go/ogen v1.2.1/go.mod h1:P2zQdEu8UqaVRfD5GEFvl+9q63VjMLvDquq1wVbyInM=
github.com/ogen-go/ogen v1.18.0 h1:6RQ7lFBjOeNaUWu4getfqIh4GJbEY4hqKuzDtec/g60=
github.com/ogen-go/ogen v1.18.0/go.mod h1:dHFr2Wf6cA7tSxMI+zPC21UR5hAlDw8ZYUkK3PziURY=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/redis/go-redis/v9 v9.10.0 h1:FxwK3eV8p/CQa0Ch276C7u2d0eNC9kCmAYQ7mCXCzVs=
github.com/redis/go-redis/v9 v9.10.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M=
github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo=
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
@@ -144,55 +263,103 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg=
golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0=
golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@@ -222,9 +389,11 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -232,12 +401,15 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/postgres v1.5.10 h1:7Lggqempgy496c0WfHXsYWxk3Th+ZcW66/21QhVFdeE=
gorm.io/driver/postgres v1.5.10/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI=
gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
gorm.io/gorm v1.21.11/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gorm.io/gorm v1.25.10 h1:dQpO+33KalOA+aFYGlK+EfxcI5MbO7EP2yYygwh9h+s=
gorm.io/gorm v1.25.10/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@@ -1,862 +0,0 @@
openapi: 3.1.0
info:
title: StrafesNET Internal - OpenAPI 3.1
description: Internal operations inaccessible from the public internet.
version: 0.1.0
tags:
- name: Mapfixes
description: Mapfix operations
- name: Submissions
description: Submission operations
paths:
/mapfixes:
post:
summary: Create a mapfix
operationId: createMapfix
tags:
- Mapfixes
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MapfixCreate'
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/MapfixID"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/validated-model:
post:
summary: Update validated model
operationId: updateMapfixValidatedModel
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ValidatedModelID
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
- name: ValidatedModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-submitted:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
operationId: actionMapfixSubmitted
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
- name: DisplayName
in: query
required: true
schema:
type: string
maxLength: 128
- name: Creator
in: query
required: true
schema:
type: string
maxLength: 128
- name: GameID
in: query
required: true
schema:
type: integer
format: int32
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-request-changes:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
operationId: actionMapfixRequestChanges
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-validated:
post:
summary: (Internal endpoint) Role Validator changes status from Validating -> Validated
operationId: actionMapfixValidated
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-failed:
post:
summary: (Internal endpoint) Role Validator changes status from Validating -> Accepted
operationId: actionMapfixAccepted
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/validator-uploaded:
post:
summary: (Internal endpoint) Role Validator changes status from Uploading -> Uploaded
operationId: actionMapfixUploaded
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/operations/{OperationID}/status/operation-failed:
post:
summary: (Internal endpoint) Fail an operation and write a StatusMessage
operationId: actionOperationFailed
tags:
- Operations
parameters:
- $ref: '#/components/parameters/OperationID'
- name: StatusMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions:
post:
summary: Create a new submission
operationId: createSubmission
tags:
- Submissions
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubmissionCreate'
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/SubmissionID"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/validated-model:
post:
summary: Update validated model
operationId: updateSubmissionValidatedModel
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ValidatedModelID
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
- name: ValidatedModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-submitted:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
operationId: actionSubmissionSubmitted
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ModelVersion
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
- name: DisplayName
in: query
required: true
schema:
type: string
maxLength: 128
- name: Creator
in: query
required: true
schema:
type: string
maxLength: 128
- name: GameID
in: query
required: true
schema:
type: integer
format: int32
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-request-changes:
post:
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
operationId: actionSubmissionRequestChanges
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-validated:
post:
summary: (Internal endpoint) Role Validator changes status from Validating -> Validated
operationId: actionSubmissionValidated
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-failed:
post:
summary: (Internal endpoint) Role Validator changes status from Validating -> Accepted
operationId: actionSubmissionAccepted
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: ErrorMessage
in: query
required: true
schema:
type: string
minLength: 0
maxLength: 4096
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/validator-uploaded:
post:
summary: (Internal endpoint) Role Validator changes status from Uploading -> Uploaded
operationId: actionSubmissionUploaded
tags:
- Submissions
parameters:
- $ref: '#/components/parameters/SubmissionID'
- name: UploadedAssetID
in: query
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/script-policy:
get:
summary: Get list of script policies
operationId: listScriptPolicy
tags:
- ScriptPolicy
parameters:
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/Limit"
- name: FromScriptHash
in: query
schema:
type: string
minLength: 16
maxLength: 16
- name: ToScriptID
in: query
schema:
type: integer
format: int64
minimum: 0
- name: Policy
in: query
schema:
type: integer
format: int32
minimum: 0
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ScriptPolicy"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a new script policy
operationId: createScriptPolicy
tags:
- ScriptPolicy
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptPolicyCreate'
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/ScriptPolicyID"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/scripts:
get:
summary: Get list of scripts
operationId: listScripts
tags:
- Script
parameters:
- $ref: "#/components/parameters/Page"
- $ref: "#/components/parameters/Limit"
- name: Hash
in: query
schema:
type: string
minLength: 16
maxLength: 16
- name: Name
in: query
schema:
type: string
maxLength: 128
- name: Source
in: query
schema:
type: string
maxLength: 1048576
- name: ResourceType
in: query
schema:
type: integer
format: int32
minimum: 0
- name: ResourceID
in: query
schema:
type: integer
format: int64
minimum: 0
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Script"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a new script
operationId: createScript
tags:
- Scripts
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ScriptCreate'
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/ScriptID"
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'
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"
components:
parameters:
MapfixID:
name: MapfixID
in: path
required: true
description: The unique identifier for a submission.
schema:
type: integer
format: int64
minimum: 0
OperationID:
name: OperationID
in: path
required: true
description: The unique identifier for a long-running operation.
schema:
type: integer
format: int32
minimum: 0
SubmissionID:
name: SubmissionID
in: path
required: true
description: The unique identifier for a submission.
schema:
type: integer
format: int64
minimum: 0
ScriptID:
name: ScriptID
in: path
required: true
description: The unique identifier for a script.
schema:
type: integer
format: int64
minimum: 0
Page:
name: Page
in: query
required: true
schema:
type: integer
format: int32
minimum: 1
Limit:
name: Limit
in: query
required: true
schema:
type: integer
format: int32
minimum: 1
maximum: 100
schemas:
MapfixID:
required:
- MapfixID
type: object
properties:
MapfixID:
type: integer
format: int64
minimum: 0
SubmissionID:
required:
- SubmissionID
type: object
properties:
SubmissionID:
type: integer
format: int64
minimum: 0
ScriptID:
required:
- ScriptID
type: object
properties:
ScriptID:
type: integer
format: int64
minimum: 0
ScriptPolicyID:
required:
- ScriptPolicyID
type: object
properties:
ScriptPolicyID:
type: integer
format: int64
minimum: 0
MapfixCreate:
required:
- OperationID
- AssetOwner
- DisplayName
- Creator
- GameID
- AssetID
- AssetVersion
- TargetAssetID
- Description
type: object
properties:
OperationID:
type: integer
format: int32
minimum: 0
AssetOwner:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
Creator:
type: string
maxLength: 128
GameID:
type: integer
format: int32
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
TargetAssetID:
type: integer
format: int64
minimum: 0
Description:
type: string
maxLength: 256
SubmissionCreate:
required:
- OperationID
- AssetOwner
- DisplayName
- Creator
- GameID
- AssetID
- AssetVersion
- Status
- Roles
type: object
properties:
OperationID:
type: integer
format: int32
minimum: 0
AssetOwner:
type: integer
format: int64
minimum: 0
DisplayName:
type: string
maxLength: 128
Creator:
type: string
maxLength: 128
GameID:
type: integer
format: int32
minimum: 0
AssetID:
type: integer
format: int64
minimum: 0
AssetVersion:
type: integer
format: int64
minimum: 0
Status:
type: integer
format: uint32
minimum: 0
maximum: 9
Roles:
type: integer
format: uint32
Script:
required:
- ID
- Name
- Hash
- Source
- ResourceType
- ResourceID
type: object
properties:
ID:
type: integer
format: int64
minimum: 0
Name:
type: string
maxLength: 128
Hash:
type: string
minLength: 16
maxLength: 16
Source:
type: string
maxLength: 1048576
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptCreate:
required:
- Name
- Source
- ResourceType
# - ResourceID
type: object
properties:
Name:
type: string
maxLength: 128
Source:
type: string
maxLength: 1048576
ResourceType:
type: integer
format: int32
minimum: 0
ResourceID:
type: integer
format: int64
minimum: 0
ScriptPolicy:
required:
- ID
- FromScriptHash
- ToScriptID
- Policy
type: object
properties:
ID:
type: integer
format: int64
minimum: 0
FromScriptHash:
type: string
minLength: 16
maxLength: 16
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
ScriptPolicyCreate:
required:
- FromScriptID
- ToScriptID
- Policy
type: object
properties:
FromScriptID:
type: integer
format: int64
minimum: 0
ToScriptID:
type: integer
format: int64
minimum: 0
Policy:
type: integer
format: int32
minimum: 0
Error:
description: Represents error object
type: object
properties:
code:
type: integer
format: int64
minimum: 0
message:
type: string
required:
- code
- message

View File

@@ -14,15 +14,41 @@ tags:
description: Long-running operations
- name: Session
description: Session queries
- name: Stats
description: Statistics queries
- name: Submissions
description: Submission operations
- name: Scripts
description: Script operations
- name: ScriptPolicy
description: Script policy operations
- name: Thumbnails
description: Thumbnail operations
- name: Users
description: User operations
security:
- cookieAuth: []
paths:
/stats:
get:
summary: Get aggregate statistics
operationId: getStats
tags:
- Stats
security: []
responses:
"200":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/Stats"
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/session/user:
get:
summary: Get information about the currently logged in user
@@ -114,6 +140,13 @@ paths:
format: int32
minimum: 0
maximum: 4
description: >
Sort order:
* `0` - Disabled
* `1` - DisplayNameAscending
* `2` - DisplayNameDescending
* `3` - DateAscending
* `4` - DateDescending
responses:
"200":
description: Successful response
@@ -151,6 +184,34 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/maps/{MapID}/download:
get:
summary: Download the map asset
operationId: downloadMapAsset
tags:
- Maps
parameters:
- name: MapID
in: path
required: true
schema:
type: integer
format: int64
minimum: 0
responses:
"200":
description: Successful response
content:
application/octet-stream:
schema:
type: string
format: binary
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes:
get:
summary: Get list of mapfixes
@@ -178,6 +239,11 @@ paths:
format: int32
minimum: 1
maximum: 5
description: >
Game ID:
* `1` - Bhop
* `2` - Surf
* `5` - FlyTrials
- name: Sort
in: query
schema:
@@ -185,6 +251,13 @@ paths:
format: int32
minimum: 0
maximum: 4
description: >
Sort order:
* `0` - Disabled
* `1` - DisplayNameAscending
* `2` - DisplayNameDescending
* `3` - DateAscending
* `4` - DateDescending
- name: Submitter
in: query
schema:
@@ -197,6 +270,12 @@ paths:
type: integer
format: int64
minimum: 0
- name: AssetVersion
in: query
schema:
type: integer
format: int64
minimum: 0
- name: TargetAssetID
in: query
schema:
@@ -210,6 +289,24 @@ paths:
format: int32
minimum: 0
maximum: 9
description: >
// Phase: Creation
* `0` - UnderConstruction
* `1` - ChangesRequested
// Phase: Review
* `2` - Submitting
* `3` - Submitted
// Phase: Testing
* `4` - AcceptedUnvalidated // pending script review, can re-trigger validation
* `5` - Validating
* `6` - Validated
* `7` - Uploading
// Phase: Final MapfixStatus
* `8` - Uploaded // uploaded to the group, but pending release
* `9` - Rejected
responses:
"200":
description: Successful response
@@ -384,10 +481,10 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/bypass-submit:
/mapfixes/{MapfixID}/status/trigger-submit-unchecked:
post:
summary: Role Reviewer changes status from ChangesRequested -> Submitted
operationId: actionMapfixBypassSubmit
summary: Role Reviewer changes status from ChangesRequested -> Submitting
operationId: actionMapfixTriggerSubmitUnchecked
tags:
- Mapfixes
parameters:
@@ -522,7 +619,7 @@ paths:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/trigger-upload:
post:
summary: Role Admin changes status from Validated -> Uploading
summary: Role MapfixUpload changes status from Validated -> Uploading
operationId: actionMapfixTriggerUpload
tags:
- Mapfixes
@@ -539,7 +636,7 @@ paths:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/reset-uploading:
post:
summary: Role Admin manually resets uploading softlock and changes status from Uploading -> Validated
summary: Role MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated
operationId: actionMapfixValidated
tags:
- Mapfixes
@@ -554,6 +651,40 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/trigger-release:
post:
summary: Role MapfixUpload changes status from Uploaded -> Releasing
operationId: actionMapfixTriggerRelease
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/mapfixes/{MapfixID}/status/reset-releasing:
post:
summary: Role MapfixUpload manually resets releasing softlock and changes status from Releasing -> Uploaded
operationId: actionMapfixUploaded
tags:
- Mapfixes
parameters:
- $ref: '#/components/parameters/MapfixID'
responses:
"204":
description: Successful response
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/operations/{OperationID}:
get:
summary: Retrieve operation with ID
@@ -602,6 +733,11 @@ paths:
format: int32
minimum: 1
maximum: 5
description: >
Game ID:
* `1` - Bhop
* `2` - Surf
* `5` - FlyTrials
- name: Sort
in: query
schema:
@@ -609,6 +745,13 @@ paths:
format: int32
minimum: 0
maximum: 4
description: >
Sort order:
* `0` - Disabled
* `1` - DisplayNameAscending
* `2` - DisplayNameDescending
* `3` - DateAscending
* `4` - DateDescending
- name: Submitter
in: query
schema:
@@ -621,6 +764,12 @@ paths:
type: integer
format: int64
minimum: 0
- name: AssetVersion
in: query
schema:
type: integer
format: int64
minimum: 0
- name: UploadedAssetID
in: query
schema:
@@ -634,6 +783,25 @@ paths:
format: int32
minimum: 0
maximum: 10
description: >
// Phase: Creation
* `0` - UnderConstruction
* `1` - ChangesRequested
// Phase: Review
* `2` - Submitting
* `3` - Submitted
// Phase: Testing
* `4` - AcceptedUnvalidated // pending script review, can re-trigger validation
* `5` - Validating
* `6` - Validated
* `7` - Uploading
* `8` - Uploaded // uploaded to the group, but pending release
// Phase: Final SubmissionStatus
* `9` - Rejected
* `10` - Released
responses:
"200":
description: Successful response
@@ -833,10 +1001,10 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/bypass-submit:
/submissions/{SubmissionID}/status/trigger-submit-unchecked:
post:
summary: Role Reviewer changes status from ChangesRequested -> Submitted
operationId: actionSubmissionBypassSubmit
summary: Role Reviewer changes status from ChangesRequested -> Submitting
operationId: actionSubmissionTriggerSubmitUnchecked
tags:
- Submissions
parameters:
@@ -971,7 +1139,7 @@ paths:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/trigger-upload:
post:
summary: Role Admin changes status from Validated -> Uploading
summary: Role SubmissionUpload changes status from Validated -> Uploading
operationId: actionSubmissionTriggerUpload
tags:
- Submissions
@@ -988,7 +1156,7 @@ paths:
$ref: "#/components/schemas/Error"
/submissions/{SubmissionID}/status/reset-uploading:
post:
summary: Role Admin manually resets uploading softlock and changes status from Uploading -> Validated
summary: Role SubmissionUpload manually resets uploading softlock and changes status from Uploading -> Validated
operationId: actionSubmissionValidated
tags:
- Submissions
@@ -1005,7 +1173,7 @@ paths:
$ref: "#/components/schemas/Error"
/release-submissions:
post:
summary: Release a set of uploaded maps
summary: Release a set of uploaded maps. Role SubmissionRelease
operationId: releaseSubmissions
tags:
- Submissions
@@ -1022,6 +1190,10 @@ paths:
responses:
"201":
description: Successful response
content:
application/json:
schema:
$ref: "#/components/schemas/OperationID"
default:
description: General Error
content:
@@ -1292,6 +1464,222 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Error"
/thumbnails/assets:
post:
summary: Batch fetch asset thumbnails
operationId: batchAssetThumbnails
tags:
- Thumbnails
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- assetIds
properties:
assetIds:
type: array
items:
type: integer
format: uint64
maxItems: 100
description: Array of asset IDs (max 100)
size:
type: string
enum:
- "150x150"
- "420x420"
- "768x432"
default: "420x420"
description: Thumbnail size
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: object
properties:
thumbnails:
type: object
additionalProperties:
type: string
description: Map of asset ID to thumbnail URL
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/thumbnails/asset/{AssetID}:
get:
summary: Get single asset thumbnail
operationId: getAssetThumbnail
tags:
- Thumbnails
security: []
parameters:
- name: AssetID
in: path
required: true
schema:
type: integer
format: uint64
- name: size
in: query
schema:
type: string
enum:
- "150x150"
- "420x420"
- "768x432"
default: "420x420"
responses:
"302":
description: Redirect to thumbnail URL
headers:
Location:
description: URL to redirect to
schema:
type: string
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/thumbnails/users:
post:
summary: Batch fetch user avatar thumbnails
operationId: batchUserThumbnails
tags:
- Thumbnails
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- userIds
properties:
userIds:
type: array
items:
type: integer
format: uint64
maxItems: 100
description: Array of user IDs (max 100)
size:
type: string
enum:
- "150x150"
- "420x420"
- "768x432"
default: "150x150"
description: Thumbnail size
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: object
properties:
thumbnails:
type: object
additionalProperties:
type: string
description: Map of user ID to thumbnail URL
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/thumbnails/user/{UserID}:
get:
summary: Get single user avatar thumbnail
operationId: getUserThumbnail
tags:
- Thumbnails
security: []
parameters:
- name: UserID
in: path
required: true
schema:
type: integer
format: uint64
- name: size
in: query
schema:
type: string
enum:
- "150x150"
- "420x420"
- "768x432"
default: "150x150"
responses:
"302":
description: Redirect to thumbnail URL
headers:
Location:
description: URL to redirect to
schema:
type: string
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/usernames:
post:
summary: Batch fetch usernames
operationId: batchUsernames
tags:
- Users
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- userIds
properties:
userIds:
type: array
items:
type: integer
format: uint64
maxItems: 100
description: Array of user IDs (max 100)
responses:
"200":
description: Successful response
content:
application/json:
schema:
type: object
properties:
usernames:
type: object
additionalProperties:
type: string
description: Map of user ID to username
default:
description: General Error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
securitySchemes:
cookieAuth:
@@ -1469,6 +1857,13 @@ components:
- Creator
- GameID
- Date
- CreatedAt
- UpdatedAt
- Submitter
- Thumbnail
- AssetVersion
- LoadCount
- Modes
type: object
properties:
ID:
@@ -1489,6 +1884,27 @@ components:
type: integer
format: int64
minimum: 0
CreatedAt:
type: integer
format: int64
UpdatedAt:
type: integer
format: int64
Submitter:
type: integer
format: uint64
Thumbnail:
type: integer
format: uint64
AssetVersion:
type: integer
format: uint64
LoadCount:
type: integer
format: uint32
Modes:
type: integer
format: uint32
Mapfix:
required:
- ID
@@ -1500,6 +1916,8 @@ components:
- Submitter
- AssetID
- AssetVersion
# - ValidatedAssetID
# - ValidatedAssetVersion
- Completed
- TargetAssetID
- StatusID
@@ -1540,6 +1958,14 @@ components:
type: integer
format: int64
minimum: 0
ValidatedAssetID:
type: integer
format: int64
minimum: 0
ValidatedAssetVersion:
type: integer
format: int64
minimum: 0
Completed:
type: boolean
TargetAssetID:
@@ -1778,7 +2204,7 @@ components:
properties:
Name:
type: string
maxLength: 128
maxLength: 256
Source:
type: string
maxLength: 1048576
@@ -1877,6 +2303,47 @@ components:
type: integer
format: int32
minimum: 0
Stats:
description: Aggregate statistics for submissions and mapfixes
type: object
properties:
TotalSubmissions:
type: integer
format: int64
minimum: 0
description: Total number of submissions
TotalMapfixes:
type: integer
format: int64
minimum: 0
description: Total number of mapfixes
ReleasedSubmissions:
type: integer
format: int64
minimum: 0
description: Number of released submissions
ReleasedMapfixes:
type: integer
format: int64
minimum: 0
description: Number of released mapfixes
SubmittedSubmissions:
type: integer
format: int64
minimum: 0
description: Number of submissions under review
SubmittedMapfixes:
type: integer
format: int64
minimum: 0
description: Number of mapfixes under review
required:
- TotalSubmissions
- TotalMapfixes
- ReleasedSubmissions
- ReleasedMapfixes
- SubmittedSubmissions
- SubmittedMapfixes
Error:
description: Represents error object
type: object

View File

@@ -5,14 +5,14 @@ package api
import (
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/otelogen"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
)
var (
@@ -32,6 +32,7 @@ type otelConfig struct {
Tracer trace.Tracer
MeterProvider metric.MeterProvider
Meter metric.Meter
Attributes []attribute.KeyValue
}
func (cfg *otelConfig) initOTEL() {
@@ -215,6 +216,13 @@ func WithMeterProvider(provider metric.MeterProvider) Option {
})
}
// WithAttributes specifies default otel attributes.
func WithAttributes(attributes ...attribute.KeyValue) Option {
return otelOptionFunc(func(cfg *otelConfig) {
cfg.Attributes = attributes
})
}
// WithClient specifies http client to use.
func WithClient(client ht.Client) ClientOption {
return optionFunc[clientConfig](func(cfg *clientConfig) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,19 @@
// Code generated by ogen, DO NOT EDIT.
package api
// setDefaults set default value of fields.
func (s *BatchAssetThumbnailsReq) setDefaults() {
{
val := BatchAssetThumbnailsReqSize("420x420")
s.Size.SetTo(val)
}
}
// setDefaults set default value of fields.
func (s *BatchUserThumbnailsReq) setDefaults() {
{
val := BatchUserThumbnailsReqSize("150x150")
s.Size.SetTo(val)
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -6,58 +6,67 @@ package api
type OperationName = string
const (
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
ActionMapfixBypassSubmitOperation OperationName = "ActionMapfixBypassSubmit"
ActionMapfixRejectOperation OperationName = "ActionMapfixReject"
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
ActionMapfixResetSubmittingOperation OperationName = "ActionMapfixResetSubmitting"
ActionMapfixRetryValidateOperation OperationName = "ActionMapfixRetryValidate"
ActionMapfixRevokeOperation OperationName = "ActionMapfixRevoke"
ActionMapfixTriggerSubmitOperation OperationName = "ActionMapfixTriggerSubmit"
ActionMapfixTriggerUploadOperation OperationName = "ActionMapfixTriggerUpload"
ActionMapfixTriggerValidateOperation OperationName = "ActionMapfixTriggerValidate"
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
ActionSubmissionBypassSubmitOperation OperationName = "ActionSubmissionBypassSubmit"
ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject"
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
ActionSubmissionResetSubmittingOperation OperationName = "ActionSubmissionResetSubmitting"
ActionSubmissionRetryValidateOperation OperationName = "ActionSubmissionRetryValidate"
ActionSubmissionRevokeOperation OperationName = "ActionSubmissionRevoke"
ActionSubmissionTriggerSubmitOperation OperationName = "ActionSubmissionTriggerSubmit"
ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload"
ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
CreateMapfixOperation OperationName = "CreateMapfix"
CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment"
CreateScriptOperation OperationName = "CreateScript"
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
CreateSubmissionOperation OperationName = "CreateSubmission"
CreateSubmissionAdminOperation OperationName = "CreateSubmissionAdmin"
CreateSubmissionAuditCommentOperation OperationName = "CreateSubmissionAuditComment"
DeleteScriptOperation OperationName = "DeleteScript"
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
GetMapOperation OperationName = "GetMap"
GetMapfixOperation OperationName = "GetMapfix"
GetOperationOperation OperationName = "GetOperation"
GetScriptOperation OperationName = "GetScript"
GetScriptPolicyOperation OperationName = "GetScriptPolicy"
GetSubmissionOperation OperationName = "GetSubmission"
ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents"
ListMapfixesOperation OperationName = "ListMapfixes"
ListMapsOperation OperationName = "ListMaps"
ListScriptPolicyOperation OperationName = "ListScriptPolicy"
ListScriptsOperation OperationName = "ListScripts"
ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents"
ListSubmissionsOperation OperationName = "ListSubmissions"
ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions"
SessionRolesOperation OperationName = "SessionRoles"
SessionUserOperation OperationName = "SessionUser"
SessionValidateOperation OperationName = "SessionValidate"
SetMapfixCompletedOperation OperationName = "SetMapfixCompleted"
SetSubmissionCompletedOperation OperationName = "SetSubmissionCompleted"
UpdateMapfixModelOperation OperationName = "UpdateMapfixModel"
UpdateScriptOperation OperationName = "UpdateScript"
UpdateScriptPolicyOperation OperationName = "UpdateScriptPolicy"
UpdateSubmissionModelOperation OperationName = "UpdateSubmissionModel"
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
ActionMapfixRejectOperation OperationName = "ActionMapfixReject"
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
ActionMapfixResetSubmittingOperation OperationName = "ActionMapfixResetSubmitting"
ActionMapfixRetryValidateOperation OperationName = "ActionMapfixRetryValidate"
ActionMapfixRevokeOperation OperationName = "ActionMapfixRevoke"
ActionMapfixTriggerReleaseOperation OperationName = "ActionMapfixTriggerRelease"
ActionMapfixTriggerSubmitOperation OperationName = "ActionMapfixTriggerSubmit"
ActionMapfixTriggerSubmitUncheckedOperation OperationName = "ActionMapfixTriggerSubmitUnchecked"
ActionMapfixTriggerUploadOperation OperationName = "ActionMapfixTriggerUpload"
ActionMapfixTriggerValidateOperation OperationName = "ActionMapfixTriggerValidate"
ActionMapfixUploadedOperation OperationName = "ActionMapfixUploaded"
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject"
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
ActionSubmissionResetSubmittingOperation OperationName = "ActionSubmissionResetSubmitting"
ActionSubmissionRetryValidateOperation OperationName = "ActionSubmissionRetryValidate"
ActionSubmissionRevokeOperation OperationName = "ActionSubmissionRevoke"
ActionSubmissionTriggerSubmitOperation OperationName = "ActionSubmissionTriggerSubmit"
ActionSubmissionTriggerSubmitUncheckedOperation OperationName = "ActionSubmissionTriggerSubmitUnchecked"
ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload"
ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
BatchAssetThumbnailsOperation OperationName = "BatchAssetThumbnails"
BatchUserThumbnailsOperation OperationName = "BatchUserThumbnails"
BatchUsernamesOperation OperationName = "BatchUsernames"
CreateMapfixOperation OperationName = "CreateMapfix"
CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment"
CreateScriptOperation OperationName = "CreateScript"
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
CreateSubmissionOperation OperationName = "CreateSubmission"
CreateSubmissionAdminOperation OperationName = "CreateSubmissionAdmin"
CreateSubmissionAuditCommentOperation OperationName = "CreateSubmissionAuditComment"
DeleteScriptOperation OperationName = "DeleteScript"
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
DownloadMapAssetOperation OperationName = "DownloadMapAsset"
GetAssetThumbnailOperation OperationName = "GetAssetThumbnail"
GetMapOperation OperationName = "GetMap"
GetMapfixOperation OperationName = "GetMapfix"
GetOperationOperation OperationName = "GetOperation"
GetScriptOperation OperationName = "GetScript"
GetScriptPolicyOperation OperationName = "GetScriptPolicy"
GetStatsOperation OperationName = "GetStats"
GetSubmissionOperation OperationName = "GetSubmission"
GetUserThumbnailOperation OperationName = "GetUserThumbnail"
ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents"
ListMapfixesOperation OperationName = "ListMapfixes"
ListMapsOperation OperationName = "ListMaps"
ListScriptPolicyOperation OperationName = "ListScriptPolicy"
ListScriptsOperation OperationName = "ListScripts"
ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents"
ListSubmissionsOperation OperationName = "ListSubmissions"
ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions"
SessionRolesOperation OperationName = "SessionRoles"
SessionUserOperation OperationName = "SessionUser"
SessionValidateOperation OperationName = "SessionValidate"
SetMapfixCompletedOperation OperationName = "SetMapfixCompleted"
SetSubmissionCompletedOperation OperationName = "SetSubmissionCompleted"
UpdateMapfixModelOperation OperationName = "UpdateMapfixModel"
UpdateScriptOperation OperationName = "UpdateScript"
UpdateScriptPolicyOperation OperationName = "UpdateScriptPolicy"
UpdateSubmissionModelOperation OperationName = "UpdateSubmissionModel"
)

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
package api
import (
"bytes"
"fmt"
"io"
"mime"
@@ -10,13 +11,13 @@ import (
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/validate"
)
func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
req *MapfixTriggerCreate,
func (s *Server) decodeBatchAssetThumbnailsRequest(r *http.Request) (
req *BatchAssetThumbnailsReq,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -37,22 +38,266 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request BatchAssetThumbnailsReq
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, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, rawBody, close, nil
default:
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeBatchUserThumbnailsRequest(r *http.Request) (
req *BatchUserThumbnailsReq,
rawBody []byte,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request BatchUserThumbnailsReq
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, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, rawBody, close, nil
default:
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeBatchUsernamesRequest(r *http.Request) (
req *BatchUsernamesReq,
rawBody []byte,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request BatchUsernamesReq
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, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, rawBody, close, nil
default:
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
req *MapfixTriggerCreate,
rawBody []byte,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request MapfixTriggerCreate
@@ -70,7 +315,7 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -78,16 +323,17 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) (
req CreateMapfixAuditCommentReq,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -108,20 +354,21 @@ func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "text/plain":
reader := r.Body
request := CreateMapfixAuditCommentReq{Data: reader}
return request, close, nil
return request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateScriptRequest(r *http.Request) (
req *ScriptCreate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -142,22 +389,29 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request ScriptCreate
@@ -175,7 +429,7 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -183,16 +437,17 @@ func (s *Server) decodeCreateScriptRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
req *ScriptPolicyCreate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -213,22 +468,29 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request ScriptPolicyCreate
@@ -246,7 +508,7 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -254,16 +516,17 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
req *SubmissionTriggerCreate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -284,22 +547,29 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request SubmissionTriggerCreate
@@ -317,7 +587,7 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -325,16 +595,17 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
req *SubmissionTriggerCreate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -355,22 +626,29 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request SubmissionTriggerCreate
@@ -388,7 +666,7 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -396,16 +674,17 @@ func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) (
req CreateSubmissionAuditCommentReq,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -426,20 +705,21 @@ func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "text/plain":
reader := r.Body
request := CreateSubmissionAuditCommentReq{Data: reader}
return request, close, nil
return request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
req []ReleaseInfo,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -460,22 +740,29 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request []ReleaseInfo
@@ -501,7 +788,7 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if request == nil {
@@ -534,16 +821,17 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return request, close, nil
return request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeUpdateScriptRequest(r *http.Request) (
req *ScriptUpdate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -564,22 +852,29 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request ScriptUpdate
@@ -597,7 +892,7 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -605,16 +900,17 @@ func (s *Server) decodeUpdateScriptRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}
func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
req *ScriptPolicyUpdate,
rawBody []byte,
close func() error,
rerr error,
) {
@@ -635,22 +931,29 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
return req, rawBody, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
defer func() {
_ = r.Body.Close()
}()
if err != nil {
return req, close, err
return req, rawBody, close, err
}
// Reset the body to allow for downstream reading.
r.Body = io.NopCloser(bytes.NewBuffer(buf))
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
return req, rawBody, close, validate.ErrBodyRequired
}
rawBody = append(rawBody, buf...)
d := jx.DecodeBytes(buf)
var request ScriptPolicyUpdate
@@ -668,7 +971,7 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
Body: buf,
Err: err,
}
return req, close, err
return req, rawBody, close, err
}
if err := func() error {
if err := request.Validate(); err != nil {
@@ -676,10 +979,10 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
}
return nil
}(); err != nil {
return req, close, errors.Wrap(err, "validate")
return req, rawBody, close, errors.Wrap(err, "validate")
}
return &request, close, nil
return &request, rawBody, close, nil
default:
return req, close, validate.InvalidContentType(ct)
return req, rawBody, close, validate.InvalidContentType(ct)
}
}

View File

@@ -7,10 +7,51 @@ import (
"net/http"
"github.com/go-faster/jx"
ht "github.com/ogen-go/ogen/http"
)
func encodeBatchAssetThumbnailsRequest(
req *BatchAssetThumbnailsReq,
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 encodeBatchUserThumbnailsRequest(
req *BatchUserThumbnailsReq,
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 encodeBatchUsernamesRequest(
req *BatchUsernamesReq,
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 encodeCreateMapfixRequest(
req *MapfixTriggerCreate,
r *http.Request,

File diff suppressed because it is too large Load Diff

View File

@@ -3,14 +3,16 @@
package api
import (
"io"
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"github.com/ogen-go/ogen/conv"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/uri"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
)
func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
@@ -20,13 +22,6 @@ func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent,
return nil
}
func encodeActionMapfixBypassSubmitResponse(response *ActionMapfixBypassSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixRejectResponse(response *ActionMapfixRejectNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -62,6 +57,13 @@ func encodeActionMapfixRevokeResponse(response *ActionMapfixRevokeNoContent, w h
return nil
}
func encodeActionMapfixTriggerReleaseResponse(response *ActionMapfixTriggerReleaseNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixTriggerSubmitResponse(response *ActionMapfixTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -69,6 +71,13 @@ func encodeActionMapfixTriggerSubmitResponse(response *ActionMapfixTriggerSubmit
return nil
}
func encodeActionMapfixTriggerSubmitUncheckedResponse(response *ActionMapfixTriggerSubmitUncheckedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixTriggerUploadResponse(response *ActionMapfixTriggerUploadNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -83,6 +92,13 @@ func encodeActionMapfixTriggerValidateResponse(response *ActionMapfixTriggerVali
return nil
}
func encodeActionMapfixUploadedResponse(response *ActionMapfixUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixValidatedResponse(response *ActionMapfixValidatedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -97,13 +113,6 @@ func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNo
return nil
}
func encodeActionSubmissionBypassSubmitResponse(response *ActionSubmissionBypassSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionRejectResponse(response *ActionSubmissionRejectNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -146,6 +155,13 @@ func encodeActionSubmissionTriggerSubmitResponse(response *ActionSubmissionTrigg
return nil
}
func encodeActionSubmissionTriggerSubmitUncheckedResponse(response *ActionSubmissionTriggerSubmitUncheckedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionTriggerUploadResponse(response *ActionSubmissionTriggerUploadNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
@@ -167,6 +183,48 @@ func encodeActionSubmissionValidatedResponse(response *ActionSubmissionValidated
return nil
}
func encodeBatchAssetThumbnailsResponse(response *BatchAssetThumbnailsOK, 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 encodeBatchUserThumbnailsResponse(response *BatchUserThumbnailsOK, 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 encodeBatchUsernamesResponse(response *BatchUsernamesOK, 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 encodeCreateMapfixResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
@@ -265,6 +323,48 @@ func encodeDeleteScriptPolicyResponse(response *DeleteScriptPolicyNoContent, w h
return nil
}
func encodeDownloadMapAssetResponse(response DownloadMapAssetOK, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/octet-stream")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
writer := w
if closer, ok := response.Data.(io.Closer); ok {
defer closer.Close()
}
if _, err := io.Copy(writer, response); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeGetAssetThumbnailResponse(response *GetAssetThumbnailFound, w http.ResponseWriter, span trace.Span) error {
// Encoding response headers.
{
h := uri.NewHeaderEncoder(w.Header())
// Encode "Location" header.
{
cfg := uri.HeaderParameterEncodingConfig{
Name: "Location",
Explode: false,
}
if err := h.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := response.Location.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode Location header")
}
}
}
w.WriteHeader(302)
span.SetStatus(codes.Ok, http.StatusText(302))
return nil
}
func encodeGetMapResponse(response *Map, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
@@ -335,6 +435,20 @@ func encodeGetScriptPolicyResponse(response *ScriptPolicy, w http.ResponseWriter
return nil
}
func encodeGetStatsResponse(response *Stats, 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 encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
@@ -349,6 +463,32 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp
return nil
}
func encodeGetUserThumbnailResponse(response *GetUserThumbnailFound, w http.ResponseWriter, span trace.Span) error {
// Encoding response headers.
{
h := uri.NewHeaderEncoder(w.Header())
// Encode "Location" header.
{
cfg := uri.HeaderParameterEncodingConfig{
Name: "Location",
Explode: false,
}
if err := h.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := response.Location.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode Location header")
}
}
}
w.WriteHeader(302)
span.SetStatus(codes.Ok, http.StatusText(302))
return nil
}
func encodeListMapfixAuditEventsResponse(response []AuditEvent, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
@@ -467,10 +607,17 @@ func encodeListSubmissionsResponse(response *Submissions, w http.ResponseWriter,
return nil
}
func encodeReleaseSubmissionsResponse(response *ReleaseSubmissionsCreated, w http.ResponseWriter, span trace.Span) error {
func encodeReleaseSubmissionsResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
span.SetStatus(codes.Ok, http.StatusText(201))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,6 @@ import (
"strings"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/ogenerrors"
)
@@ -34,48 +33,51 @@ func findAuthorization(h http.Header, prefix string) (string, bool) {
}
var operationRolesCookieAuth = map[string][]string{
ActionMapfixAcceptedOperation: []string{},
ActionMapfixBypassSubmitOperation: []string{},
ActionMapfixRejectOperation: []string{},
ActionMapfixRequestChangesOperation: []string{},
ActionMapfixResetSubmittingOperation: []string{},
ActionMapfixRetryValidateOperation: []string{},
ActionMapfixRevokeOperation: []string{},
ActionMapfixTriggerSubmitOperation: []string{},
ActionMapfixTriggerUploadOperation: []string{},
ActionMapfixTriggerValidateOperation: []string{},
ActionMapfixValidatedOperation: []string{},
ActionSubmissionAcceptedOperation: []string{},
ActionSubmissionBypassSubmitOperation: []string{},
ActionSubmissionRejectOperation: []string{},
ActionSubmissionRequestChangesOperation: []string{},
ActionSubmissionResetSubmittingOperation: []string{},
ActionSubmissionRetryValidateOperation: []string{},
ActionSubmissionRevokeOperation: []string{},
ActionSubmissionTriggerSubmitOperation: []string{},
ActionSubmissionTriggerUploadOperation: []string{},
ActionSubmissionTriggerValidateOperation: []string{},
ActionSubmissionValidatedOperation: []string{},
CreateMapfixOperation: []string{},
CreateMapfixAuditCommentOperation: []string{},
CreateScriptOperation: []string{},
CreateScriptPolicyOperation: []string{},
CreateSubmissionOperation: []string{},
CreateSubmissionAdminOperation: []string{},
CreateSubmissionAuditCommentOperation: []string{},
DeleteScriptOperation: []string{},
DeleteScriptPolicyOperation: []string{},
GetOperationOperation: []string{},
ReleaseSubmissionsOperation: []string{},
SessionRolesOperation: []string{},
SessionUserOperation: []string{},
SessionValidateOperation: []string{},
SetMapfixCompletedOperation: []string{},
SetSubmissionCompletedOperation: []string{},
UpdateMapfixModelOperation: []string{},
UpdateScriptOperation: []string{},
UpdateScriptPolicyOperation: []string{},
UpdateSubmissionModelOperation: []string{},
ActionMapfixAcceptedOperation: []string{},
ActionMapfixRejectOperation: []string{},
ActionMapfixRequestChangesOperation: []string{},
ActionMapfixResetSubmittingOperation: []string{},
ActionMapfixRetryValidateOperation: []string{},
ActionMapfixRevokeOperation: []string{},
ActionMapfixTriggerReleaseOperation: []string{},
ActionMapfixTriggerSubmitOperation: []string{},
ActionMapfixTriggerSubmitUncheckedOperation: []string{},
ActionMapfixTriggerUploadOperation: []string{},
ActionMapfixTriggerValidateOperation: []string{},
ActionMapfixUploadedOperation: []string{},
ActionMapfixValidatedOperation: []string{},
ActionSubmissionAcceptedOperation: []string{},
ActionSubmissionRejectOperation: []string{},
ActionSubmissionRequestChangesOperation: []string{},
ActionSubmissionResetSubmittingOperation: []string{},
ActionSubmissionRetryValidateOperation: []string{},
ActionSubmissionRevokeOperation: []string{},
ActionSubmissionTriggerSubmitOperation: []string{},
ActionSubmissionTriggerSubmitUncheckedOperation: []string{},
ActionSubmissionTriggerUploadOperation: []string{},
ActionSubmissionTriggerValidateOperation: []string{},
ActionSubmissionValidatedOperation: []string{},
CreateMapfixOperation: []string{},
CreateMapfixAuditCommentOperation: []string{},
CreateScriptOperation: []string{},
CreateScriptPolicyOperation: []string{},
CreateSubmissionOperation: []string{},
CreateSubmissionAdminOperation: []string{},
CreateSubmissionAuditCommentOperation: []string{},
DeleteScriptOperation: []string{},
DeleteScriptPolicyOperation: []string{},
DownloadMapAssetOperation: []string{},
GetOperationOperation: []string{},
ReleaseSubmissionsOperation: []string{},
SessionRolesOperation: []string{},
SessionUserOperation: []string{},
SessionValidateOperation: []string{},
SetMapfixCompletedOperation: []string{},
SetSubmissionCompletedOperation: []string{},
UpdateMapfixModelOperation: []string{},
UpdateScriptOperation: []string{},
UpdateScriptPolicyOperation: []string{},
UpdateSubmissionModelOperation: []string{},
}
func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {

View File

@@ -14,12 +14,6 @@ type Handler interface {
//
// POST /mapfixes/{MapfixID}/status/reset-validating
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
// ActionMapfixBypassSubmit implements actionMapfixBypassSubmit operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/bypass-submit
ActionMapfixBypassSubmit(ctx context.Context, params ActionMapfixBypassSubmitParams) error
// ActionMapfixReject implements actionMapfixReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
@@ -51,15 +45,27 @@ type Handler interface {
//
// POST /mapfixes/{MapfixID}/status/revoke
ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error
// ActionMapfixTriggerRelease implements actionMapfixTriggerRelease operation.
//
// Role MapfixUpload changes status from Uploaded -> Releasing.
//
// POST /mapfixes/{MapfixID}/status/trigger-release
ActionMapfixTriggerRelease(ctx context.Context, params ActionMapfixTriggerReleaseParams) error
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit
ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error
// ActionMapfixTriggerSubmitUnchecked implements actionMapfixTriggerSubmitUnchecked operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitting.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit-unchecked
ActionMapfixTriggerSubmitUnchecked(ctx context.Context, params ActionMapfixTriggerSubmitUncheckedParams) error
// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
// Role MapfixUpload changes status from Validated -> Uploading.
//
// POST /mapfixes/{MapfixID}/status/trigger-upload
ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error
@@ -69,9 +75,15 @@ type Handler interface {
//
// POST /mapfixes/{MapfixID}/status/trigger-validate
ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// Role MapfixUpload manually resets releasing softlock and changes status from Releasing -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/reset-releasing
ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error
// ActionMapfixValidated implements actionMapfixValidated operation.
//
// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
// Role MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated.
//
// POST /mapfixes/{MapfixID}/status/reset-uploading
ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
@@ -81,12 +93,6 @@ type Handler interface {
//
// POST /submissions/{SubmissionID}/status/reset-validating
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
// ActionSubmissionBypassSubmit implements actionSubmissionBypassSubmit operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitted.
//
// POST /submissions/{SubmissionID}/status/bypass-submit
ActionSubmissionBypassSubmit(ctx context.Context, params ActionSubmissionBypassSubmitParams) error
// ActionSubmissionReject implements actionSubmissionReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
@@ -124,9 +130,15 @@ type Handler interface {
//
// POST /submissions/{SubmissionID}/status/trigger-submit
ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error
// ActionSubmissionTriggerSubmitUnchecked implements actionSubmissionTriggerSubmitUnchecked operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitting.
//
// POST /submissions/{SubmissionID}/status/trigger-submit-unchecked
ActionSubmissionTriggerSubmitUnchecked(ctx context.Context, params ActionSubmissionTriggerSubmitUncheckedParams) error
// ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
// Role SubmissionUpload changes status from Validated -> Uploading.
//
// POST /submissions/{SubmissionID}/status/trigger-upload
ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error
@@ -138,10 +150,29 @@ type Handler interface {
ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
// Role SubmissionUpload manually resets uploading softlock and changes status from Uploading ->
// Validated.
//
// POST /submissions/{SubmissionID}/status/reset-uploading
ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error
// BatchAssetThumbnails implements batchAssetThumbnails operation.
//
// Batch fetch asset thumbnails.
//
// POST /thumbnails/assets
BatchAssetThumbnails(ctx context.Context, req *BatchAssetThumbnailsReq) (*BatchAssetThumbnailsOK, error)
// BatchUserThumbnails implements batchUserThumbnails operation.
//
// Batch fetch user avatar thumbnails.
//
// POST /thumbnails/users
BatchUserThumbnails(ctx context.Context, req *BatchUserThumbnailsReq) (*BatchUserThumbnailsOK, error)
// BatchUsernames implements batchUsernames operation.
//
// Batch fetch usernames.
//
// POST /usernames
BatchUsernames(ctx context.Context, req *BatchUsernamesReq) (*BatchUsernamesOK, error)
// CreateMapfix implements createMapfix operation.
//
// Trigger the validator to create a mapfix.
@@ -196,6 +227,18 @@ type Handler interface {
//
// DELETE /script-policy/{ScriptPolicyID}
DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error
// DownloadMapAsset implements downloadMapAsset operation.
//
// Download the map asset.
//
// GET /maps/{MapID}/download
DownloadMapAsset(ctx context.Context, params DownloadMapAssetParams) (DownloadMapAssetOK, error)
// GetAssetThumbnail implements getAssetThumbnail operation.
//
// Get single asset thumbnail.
//
// GET /thumbnails/asset/{AssetID}
GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (*GetAssetThumbnailFound, error)
// GetMap implements getMap operation.
//
// Retrieve map with ID.
@@ -226,12 +269,24 @@ type Handler interface {
//
// GET /script-policy/{ScriptPolicyID}
GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (*ScriptPolicy, error)
// GetStats implements getStats operation.
//
// Get aggregate statistics.
//
// GET /stats
GetStats(ctx context.Context) (*Stats, error)
// GetSubmission implements getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
// GetUserThumbnail implements getUserThumbnail operation.
//
// Get single user avatar thumbnail.
//
// GET /thumbnails/user/{UserID}
GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (*GetUserThumbnailFound, error)
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
@@ -276,10 +331,10 @@ type Handler interface {
ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error)
// ReleaseSubmissions implements releaseSubmissions operation.
//
// Release a set of uploaded maps.
// Release a set of uploaded maps. Role SubmissionRelease.
//
// POST /release-submissions
ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) error
ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) (*OperationID, error)
// SessionRoles implements sessionRoles operation.
//
// Get list of roles for the current session.

View File

@@ -22,15 +22,6 @@ func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params Act
return ht.ErrNotImplemented
}
// ActionMapfixBypassSubmit implements actionMapfixBypassSubmit operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/bypass-submit
func (UnimplementedHandler) ActionMapfixBypassSubmit(ctx context.Context, params ActionMapfixBypassSubmitParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixReject implements actionMapfixReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
@@ -77,6 +68,15 @@ func (UnimplementedHandler) ActionMapfixRevoke(ctx context.Context, params Actio
return ht.ErrNotImplemented
}
// ActionMapfixTriggerRelease implements actionMapfixTriggerRelease operation.
//
// Role MapfixUpload changes status from Uploaded -> Releasing.
//
// POST /mapfixes/{MapfixID}/status/trigger-release
func (UnimplementedHandler) ActionMapfixTriggerRelease(ctx context.Context, params ActionMapfixTriggerReleaseParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
@@ -86,9 +86,18 @@ func (UnimplementedHandler) ActionMapfixTriggerSubmit(ctx context.Context, param
return ht.ErrNotImplemented
}
// ActionMapfixTriggerSubmitUnchecked implements actionMapfixTriggerSubmitUnchecked operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitting.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit-unchecked
func (UnimplementedHandler) ActionMapfixTriggerSubmitUnchecked(ctx context.Context, params ActionMapfixTriggerSubmitUncheckedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
// Role MapfixUpload changes status from Validated -> Uploading.
//
// POST /mapfixes/{MapfixID}/status/trigger-upload
func (UnimplementedHandler) ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error {
@@ -104,9 +113,18 @@ func (UnimplementedHandler) ActionMapfixTriggerValidate(ctx context.Context, par
return ht.ErrNotImplemented
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// Role MapfixUpload manually resets releasing softlock and changes status from Releasing -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/reset-releasing
func (UnimplementedHandler) ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixValidated implements actionMapfixValidated operation.
//
// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
// Role MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated.
//
// POST /mapfixes/{MapfixID}/status/reset-uploading
func (UnimplementedHandler) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
@@ -122,15 +140,6 @@ func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params
return ht.ErrNotImplemented
}
// ActionSubmissionBypassSubmit implements actionSubmissionBypassSubmit operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitted.
//
// POST /submissions/{SubmissionID}/status/bypass-submit
func (UnimplementedHandler) ActionSubmissionBypassSubmit(ctx context.Context, params ActionSubmissionBypassSubmitParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionReject implements actionSubmissionReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
@@ -186,9 +195,18 @@ func (UnimplementedHandler) ActionSubmissionTriggerSubmit(ctx context.Context, p
return ht.ErrNotImplemented
}
// ActionSubmissionTriggerSubmitUnchecked implements actionSubmissionTriggerSubmitUnchecked operation.
//
// Role Reviewer changes status from ChangesRequested -> Submitting.
//
// POST /submissions/{SubmissionID}/status/trigger-submit-unchecked
func (UnimplementedHandler) ActionSubmissionTriggerSubmitUnchecked(ctx context.Context, params ActionSubmissionTriggerSubmitUncheckedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation.
//
// Role Admin changes status from Validated -> Uploading.
// Role SubmissionUpload changes status from Validated -> Uploading.
//
// POST /submissions/{SubmissionID}/status/trigger-upload
func (UnimplementedHandler) ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error {
@@ -206,13 +224,41 @@ func (UnimplementedHandler) ActionSubmissionTriggerValidate(ctx context.Context,
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// Role Admin manually resets uploading softlock and changes status from Uploading -> Validated.
// Role SubmissionUpload manually resets uploading softlock and changes status from Uploading ->
// Validated.
//
// POST /submissions/{SubmissionID}/status/reset-uploading
func (UnimplementedHandler) ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error {
return ht.ErrNotImplemented
}
// BatchAssetThumbnails implements batchAssetThumbnails operation.
//
// Batch fetch asset thumbnails.
//
// POST /thumbnails/assets
func (UnimplementedHandler) BatchAssetThumbnails(ctx context.Context, req *BatchAssetThumbnailsReq) (r *BatchAssetThumbnailsOK, _ error) {
return r, ht.ErrNotImplemented
}
// BatchUserThumbnails implements batchUserThumbnails operation.
//
// Batch fetch user avatar thumbnails.
//
// POST /thumbnails/users
func (UnimplementedHandler) BatchUserThumbnails(ctx context.Context, req *BatchUserThumbnailsReq) (r *BatchUserThumbnailsOK, _ error) {
return r, ht.ErrNotImplemented
}
// BatchUsernames implements batchUsernames operation.
//
// Batch fetch usernames.
//
// POST /usernames
func (UnimplementedHandler) BatchUsernames(ctx context.Context, req *BatchUsernamesReq) (r *BatchUsernamesOK, _ error) {
return r, ht.ErrNotImplemented
}
// CreateMapfix implements createMapfix operation.
//
// Trigger the validator to create a mapfix.
@@ -294,6 +340,24 @@ func (UnimplementedHandler) DeleteScriptPolicy(ctx context.Context, params Delet
return ht.ErrNotImplemented
}
// DownloadMapAsset implements downloadMapAsset operation.
//
// Download the map asset.
//
// GET /maps/{MapID}/download
func (UnimplementedHandler) DownloadMapAsset(ctx context.Context, params DownloadMapAssetParams) (r DownloadMapAssetOK, _ error) {
return r, ht.ErrNotImplemented
}
// GetAssetThumbnail implements getAssetThumbnail operation.
//
// Get single asset thumbnail.
//
// GET /thumbnails/asset/{AssetID}
func (UnimplementedHandler) GetAssetThumbnail(ctx context.Context, params GetAssetThumbnailParams) (r *GetAssetThumbnailFound, _ error) {
return r, ht.ErrNotImplemented
}
// GetMap implements getMap operation.
//
// Retrieve map with ID.
@@ -339,6 +403,15 @@ func (UnimplementedHandler) GetScriptPolicy(ctx context.Context, params GetScrip
return r, ht.ErrNotImplemented
}
// GetStats implements getStats operation.
//
// Get aggregate statistics.
//
// GET /stats
func (UnimplementedHandler) GetStats(ctx context.Context) (r *Stats, _ error) {
return r, ht.ErrNotImplemented
}
// GetSubmission implements getSubmission operation.
//
// Retrieve map with ID.
@@ -348,6 +421,15 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss
return r, ht.ErrNotImplemented
}
// GetUserThumbnail implements getUserThumbnail operation.
//
// Get single user avatar thumbnail.
//
// GET /thumbnails/user/{UserID}
func (UnimplementedHandler) GetUserThumbnail(ctx context.Context, params GetUserThumbnailParams) (r *GetUserThumbnailFound, _ error) {
return r, ht.ErrNotImplemented
}
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
@@ -413,11 +495,11 @@ func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubm
// ReleaseSubmissions implements releaseSubmissions operation.
//
// Release a set of uploaded maps.
// Release a set of uploaded maps. Role SubmissionRelease.
//
// POST /release-submissions
func (UnimplementedHandler) ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) error {
return ht.ErrNotImplemented
func (UnimplementedHandler) ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) (r *OperationID, _ error) {
return r, ht.ErrNotImplemented
}
// SessionRoles implements sessionRoles operation.

File diff suppressed because it is too large Load Diff

57
pkg/cmds/api.go Normal file
View File

@@ -0,0 +1,57 @@
package cmds
import (
"git.itzana.me/strafesnet/maps-service/pkg/public_api"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func NewApiCommand() *cli.Command {
return &cli.Command{
Name: "api",
Usage: "Run api service",
Action: runAPI,
Flags: []cli.Flag{
&cli.IntFlag{
Name: "port",
Usage: "Listen port",
EnvVars: []string{"PORT"},
Value: 8080,
},
&cli.StringFlag{
Name: "dev-rpc-host",
Usage: "Host of dev rpc",
EnvVars: []string{"DEV_RPC_HOST"},
Value: "dev-service:8081",
},
&cli.StringFlag{
Name: "maps-rpc-host",
Usage: "Host of maps rpc",
EnvVars: []string{"MAPS_RPC_HOST"},
Value: "maptest-api:8081",
},
},
}
}
func runAPI(ctx *cli.Context) error {
// Dev service client
devConn, err := grpc.Dial(ctx.String("dev-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return err
}
// Data service client
mapsConn, err := grpc.Dial(ctx.String("maps-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return err
}
return api.NewRouter(
api.WithContext(ctx),
api.WithPort(ctx.Int("port")),
api.WithDevClient(devConn),
api.WithMapsClient(mapsConn),
)
}

View File

@@ -2,17 +2,23 @@ package cmds
import (
"fmt"
"net"
"net/http"
"git.itzana.me/strafesnet/go-grpc/auth"
"git.itzana.me/strafesnet/go-grpc/maps"
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"git.itzana.me/strafesnet/go-grpc/users"
"git.itzana.me/strafesnet/go-grpc/validator"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/controller"
"git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/roblox"
"git.itzana.me/strafesnet/maps-service/pkg/service"
"git.itzana.me/strafesnet/maps-service/pkg/service_internal"
"git.itzana.me/strafesnet/maps-service/pkg/validator_controller"
"git.itzana.me/strafesnet/maps-service/pkg/web_api"
"github.com/nats-io/nats.go"
"github.com/redis/go-redis/v9"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
@@ -91,6 +97,30 @@ func NewServeCommand() *cli.Command {
EnvVars: []string{"NATS_HOST"},
Value: "nats:4222",
},
&cli.StringFlag{
Name: "rbx-api-key",
Usage: "API Key for downloading asset locations",
EnvVars: []string{"RBX_API_KEY"},
Required: true,
},
&cli.StringFlag{
Name: "redis-host",
Usage: "Host of Redis cache",
EnvVars: []string{"REDIS_HOST"},
Value: "localhost:6379",
},
&cli.StringFlag{
Name: "redis-password",
Usage: "Password for Redis",
EnvVars: []string{"REDIS_PASSWORD"},
Value: "",
},
&cli.IntFlag{
Name: "redis-db",
Usage: "Redis database number",
EnvVars: []string{"REDIS_DB"},
Value: 0,
},
},
}
}
@@ -118,51 +148,92 @@ func serve(ctx *cli.Context) error {
log.WithError(err).Fatal("failed to add stream")
}
// Initialize Redis client
redisClient := redis.NewClient(&redis.Options{
Addr: ctx.String("redis-host"),
Password: ctx.String("redis-password"),
DB: ctx.Int("redis-db"),
})
// Test Redis connection
if err := redisClient.Ping(ctx.Context).Err(); err != nil {
log.WithError(err).Warn("failed to connect to Redis - thumbnails will not be cached")
}
// Initialize Roblox client
robloxClient := &roblox.Client{
HttpClient: http.DefaultClient,
ApiKey: ctx.String("rbx-api-key"),
}
// connect to main game database
conn, err := grpc.Dial(ctx.String("data-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
svc := &service.Service{
DB: db,
Nats: js,
Maps: maps.NewMapsServiceClient(conn),
Users: users.NewUsersServiceClient(conn),
}
svc_inner := service.NewService(
db,
js,
maps.NewMapsServiceClient(conn),
users.NewUsersServiceClient(conn),
robloxClient,
redisClient,
)
svc_external := web_api.NewService(
&svc_inner,
roblox.Client{
HttpClient: http.DefaultClient,
ApiKey: ctx.String("rbx-api-key"),
},
)
conn, err = grpc.Dial(ctx.String("auth-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
sec := service.SecurityHandler{
sec := web_api.SecurityHandler{
Client: auth.NewAuthServiceClient(conn),
}
srv, err := api.NewServer(svc, sec, api.WithPathPrefix("/v1"))
srv_external, err := api.NewServer(&svc_external, sec, api.WithPathPrefix("/v1"))
if err != nil {
log.WithError(err).Fatal("failed to initialize api server")
}
svc2 := &service_internal.Service{
DB: db,
Nats: js,
}
grpcServer := grpc.NewServer()
srv2, err := internal.NewServer(svc2, internal.WithPathPrefix("/v1"))
maps_controller := controller.NewMapsController(&svc_inner)
maps_extended.RegisterMapsServiceServer(grpcServer,&maps_controller)
mapfix_controller := validator_controller.NewMapfixesController(&svc_inner)
operation_controller := validator_controller.NewOperationsController(&svc_inner)
script_controller := validator_controller.NewScriptsController(&svc_inner)
script_policy_controller := validator_controller.NewScriptPolicyController(&svc_inner)
submission_controller := validator_controller.NewSubmissionsController(&svc_inner)
validator.RegisterValidatorMapfixServiceServer(grpcServer,&mapfix_controller)
validator.RegisterValidatorOperationServiceServer(grpcServer,&operation_controller)
validator.RegisterValidatorScriptServiceServer(grpcServer,&script_controller)
validator.RegisterValidatorScriptPolicyServiceServer(grpcServer,&script_policy_controller)
validator.RegisterValidatorSubmissionServiceServer(grpcServer,&submission_controller)
port := ctx.Int("port-internal")
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
log.WithError(err).Fatal("failed to initialize api server")
log.WithField("error", err).Fatalln("failed to net.Listen")
}
// Channel to collect errors
errChan := make(chan error, 2)
// First server
go func(errChan chan error) {
errChan <- http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port-internal")), srv2)
errChan <- grpcServer.Serve(lis)
}(errChan)
// Second server
go func(errChan chan error) {
errChan <- http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port")), srv)
errChan <- http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port")), srv_external)
}(errChan)
// Wait for the first error or completion of both tasks

197
pkg/controller/maps.go Normal file
View File

@@ -0,0 +1,197 @@
package controller
import (
"context"
"errors"
"time"
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
var (
PageError = errors.New("Pagination required")
)
type Maps struct {
*maps_extended.UnimplementedMapsServiceServer
inner *service.Service
}
func NewMapsController(
inner *service.Service,
) Maps {
return Maps{
inner: inner,
}
}
func (svc *Maps) Create(ctx context.Context, request *maps_extended.MapCreate) (*maps_extended.MapId, error) {
id, err := svc.inner.CreateMap(ctx, model.Map{
ID: request.ID,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: request.GameID,
Submitter: request.Submitter,
Date: time.Unix(request.Date, 0),
Thumbnail: request.Thumbnail,
AssetVersion: request.AssetVersion,
LoadCount: 0,
Modes: request.Modes,
})
if err != nil {
return nil, err
}
return &maps_extended.MapId{
ID: id,
}, nil
}
func (svc *Maps) Delete(ctx context.Context, request *maps_extended.MapId) (*maps_extended.NullResponse, error) {
err := svc.inner.DeleteMap(ctx, request.ID)
if err != nil {
return nil, err
}
return &maps_extended.NullResponse{}, nil
}
func (svc *Maps) Get(ctx context.Context, request *maps_extended.MapId) (*maps_extended.MapResponse, error) {
item, err := svc.inner.GetMap(ctx, request.ID)
if err != nil {
return nil, err
}
return &maps_extended.MapResponse{
ID: item.ID,
DisplayName: item.DisplayName,
Creator: item.Creator,
GameID: uint32(item.GameID),
Date: item.Date.Unix(),
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
Submitter: uint64(item.Submitter),
Thumbnail: uint64(item.Thumbnail),
AssetVersion: uint64(item.AssetVersion),
LoadCount: item.LoadCount,
Modes: item.Modes,
}, nil
}
func (svc *Maps) GetList(ctx context.Context, request *maps_extended.MapIdList) (*maps_extended.MapList, error) {
items, err := svc.inner.GetMapList(ctx, request.ID)
if err != nil {
return nil, err
}
resp := maps_extended.MapList{}
resp.Maps = make([]*maps_extended.MapResponse, len(items))
for i, item := range items {
resp.Maps[i] = &maps_extended.MapResponse{
ID: item.ID,
DisplayName: item.DisplayName,
Creator: item.Creator,
GameID: uint32(item.GameID),
Date: item.Date.Unix(),
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
Submitter: uint64(item.Submitter),
Thumbnail: uint64(item.Thumbnail),
AssetVersion: uint64(item.AssetVersion),
LoadCount: item.LoadCount,
Modes: item.Modes,
}
}
return &resp, nil
}
func (svc *Maps) List(ctx context.Context, request *maps_extended.ListRequest) (*maps_extended.MapList, error) {
if request.Page == nil {
return nil, PageError
}
filter := service.NewMapFilter()
if request.Filter != nil {
if request.Filter.DisplayName != nil {
filter.SetDisplayName(*request.Filter.DisplayName)
}
if request.Filter.Creator != nil {
filter.SetCreator(*request.Filter.Creator)
}
if request.Filter.GameID != nil {
filter.SetGameID(*request.Filter.GameID)
}
if request.Filter.Submitter != nil {
filter.SetSubmitter(*request.Filter.Submitter)
}
}
items, err := svc.inner.ListMaps(ctx, filter, model.Page{
Number: int32(request.Page.Number),
Size: int32(request.Page.Size),
})
if err != nil {
return nil, err
}
resp := maps_extended.MapList{}
resp.Maps = make([]*maps_extended.MapResponse, len(items))
for i, item := range items {
resp.Maps[i] = &maps_extended.MapResponse{
ID: item.ID,
DisplayName: item.DisplayName,
Creator: item.Creator,
GameID: uint32(item.GameID),
Date: item.Date.Unix(),
CreatedAt: item.CreatedAt.Unix(),
UpdatedAt: item.UpdatedAt.Unix(),
Submitter: uint64(item.Submitter),
Thumbnail: uint64(item.Thumbnail),
AssetVersion: uint64(item.AssetVersion),
LoadCount: item.LoadCount,
Modes: item.Modes,
}
}
return &resp, nil
}
func (svc *Maps) Update(ctx context.Context, request *maps_extended.MapUpdate) (*maps_extended.NullResponse, error) {
update := service.NewMapUpdate()
if request.DisplayName != nil {
update.SetDisplayName(*request.DisplayName)
}
if request.Creator != nil {
update.SetCreator(*request.Creator)
}
if request.GameID != nil {
update.SetGameID(*request.GameID)
}
if request.Date != nil {
update.SetDate(*request.Date)
}
if request.Submitter != nil {
update.SetSubmitter(*request.Submitter)
}
if request.Thumbnail != nil {
update.SetThumbnail(*request.Thumbnail)
}
if request.AssetVersion != nil {
update.SetAssetVersion(*request.AssetVersion)
}
if request.Modes != nil {
update.SetModes(*request.Modes)
}
err := svc.inner.UpdateMap(ctx, request.ID, update)
if err != nil {
return nil, err
}
return &maps_extended.NullResponse{}, nil
}
func (svc *Maps) IncrementLoadCount(ctx context.Context, request *maps_extended.MapId) (*maps_extended.NullResponse, error) {
err := svc.inner.IncrementMapLoadCount(ctx, request.ID)
if err != nil {
return nil, err
}
return &maps_extended.NullResponse{}, nil
}

View File

@@ -25,6 +25,7 @@ const (
type Datastore interface {
AuditEvents() AuditEvents
Maps() Maps
Mapfixes() Mapfixes
Operations() Operations
Submissions() Submissions
@@ -40,6 +41,16 @@ type AuditEvents interface {
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.AuditEvent, error)
}
type Maps interface {
Get(ctx context.Context, id int64) (model.Map, error)
GetList(ctx context.Context, id []int64) ([]model.Map, error)
Create(ctx context.Context, smap model.Map) (model.Map, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Map, error)
IncrementLoadCount(ctx context.Context, id int64) error
}
type Mapfixes interface {
Get(ctx context.Context, id int64) (model.Mapfix, error)
GetList(ctx context.Context, id []int64) ([]model.Mapfix, error)

View File

@@ -56,7 +56,7 @@ func (env *AuditEvents) Delete(ctx context.Context, id int64) error {
func (env *AuditEvents) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.AuditEvent, error) {
var events []model.AuditEvent
if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil {
if err := env.db.Where(filters.Map()).Order("id ASC").Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil {
return nil, err
}

View File

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

View File

@@ -13,6 +13,10 @@ func (g Gormstore) AuditEvents() datastore.AuditEvents {
return &AuditEvents{db: g.db}
}
func (g Gormstore) Maps() datastore.Maps {
return &Maps{db: g.db}
}
func (g Gormstore) Mapfixes() datastore.Mapfixes {
return &Mapfixes{db: g.db}
}

View File

@@ -55,11 +55,16 @@ func (env *Mapfixes) Update(ctx context.Context, id int64, values datastore.Opti
// the update can only occur if the status matches one of the provided values.
func (env *Mapfixes) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.MapfixStatus, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Mapfix{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
result := env.db.Model(&model.Mapfix{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map())
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
return result.Error
}
if result.RowsAffected == 0 {
return datastore.ErroNoRowsAffected
}
return nil

View File

@@ -0,0 +1,84 @@
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 Maps struct {
db *gorm.DB
}
func (env *Maps) Get(ctx context.Context, id int64) (model.Map, error) {
var mdl model.Map
if err := env.db.First(&mdl, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
return mdl, err
}
return mdl, nil
}
func (env *Maps) GetList(ctx context.Context, id []int64) ([]model.Map, error) {
var mapList []model.Map
if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
return mapList, err
}
return mapList, nil
}
func (env *Maps) Create(ctx context.Context, smap model.Map) (model.Map, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Maps) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Map{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Maps) IncrementLoadCount(ctx context.Context, id int64) error {
if err := env.db.Model(&model.Map{}).Where("id = ?", id).UpdateColumn("load_count", gorm.Expr("load_count + ?", 1)).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Maps) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Map{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Maps) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.Map, error) {
var events []model.Map
if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil {
return nil, err
}
return events, nil
}

View File

@@ -55,11 +55,16 @@ 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.
func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, 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 == gorm.ErrRecordNotFound {
result := env.db.Model(&model.Submission{}).Where("id = ?", id).Where("status_id IN ?", statuses).Updates(values.Map())
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
return result.Error
}
if result.RowsAffected == 0 {
return datastore.ErroNoRowsAffected
}
return nil

View File

@@ -1,283 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"net/http"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/metric"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/otelogen"
)
var (
// Allocate option closure once.
clientSpanKind = trace.WithSpanKind(trace.SpanKindClient)
// Allocate option closure once.
serverSpanKind = trace.WithSpanKind(trace.SpanKindServer)
)
type (
optionFunc[C any] func(*C)
otelOptionFunc func(*otelConfig)
)
type otelConfig struct {
TracerProvider trace.TracerProvider
Tracer trace.Tracer
MeterProvider metric.MeterProvider
Meter metric.Meter
}
func (cfg *otelConfig) initOTEL() {
if cfg.TracerProvider == nil {
cfg.TracerProvider = otel.GetTracerProvider()
}
if cfg.MeterProvider == nil {
cfg.MeterProvider = otel.GetMeterProvider()
}
cfg.Tracer = cfg.TracerProvider.Tracer(otelogen.Name,
trace.WithInstrumentationVersion(otelogen.SemVersion()),
)
cfg.Meter = cfg.MeterProvider.Meter(otelogen.Name,
metric.WithInstrumentationVersion(otelogen.SemVersion()),
)
}
// ErrorHandler is error handler.
type ErrorHandler = ogenerrors.ErrorHandler
type serverConfig struct {
otelConfig
NotFound http.HandlerFunc
MethodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)
ErrorHandler ErrorHandler
Prefix string
Middleware Middleware
MaxMultipartMemory int64
}
// ServerOption is server config option.
type ServerOption interface {
applyServer(*serverConfig)
}
var _ ServerOption = (optionFunc[serverConfig])(nil)
func (o optionFunc[C]) applyServer(c *C) {
o(c)
}
var _ ServerOption = (otelOptionFunc)(nil)
func (o otelOptionFunc) applyServer(c *serverConfig) {
o(&c.otelConfig)
}
func newServerConfig(opts ...ServerOption) serverConfig {
cfg := serverConfig{
NotFound: http.NotFound,
MethodNotAllowed: func(w http.ResponseWriter, r *http.Request, allowed string) {
status := http.StatusMethodNotAllowed
if r.Method == "OPTIONS" {
w.Header().Set("Access-Control-Allow-Methods", allowed)
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
status = http.StatusNoContent
} else {
w.Header().Set("Allow", allowed)
}
w.WriteHeader(status)
},
ErrorHandler: ogenerrors.DefaultErrorHandler,
Middleware: nil,
MaxMultipartMemory: 32 << 20, // 32 MB
}
for _, opt := range opts {
opt.applyServer(&cfg)
}
cfg.initOTEL()
return cfg
}
type baseServer struct {
cfg serverConfig
requests metric.Int64Counter
errors metric.Int64Counter
duration metric.Float64Histogram
}
func (s baseServer) notFound(w http.ResponseWriter, r *http.Request) {
s.cfg.NotFound(w, r)
}
func (s baseServer) notAllowed(w http.ResponseWriter, r *http.Request, allowed string) {
s.cfg.MethodNotAllowed(w, r, allowed)
}
func (cfg serverConfig) baseServer() (s baseServer, err error) {
s = baseServer{cfg: cfg}
if s.requests, err = otelogen.ServerRequestCountCounter(s.cfg.Meter); err != nil {
return s, err
}
if s.errors, err = otelogen.ServerErrorsCountCounter(s.cfg.Meter); err != nil {
return s, err
}
if s.duration, err = otelogen.ServerDurationHistogram(s.cfg.Meter); err != nil {
return s, err
}
return s, nil
}
type clientConfig struct {
otelConfig
Client ht.Client
}
// ClientOption is client config option.
type ClientOption interface {
applyClient(*clientConfig)
}
var _ ClientOption = (optionFunc[clientConfig])(nil)
func (o optionFunc[C]) applyClient(c *C) {
o(c)
}
var _ ClientOption = (otelOptionFunc)(nil)
func (o otelOptionFunc) applyClient(c *clientConfig) {
o(&c.otelConfig)
}
func newClientConfig(opts ...ClientOption) clientConfig {
cfg := clientConfig{
Client: http.DefaultClient,
}
for _, opt := range opts {
opt.applyClient(&cfg)
}
cfg.initOTEL()
return cfg
}
type baseClient struct {
cfg clientConfig
requests metric.Int64Counter
errors metric.Int64Counter
duration metric.Float64Histogram
}
func (cfg clientConfig) baseClient() (c baseClient, err error) {
c = baseClient{cfg: cfg}
if c.requests, err = otelogen.ClientRequestCountCounter(c.cfg.Meter); err != nil {
return c, err
}
if c.errors, err = otelogen.ClientErrorsCountCounter(c.cfg.Meter); err != nil {
return c, err
}
if c.duration, err = otelogen.ClientDurationHistogram(c.cfg.Meter); err != nil {
return c, err
}
return c, nil
}
// Option is config option.
type Option interface {
ServerOption
ClientOption
}
// WithTracerProvider specifies a tracer provider to use for creating a tracer.
//
// If none is specified, the global provider is used.
func WithTracerProvider(provider trace.TracerProvider) Option {
return otelOptionFunc(func(cfg *otelConfig) {
if provider != nil {
cfg.TracerProvider = provider
}
})
}
// WithMeterProvider specifies a meter provider to use for creating a meter.
//
// If none is specified, the otel.GetMeterProvider() is used.
func WithMeterProvider(provider metric.MeterProvider) Option {
return otelOptionFunc(func(cfg *otelConfig) {
if provider != nil {
cfg.MeterProvider = provider
}
})
}
// WithClient specifies http client to use.
func WithClient(client ht.Client) ClientOption {
return optionFunc[clientConfig](func(cfg *clientConfig) {
if client != nil {
cfg.Client = client
}
})
}
// WithNotFound specifies Not Found handler to use.
func WithNotFound(notFound http.HandlerFunc) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if notFound != nil {
cfg.NotFound = notFound
}
})
}
// WithMethodNotAllowed specifies Method Not Allowed handler to use.
func WithMethodNotAllowed(methodNotAllowed func(w http.ResponseWriter, r *http.Request, allowed string)) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if methodNotAllowed != nil {
cfg.MethodNotAllowed = methodNotAllowed
}
})
}
// WithErrorHandler specifies error handler to use.
func WithErrorHandler(h ErrorHandler) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if h != nil {
cfg.ErrorHandler = h
}
})
}
// WithPathPrefix specifies server path prefix.
func WithPathPrefix(prefix string) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
cfg.Prefix = prefix
})
}
// WithMiddleware specifies middlewares to use.
func WithMiddleware(m ...Middleware) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
switch len(m) {
case 0:
cfg.Middleware = nil
case 1:
cfg.Middleware = m[0]
default:
cfg.Middleware = middleware.ChainMiddlewares(m...)
}
})
}
// WithMaxMultipartMemory specifies limit of memory for storing file parts.
// File parts which can't be stored in memory will be stored on disk in temporary files.
func WithMaxMultipartMemory(max int64) ServerOption {
return optionFunc[serverConfig](func(cfg *serverConfig) {
if max > 0 {
cfg.MaxMultipartMemory = max
}
})
}

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

@@ -1,42 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
"go.opentelemetry.io/otel/attribute"
)
// Labeler is used to allow adding custom attributes to the server request metrics.
type Labeler struct {
attrs []attribute.KeyValue
}
// Add attributes to the Labeler.
func (l *Labeler) Add(attrs ...attribute.KeyValue) {
l.attrs = append(l.attrs, attrs...)
}
// AttributeSet returns the attributes added to the Labeler as an attribute.Set.
func (l *Labeler) AttributeSet() attribute.Set {
return attribute.NewSet(l.attrs...)
}
type labelerContextKey struct{}
// LabelerFromContext retrieves the Labeler from the provided context, if present.
//
// If no Labeler was found in the provided context a new, empty Labeler is returned and the second
// return value is false. In this case it is safe to use the Labeler but any attributes added to
// it will not be used.
func LabelerFromContext(ctx context.Context) (*Labeler, bool) {
if l, ok := ctx.Value(labelerContextKey{}).(*Labeler); ok {
return l, true
}
return &Labeler{}, false
}
func contextWithLabeler(ctx context.Context, l *Labeler) context.Context {
return context.WithValue(ctx, labelerContextKey{}, l)
}

View File

@@ -1,10 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"github.com/ogen-go/ogen/middleware"
)
// Middleware is middleware type.
type Middleware = middleware.Middleware

View File

@@ -1,29 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
// OperationName is the ogen operation name
type OperationName = string
const (
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
ActionMapfixSubmittedOperation OperationName = "ActionMapfixSubmitted"
ActionMapfixUploadedOperation OperationName = "ActionMapfixUploaded"
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
ActionOperationFailedOperation OperationName = "ActionOperationFailed"
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
ActionSubmissionSubmittedOperation OperationName = "ActionSubmissionSubmitted"
ActionSubmissionUploadedOperation OperationName = "ActionSubmissionUploaded"
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
CreateMapfixOperation OperationName = "CreateMapfix"
CreateScriptOperation OperationName = "CreateScript"
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
CreateSubmissionOperation OperationName = "CreateSubmission"
GetScriptOperation OperationName = "GetScript"
ListScriptPolicyOperation OperationName = "ListScriptPolicy"
ListScriptsOperation OperationName = "ListScripts"
UpdateMapfixValidatedModelOperation OperationName = "UpdateMapfixValidatedModel"
UpdateSubmissionValidatedModelOperation OperationName = "UpdateSubmissionValidatedModel"
)

File diff suppressed because it is too large Load Diff

View File

@@ -1,299 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"io"
"mime"
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/validate"
)
func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
req *MapfixCreate,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request MapfixCreate
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) 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 = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request 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 = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request 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
}
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) decodeCreateSubmissionRequest(r *http.Request) (
req *SubmissionCreate,
close func() error,
rerr error,
) {
var closers []func() error
close = func() error {
var merr error
// Close in reverse order, to match defer behavior.
for i := len(closers) - 1; i >= 0; i-- {
c := closers[i]
merr = errors.Join(merr, c())
}
return merr
}
defer func() {
if rerr != nil {
rerr = errors.Join(rerr, close())
}
}()
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
if err != nil {
return req, close, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
if r.ContentLength == 0 {
return req, close, validate.ErrBodyRequired
}
buf, err := io.ReadAll(r.Body)
if err != nil {
return req, close, err
}
if len(buf) == 0 {
return req, close, validate.ErrBodyRequired
}
d := jx.DecodeBytes(buf)
var request SubmissionCreate
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)
}
}

View File

@@ -1,68 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"bytes"
"net/http"
"github.com/go-faster/jx"
ht "github.com/ogen-go/ogen/http"
)
func encodeCreateMapfixRequest(
req *MapfixCreate,
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 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(
req *SubmissionCreate,
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
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,238 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"net/http"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/trace"
ht "github.com/ogen-go/ogen/http"
)
func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixSubmittedResponse(response *ActionMapfixSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixUploadedResponse(response *ActionMapfixUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixValidatedResponse(response *ActionMapfixValidatedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionOperationFailedResponse(response *ActionOperationFailedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionSubmittedResponse(response *ActionSubmissionSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionUploadedResponse(response *ActionSubmissionUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionValidatedResponse(response *ActionSubmissionValidatedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeCreateMapfixResponse(response *MapfixID, 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 encodeCreateScriptResponse(response *ScriptID, 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 *ScriptPolicyID, 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 encodeCreateSubmissionResponse(response *SubmissionID, 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 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 encodeListScriptPolicyResponse(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)
e.ArrStart()
for _, elem := range response {
elem.Encode(e)
}
e.ArrEnd()
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeListScriptsResponse(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)
e.ArrStart()
for _, elem := range response {
elem.Encode(e)
}
e.ArrEnd()
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeUpdateMapfixValidatedModelResponse(response *UpdateMapfixValidatedModelNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateSubmissionValidatedModelResponse(response *UpdateSubmissionValidatedModelNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeErrorResponse(response *ErrorStatusCode, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
code := response.StatusCode
if code == 0 {
// Set default status code.
code = http.StatusOK
}
w.WriteHeader(code)
if st := http.StatusText(code); code >= http.StatusBadRequest {
span.SetStatus(codes.Error, st)
} else {
span.SetStatus(codes.Ok, st)
}
e := new(jx.Encoder)
response.Response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
if code >= http.StatusInternalServerError {
return errors.Wrapf(ht.ErrInternalServerErrorResponse, "code: %d, message: %s", code, http.StatusText(code))
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,710 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"fmt"
)
func (s *ErrorStatusCode) Error() string {
return fmt.Sprintf("code %d: %+v", s.StatusCode, s.Response)
}
// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
type ActionMapfixAcceptedNoContent struct{}
// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
type ActionMapfixRequestChangesNoContent struct{}
// ActionMapfixSubmittedNoContent is response for ActionMapfixSubmitted operation.
type ActionMapfixSubmittedNoContent struct{}
// ActionMapfixUploadedNoContent is response for ActionMapfixUploaded operation.
type ActionMapfixUploadedNoContent struct{}
// ActionMapfixValidatedNoContent is response for ActionMapfixValidated operation.
type ActionMapfixValidatedNoContent struct{}
// ActionOperationFailedNoContent is response for ActionOperationFailed operation.
type ActionOperationFailedNoContent struct{}
// ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
type ActionSubmissionAcceptedNoContent struct{}
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation.
type ActionSubmissionRequestChangesNoContent struct{}
// ActionSubmissionSubmittedNoContent is response for ActionSubmissionSubmitted operation.
type ActionSubmissionSubmittedNoContent struct{}
// ActionSubmissionUploadedNoContent is response for ActionSubmissionUploaded operation.
type ActionSubmissionUploadedNoContent struct{}
// ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation.
type ActionSubmissionValidatedNoContent struct{}
// Represents error object.
// Ref: #/components/schemas/Error
type Error struct {
Code int64 `json:"code"`
Message string `json:"message"`
}
// GetCode returns the value of Code.
func (s *Error) GetCode() int64 {
return s.Code
}
// GetMessage returns the value of Message.
func (s *Error) GetMessage() string {
return s.Message
}
// SetCode sets the value of Code.
func (s *Error) SetCode(val int64) {
s.Code = val
}
// SetMessage sets the value of Message.
func (s *Error) SetMessage(val string) {
s.Message = val
}
// ErrorStatusCode wraps Error with StatusCode.
type ErrorStatusCode struct {
StatusCode int
Response Error
}
// GetStatusCode returns the value of StatusCode.
func (s *ErrorStatusCode) GetStatusCode() int {
return s.StatusCode
}
// GetResponse returns the value of Response.
func (s *ErrorStatusCode) GetResponse() Error {
return s.Response
}
// SetStatusCode sets the value of StatusCode.
func (s *ErrorStatusCode) SetStatusCode(val int) {
s.StatusCode = val
}
// SetResponse sets the value of Response.
func (s *ErrorStatusCode) SetResponse(val Error) {
s.Response = val
}
// Ref: #/components/schemas/MapfixCreate
type MapfixCreate struct {
OperationID int32 `json:"OperationID"`
AssetOwner int64 `json:"AssetOwner"`
DisplayName string `json:"DisplayName"`
Creator string `json:"Creator"`
GameID int32 `json:"GameID"`
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
TargetAssetID int64 `json:"TargetAssetID"`
Description string `json:"Description"`
}
// GetOperationID returns the value of OperationID.
func (s *MapfixCreate) GetOperationID() int32 {
return s.OperationID
}
// GetAssetOwner returns the value of AssetOwner.
func (s *MapfixCreate) GetAssetOwner() int64 {
return s.AssetOwner
}
// GetDisplayName returns the value of DisplayName.
func (s *MapfixCreate) GetDisplayName() string {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *MapfixCreate) GetCreator() string {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *MapfixCreate) GetGameID() int32 {
return s.GameID
}
// GetAssetID returns the value of AssetID.
func (s *MapfixCreate) GetAssetID() int64 {
return s.AssetID
}
// GetAssetVersion returns the value of AssetVersion.
func (s *MapfixCreate) GetAssetVersion() int64 {
return s.AssetVersion
}
// GetTargetAssetID returns the value of TargetAssetID.
func (s *MapfixCreate) GetTargetAssetID() int64 {
return s.TargetAssetID
}
// GetDescription returns the value of Description.
func (s *MapfixCreate) GetDescription() string {
return s.Description
}
// SetOperationID sets the value of OperationID.
func (s *MapfixCreate) SetOperationID(val int32) {
s.OperationID = val
}
// SetAssetOwner sets the value of AssetOwner.
func (s *MapfixCreate) SetAssetOwner(val int64) {
s.AssetOwner = val
}
// SetDisplayName sets the value of DisplayName.
func (s *MapfixCreate) SetDisplayName(val string) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *MapfixCreate) SetCreator(val string) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *MapfixCreate) SetGameID(val int32) {
s.GameID = val
}
// SetAssetID sets the value of AssetID.
func (s *MapfixCreate) SetAssetID(val int64) {
s.AssetID = val
}
// SetAssetVersion sets the value of AssetVersion.
func (s *MapfixCreate) SetAssetVersion(val int64) {
s.AssetVersion = val
}
// SetTargetAssetID sets the value of TargetAssetID.
func (s *MapfixCreate) SetTargetAssetID(val int64) {
s.TargetAssetID = val
}
// SetDescription sets the value of Description.
func (s *MapfixCreate) SetDescription(val string) {
s.Description = val
}
// Ref: #/components/schemas/MapfixID
type MapfixID struct {
MapfixID int64 `json:"MapfixID"`
}
// GetMapfixID returns the value of MapfixID.
func (s *MapfixID) GetMapfixID() int64 {
return s.MapfixID
}
// SetMapfixID sets the value of MapfixID.
func (s *MapfixID) SetMapfixID(val int64) {
s.MapfixID = val
}
// NewOptInt32 returns new OptInt32 with value set to v.
func NewOptInt32(v int32) OptInt32 {
return OptInt32{
Value: v,
Set: true,
}
}
// OptInt32 is optional int32.
type OptInt32 struct {
Value int32
Set bool
}
// IsSet returns true if OptInt32 was set.
func (o OptInt32) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptInt32) Reset() {
var v int32
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptInt32) SetTo(v int32) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptInt32) Get() (v int32, ok bool) {
if !o.Set {
return v, false
}
return o.Value, true
}
// Or returns value if set, or given parameter if does not.
func (o OptInt32) Or(d int32) int32 {
if v, ok := o.Get(); ok {
return v
}
return d
}
// NewOptInt64 returns new OptInt64 with value set to v.
func NewOptInt64(v int64) OptInt64 {
return OptInt64{
Value: v,
Set: true,
}
}
// OptInt64 is optional int64.
type OptInt64 struct {
Value int64
Set bool
}
// IsSet returns true if OptInt64 was set.
func (o OptInt64) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptInt64) Reset() {
var v int64
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptInt64) SetTo(v int64) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptInt64) Get() (v int64, ok bool) {
if !o.Set {
return v, false
}
return o.Value, true
}
// Or returns value if set, or given parameter if does not.
func (o OptInt64) Or(d int64) int64 {
if v, ok := o.Get(); ok {
return v
}
return d
}
// NewOptString returns new OptString with value set to v.
func NewOptString(v string) OptString {
return OptString{
Value: v,
Set: true,
}
}
// OptString is optional string.
type OptString struct {
Value string
Set bool
}
// IsSet returns true if OptString was set.
func (o OptString) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptString) Reset() {
var v string
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptString) SetTo(v string) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptString) Get() (v string, 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 OptString) Or(d string) string {
if v, ok := o.Get(); ok {
return v
}
return d
}
// Ref: #/components/schemas/Script
type Script struct {
ID int64 `json:"ID"`
Name string `json:"Name"`
Hash string `json:"Hash"`
Source string `json:"Source"`
ResourceType int32 `json:"ResourceType"`
ResourceID int64 `json:"ResourceID"`
}
// GetID returns the value of ID.
func (s *Script) GetID() int64 {
return s.ID
}
// GetName returns the value of Name.
func (s *Script) GetName() string {
return s.Name
}
// 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
}
// GetResourceType returns the value of ResourceType.
func (s *Script) GetResourceType() int32 {
return s.ResourceType
}
// GetResourceID returns the value of ResourceID.
func (s *Script) GetResourceID() int64 {
return s.ResourceID
}
// SetID sets the value of ID.
func (s *Script) SetID(val int64) {
s.ID = val
}
// SetName sets the value of Name.
func (s *Script) SetName(val string) {
s.Name = 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
}
// SetResourceType sets the value of ResourceType.
func (s *Script) SetResourceType(val int32) {
s.ResourceType = val
}
// SetResourceID sets the value of ResourceID.
func (s *Script) SetResourceID(val int64) {
s.ResourceID = val
}
// Ref: #/components/schemas/ScriptCreate
type ScriptCreate struct {
Name string `json:"Name"`
Source string `json:"Source"`
ResourceType int32 `json:"ResourceType"`
ResourceID OptInt64 `json:"ResourceID"`
}
// GetName returns the value of Name.
func (s *ScriptCreate) GetName() string {
return s.Name
}
// GetSource returns the value of Source.
func (s *ScriptCreate) GetSource() string {
return s.Source
}
// GetResourceType returns the value of ResourceType.
func (s *ScriptCreate) GetResourceType() int32 {
return s.ResourceType
}
// GetResourceID returns the value of ResourceID.
func (s *ScriptCreate) GetResourceID() OptInt64 {
return s.ResourceID
}
// SetName sets the value of Name.
func (s *ScriptCreate) SetName(val string) {
s.Name = val
}
// SetSource sets the value of Source.
func (s *ScriptCreate) SetSource(val string) {
s.Source = val
}
// SetResourceType sets the value of ResourceType.
func (s *ScriptCreate) SetResourceType(val int32) {
s.ResourceType = val
}
// SetResourceID sets the value of ResourceID.
func (s *ScriptCreate) SetResourceID(val OptInt64) {
s.ResourceID = val
}
// Ref: #/components/schemas/ScriptID
type ScriptID struct {
ScriptID int64 `json:"ScriptID"`
}
// GetScriptID returns the value of ScriptID.
func (s *ScriptID) GetScriptID() int64 {
return s.ScriptID
}
// SetScriptID sets the value of ScriptID.
func (s *ScriptID) SetScriptID(val int64) {
s.ScriptID = 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/ScriptPolicyID
type ScriptPolicyID struct {
ScriptPolicyID int64 `json:"ScriptPolicyID"`
}
// GetScriptPolicyID returns the value of ScriptPolicyID.
func (s *ScriptPolicyID) GetScriptPolicyID() int64 {
return s.ScriptPolicyID
}
// SetScriptPolicyID sets the value of ScriptPolicyID.
func (s *ScriptPolicyID) SetScriptPolicyID(val int64) {
s.ScriptPolicyID = val
}
// Ref: #/components/schemas/SubmissionCreate
type SubmissionCreate struct {
OperationID int32 `json:"OperationID"`
AssetOwner int64 `json:"AssetOwner"`
DisplayName string `json:"DisplayName"`
Creator string `json:"Creator"`
GameID int32 `json:"GameID"`
AssetID int64 `json:"AssetID"`
AssetVersion int64 `json:"AssetVersion"`
Status uint32 `json:"Status"`
Roles uint32 `json:"Roles"`
}
// GetOperationID returns the value of OperationID.
func (s *SubmissionCreate) GetOperationID() int32 {
return s.OperationID
}
// GetAssetOwner returns the value of AssetOwner.
func (s *SubmissionCreate) GetAssetOwner() int64 {
return s.AssetOwner
}
// GetDisplayName returns the value of DisplayName.
func (s *SubmissionCreate) GetDisplayName() string {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *SubmissionCreate) GetCreator() string {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *SubmissionCreate) GetGameID() int32 {
return s.GameID
}
// GetAssetID returns the value of AssetID.
func (s *SubmissionCreate) GetAssetID() int64 {
return s.AssetID
}
// GetAssetVersion returns the value of AssetVersion.
func (s *SubmissionCreate) GetAssetVersion() int64 {
return s.AssetVersion
}
// GetStatus returns the value of Status.
func (s *SubmissionCreate) GetStatus() uint32 {
return s.Status
}
// GetRoles returns the value of Roles.
func (s *SubmissionCreate) GetRoles() uint32 {
return s.Roles
}
// SetOperationID sets the value of OperationID.
func (s *SubmissionCreate) SetOperationID(val int32) {
s.OperationID = val
}
// SetAssetOwner sets the value of AssetOwner.
func (s *SubmissionCreate) SetAssetOwner(val int64) {
s.AssetOwner = val
}
// SetDisplayName sets the value of DisplayName.
func (s *SubmissionCreate) SetDisplayName(val string) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *SubmissionCreate) SetCreator(val string) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *SubmissionCreate) SetGameID(val int32) {
s.GameID = val
}
// SetAssetID sets the value of AssetID.
func (s *SubmissionCreate) SetAssetID(val int64) {
s.AssetID = val
}
// SetAssetVersion sets the value of AssetVersion.
func (s *SubmissionCreate) SetAssetVersion(val int64) {
s.AssetVersion = val
}
// SetStatus sets the value of Status.
func (s *SubmissionCreate) SetStatus(val uint32) {
s.Status = val
}
// SetRoles sets the value of Roles.
func (s *SubmissionCreate) SetRoles(val uint32) {
s.Roles = val
}
// Ref: #/components/schemas/SubmissionID
type SubmissionID struct {
SubmissionID int64 `json:"SubmissionID"`
}
// GetSubmissionID returns the value of SubmissionID.
func (s *SubmissionID) GetSubmissionID() int64 {
return s.SubmissionID
}
// SetSubmissionID sets the value of SubmissionID.
func (s *SubmissionID) SetSubmissionID(val int64) {
s.SubmissionID = val
}
// UpdateMapfixValidatedModelNoContent is response for UpdateMapfixValidatedModel operation.
type UpdateMapfixValidatedModelNoContent struct{}
// UpdateSubmissionValidatedModelNoContent is response for UpdateSubmissionValidatedModel operation.
type UpdateSubmissionValidatedModelNoContent struct{}

View File

@@ -1,154 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
)
// Handler handles operations described by OpenAPI v3 specification.
type Handler interface {
// ActionMapfixAccepted implements actionMapfixAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/validator-failed
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/validator-uploaded
ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error
// ActionMapfixValidated implements actionMapfixValidated operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Validated.
//
// POST /mapfixes/{MapfixID}/status/validator-validated
ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
// ActionOperationFailed implements actionOperationFailed operation.
//
// (Internal endpoint) Fail an operation and write a StatusMessage.
//
// POST /operations/{OperationID}/status/operation-failed
ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /submissions/{SubmissionID}/status/validator-failed
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /submissions/{SubmissionID}/status/validator-uploaded
ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Validated.
//
// POST /submissions/{SubmissionID}/status/validator-validated
ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error
// CreateMapfix implements createMapfix operation.
//
// Create a mapfix.
//
// POST /mapfixes
CreateMapfix(ctx context.Context, req *MapfixCreate) (*MapfixID, error)
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
CreateScript(ctx context.Context, req *ScriptCreate) (*ScriptID, error)
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
CreateScriptPolicy(ctx context.Context, req *ScriptPolicyCreate) (*ScriptPolicyID, error)
// CreateSubmission implements createSubmission operation.
//
// Create a new submission.
//
// POST /submissions
CreateSubmission(ctx context.Context, req *SubmissionCreate) (*SubmissionID, error)
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
GetScript(ctx context.Context, params GetScriptParams) (*Script, error)
// ListScriptPolicy implements listScriptPolicy operation.
//
// Get list of script policies.
//
// GET /script-policy
ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) ([]ScriptPolicy, error)
// ListScripts implements listScripts operation.
//
// Get list of scripts.
//
// GET /scripts
ListScripts(ctx context.Context, params ListScriptsParams) ([]Script, error)
// UpdateMapfixValidatedModel implements updateMapfixValidatedModel operation.
//
// Update validated model.
//
// POST /mapfixes/{MapfixID}/validated-model
UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error
// UpdateSubmissionValidatedModel implements updateSubmissionValidatedModel operation.
//
// Update validated model.
//
// POST /submissions/{SubmissionID}/validated-model
UpdateSubmissionValidatedModel(ctx context.Context, params UpdateSubmissionValidatedModelParams) error
// NewError creates *ErrorStatusCode from error returned by handler.
//
// Used for common default response.
NewError(ctx context.Context, err error) *ErrorStatusCode
}
// Server implements http server based on OpenAPI v3 specification and
// calls Handler to handle requests.
type Server struct {
h Handler
baseServer
}
// NewServer creates new Server.
func NewServer(h Handler, opts ...ServerOption) (*Server, error) {
s, err := newServerConfig(opts...).baseServer()
if err != nil {
return nil, err
}
return &Server{
h: h,
baseServer: s,
}, nil
}

View File

@@ -1,202 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
ht "github.com/ogen-go/ogen/http"
)
// UnimplementedHandler is no-op Handler which returns http.ErrNotImplemented.
type UnimplementedHandler struct{}
var _ Handler = UnimplementedHandler{}
// ActionMapfixAccepted implements actionMapfixAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/validator-failed
func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (UnimplementedHandler) ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/validator-uploaded
func (UnimplementedHandler) ActionMapfixUploaded(ctx context.Context, params ActionMapfixUploadedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixValidated implements actionMapfixValidated operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Validated.
//
// POST /mapfixes/{MapfixID}/status/validator-validated
func (UnimplementedHandler) ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error {
return ht.ErrNotImplemented
}
// ActionOperationFailed implements actionOperationFailed operation.
//
// (Internal endpoint) Fail an operation and write a StatusMessage.
//
// POST /operations/{OperationID}/status/operation-failed
func (UnimplementedHandler) ActionOperationFailed(ctx context.Context, params ActionOperationFailedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /submissions/{SubmissionID}/status/validator-failed
func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (UnimplementedHandler) ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /submissions/{SubmissionID}/status/validator-uploaded
func (UnimplementedHandler) ActionSubmissionUploaded(ctx context.Context, params ActionSubmissionUploadedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Validated.
//
// POST /submissions/{SubmissionID}/status/validator-validated
func (UnimplementedHandler) ActionSubmissionValidated(ctx context.Context, params ActionSubmissionValidatedParams) error {
return ht.ErrNotImplemented
}
// CreateMapfix implements createMapfix operation.
//
// Create a mapfix.
//
// POST /mapfixes
func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixCreate) (r *MapfixID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (UnimplementedHandler) CreateScript(ctx context.Context, req *ScriptCreate) (r *ScriptID, _ 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 *ScriptPolicyID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateSubmission implements createSubmission operation.
//
// Create a new submission.
//
// POST /submissions
func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *SubmissionCreate) (r *SubmissionID, _ error) {
return r, 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
}
// ListScriptPolicy implements listScriptPolicy operation.
//
// Get list of script policies.
//
// GET /script-policy
func (UnimplementedHandler) ListScriptPolicy(ctx context.Context, params ListScriptPolicyParams) (r []ScriptPolicy, _ error) {
return r, ht.ErrNotImplemented
}
// ListScripts implements listScripts operation.
//
// Get list of scripts.
//
// GET /scripts
func (UnimplementedHandler) ListScripts(ctx context.Context, params ListScriptsParams) (r []Script, _ error) {
return r, ht.ErrNotImplemented
}
// UpdateMapfixValidatedModel implements updateMapfixValidatedModel operation.
//
// Update validated model.
//
// POST /mapfixes/{MapfixID}/validated-model
func (UnimplementedHandler) UpdateMapfixValidatedModel(ctx context.Context, params UpdateMapfixValidatedModelParams) error {
return ht.ErrNotImplemented
}
// UpdateSubmissionValidatedModel implements updateSubmissionValidatedModel operation.
//
// Update validated model.
//
// POST /submissions/{SubmissionID}/validated-model
func (UnimplementedHandler) UpdateSubmissionValidatedModel(ctx context.Context, params UpdateSubmissionValidatedModelParams) error {
return ht.ErrNotImplemented
}
// NewError creates *ErrorStatusCode from error returned by handler.
//
// Used for common default response.
func (UnimplementedHandler) NewError(ctx context.Context, err error) (r *ErrorStatusCode) {
r = new(ErrorStatusCode)
return r
}

View File

@@ -1,940 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/validate"
)
func (s *Error) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Code)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "code",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ErrorStatusCode) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := s.Response.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Response",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *MapfixCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.OperationID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "OperationID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetOwner)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetOwner",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.GameID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "GameID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetVersion)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetVersion",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.TargetAssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "TargetAssetID",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 256,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Description)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Description",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *MapfixID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.MapfixID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "MapfixID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *Script) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ID",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Name)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Name",
Error: 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(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 err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ResourceType)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceType",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ResourceID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
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: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Name)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Name",
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 err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ResourceType)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceType",
Error: err,
})
}
if err := func() error {
if value, ok := s.ResourceID.Get(); ok {
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(value)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
return err
}
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ResourceID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ScriptID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicy) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ID",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 16,
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 err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ToScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ToScriptID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Policy)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Policy",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicyCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.FromScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "FromScriptID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ToScriptID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ToScriptID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Policy)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Policy",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *ScriptPolicyID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.ScriptPolicyID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "ScriptPolicyID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *SubmissionCreate) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.OperationID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "OperationID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetOwner)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetOwner",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.DisplayName)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "DisplayName",
Error: err,
})
}
if err := func() error {
if err := (validate.String{
MinLength: 0,
MinLengthSet: false,
MaxLength: 128,
MaxLengthSet: true,
Email: false,
Hostname: false,
Regex: nil,
}).Validate(string(s.Creator)); err != nil {
return errors.Wrap(err, "string")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Creator",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.GameID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "GameID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetID",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.AssetVersion)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "AssetVersion",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: true,
Max: 9,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Status)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Status",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
func (s *SubmissionID) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 0,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.SubmissionID)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "SubmissionID",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}

View File

@@ -2,9 +2,12 @@ package model
import (
"encoding/json"
"math"
"time"
)
const ValidatorUserID uint64 = uint64(math.MaxInt64)
type AuditEventType int32
// User clicked "Submit", "Accept" etc
@@ -48,6 +51,19 @@ type AuditEventDataError struct {
Error string `json:"error"`
}
type Check struct {
Name string `json:"name"`
Summary string `json:"summary"`
Passed bool `json:"passed"`
}
// Validator map checks details
const AuditEventTypeCheckList AuditEventType = 7
type AuditEventDataCheckList struct {
CheckList []Check `json:"check_list"`
}
type AuditEvent struct {
ID int64 `gorm:"primaryKey"`
CreatedAt time.Time

18
pkg/model/map.go Normal file
View File

@@ -0,0 +1,18 @@
package model
import "time"
type Map struct {
ID int64
DisplayName string
Creator string
GameID uint32
Date time.Time // Release date
CreatedAt time.Time
UpdatedAt time.Time
Submitter uint64 // UserID of submitter
Thumbnail uint64 // AssetID of thumbnail
AssetVersion uint64 // Version number for LoadAssetVersion
LoadCount uint32 // How many times the map has been loaded
Modes uint32 // Number of modes (always at least one)
}

View File

@@ -18,10 +18,12 @@ const (
MapfixStatusValidating MapfixStatus = 5
MapfixStatusValidated MapfixStatus = 6
MapfixStatusUploading MapfixStatus = 7
MapfixStatusUploaded MapfixStatus = 8 // uploaded to the group, but pending release
MapfixStatusReleasing MapfixStatus = 11
// Phase: Final MapfixStatus
MapfixStatusUploaded MapfixStatus = 8 // uploaded to the group, but pending release
MapfixStatusRejected MapfixStatus = 9
MapfixStatusReleased MapfixStatus = 10
)
type Mapfix struct {

View File

@@ -27,11 +27,13 @@ type CreateMapfixRequest struct {
type CheckSubmissionRequest struct{
SubmissionID int64
ModelID uint64
SkipChecks bool
}
type CheckMapfixRequest struct{
MapfixID int64
ModelID uint64
MapfixID int64
ModelID uint64
SkipChecks bool
}
type ValidateSubmissionRequest struct {
@@ -63,3 +65,29 @@ type UploadMapfixRequest struct {
ModelVersion uint64
TargetAssetID uint64
}
type ReleaseSubmissionRequest struct {
// Release schedule
SubmissionID int64
ReleaseDate int64
// Model download info
ModelID uint64
ModelVersion uint64
// MapCreate
UploadedAssetID uint64
DisplayName string
Creator string
GameID uint32
Submitter uint64
}
type BatchReleaseSubmissionsRequest struct {
Submissions []ReleaseSubmissionRequest
OperationID int32
}
type ReleaseMapfixRequest struct {
MapfixID int64
ModelID uint64
ModelVersion uint64
TargetAssetID uint64
}

13
pkg/model/resource.go Normal file
View File

@@ -0,0 +1,13 @@
package model
type ResourceType int32
const (
ResourceUnknown ResourceType = 0
ResourceMapfix ResourceType = 1
ResourceSubmission ResourceType = 2
)
type Resource struct{
ID int64
Type ResourceType
}

33
pkg/model/roles.go Normal file
View File

@@ -0,0 +1,33 @@
package model
// Submissions roles bitflag
type Roles int32
var (
RolesSubmissionUpload Roles = 1<<6
RolesSubmissionReview Roles = 1<<5
RolesSubmissionRelease Roles = 1<<4
RolesScriptWrite Roles = 1<<3
RolesMapfixUpload Roles = 1<<2
RolesMapfixReview Roles = 1<<1
RolesMapDownload Roles = 1<<0
RolesEmpty Roles = 0
)
// StrafesNET group roles
type GroupRole int32
var (
// has ScriptWrite
RoleQuat GroupRole = 255
RoleItzaname GroupRole = 254
RoleStagingDeveloper GroupRole = 240
RolesAll Roles = ^RolesEmpty
// has SubmissionUpload
RoleMapAdmin GroupRole = 128
RolesMapAdmin Roles = RolesSubmissionRelease|RolesSubmissionUpload|RolesSubmissionReview|RolesMapCouncil
// has MapfixReview
RoleMapCouncil GroupRole = 64
RolesMapCouncil Roles = RolesMapfixReview|RolesMapfixUpload|RolesMapAccess
// access to downloading maps
RoleMapAccess GroupRole = 32
RolesMapAccess Roles = RolesMapDownload
)

View File

@@ -23,13 +23,6 @@ func HashParse(hash string) (uint64, error){
return strconv.ParseUint(hash, 16, 64)
}
type ResourceType int32
const (
ResourceUnknown ResourceType = 0
ResourceMapfix ResourceType = 1
ResourceSubmission ResourceType = 2
)
type Script struct {
ID int64 `gorm:"primaryKey"`
Name string

47
pkg/public_api/dto/map.go Normal file
View File

@@ -0,0 +1,47 @@
package dto
import (
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"time"
)
type MapFilter struct {
GameID *uint32 `json:"game_id" form:"game_id"`
} // @name MapFilter
type Map struct {
ID int64 `json:"id"`
DisplayName string `json:"display_name"`
Creator string `json:"creator"`
GameID uint32 `json:"game_id"`
Date time.Time `json:"date"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
Submitter uint64 `json:"submitter"`
Thumbnail uint64 `json:"thumbnail"`
AssetVersion uint64 `json:"asset_version"`
LoadCount uint32 `json:"load_count"`
Modes uint32 `json:"modes"`
} // @name Map
// FromGRPC converts a maps.MapResponse protobuf message to a Map domain object
func (m *Map) FromGRPC(resp *maps_extended.MapResponse) *Map {
if resp == nil {
return nil
}
m.ID = resp.ID
m.DisplayName = resp.DisplayName
m.Creator = resp.Creator
m.Date = time.Unix(resp.Date, 0)
m.GameID = resp.GameID
m.CreatedAt = time.Unix(resp.CreatedAt, 0)
m.UpdatedAt = time.Unix(resp.UpdatedAt, 0)
m.Submitter = resp.Submitter
m.Thumbnail = resp.Thumbnail
m.AssetVersion = resp.AssetVersion
m.LoadCount = resp.LoadCount
m.Modes = resp.Modes
return m
}

View File

@@ -0,0 +1,52 @@
package dto
// @Description Generic response
type Response[T any] struct {
// Data contains the actual response payload
Data T `json:"data"`
} // @name Response
type PagedTotalResponse[T any] struct {
// Data contains the actual response payload
Data []T `json:"data"`
// Pagination contains information about paging
Pagination PaginationWithTotal `json:"pagination"`
} // @name PagedTotalResponse
// PaginationWithTotal holds information about the current page, total items, etc.
type PaginationWithTotal struct {
// Current page number
Page int `json:"page"`
// Number of items per page
PageSize int `json:"page_size"`
// Total number of items across all pages
TotalItems int `json:"total_items"`
// Total number of pages
TotalPages int `json:"total_pages"`
} // @name PaginationWithTotal
type PagedResponse[T any] struct {
// Data contains the actual response payload
Data []T `json:"data"`
// Pagination contains information about paging
Pagination Pagination `json:"pagination"`
} // @name PagedResponse
// Pagination holds information about the current page.
type Pagination struct {
// Current page number
Page int `json:"page"`
// Number of items per page
PageSize int `json:"page_size"`
} // @name Pagination
// Error holds error responses
type Error struct {
Error string `json:"error"`
} // @name Error

View File

@@ -0,0 +1,98 @@
package handlers
import (
"fmt"
"github.com/gin-gonic/gin"
"google.golang.org/grpc"
"strconv"
)
const (
ErrMsgDataClient = "data client is required"
)
// Handler is a base handler that provides common functionality for all HTTP handlers.
type Handler struct {
mapsClient *grpc.ClientConn
}
// HandlerOption defines a functional option for configuring a Handler
type HandlerOption func(*Handler)
// WithMapsClient sets the data client for the Handler
func WithMapsClient(mapsClient *grpc.ClientConn) HandlerOption {
return func(h *Handler) {
h.mapsClient = mapsClient
}
}
// NewHandler creates a new Handler with the provided options.
// It requires both a datastore and an authentication service to function properly.
func NewHandler(options ...HandlerOption) (*Handler, error) {
handler := &Handler{}
// Apply all provided options
for _, option := range options {
option(handler)
}
// Validate required dependencies
if err := handler.validateDependencies(); err != nil {
return nil, err
}
return handler, nil
}
// validateDependencies ensures all required dependencies are properly set
func (h *Handler) validateDependencies() error {
if h.mapsClient == nil {
return fmt.Errorf(ErrMsgDataClient)
}
return nil
}
// validateRange ensures a value is within the specified range, returning defaultValue if outside
func validateRange(value, min, max, defaultValue int) int {
if value < min {
return defaultValue
}
if value > max {
return max
}
return value
}
// validateMin ensures a value is at least the minimum, returning defaultValue if below
func validateMin(value, min, defaultValue int) int {
if value < min {
return defaultValue
}
return value
}
// getPagination extracts pagination parameters from query string.
// It applies validation rules to ensure parameters are within acceptable ranges.
func getPagination(ctx *gin.Context, defaultPageSize, minPageSize, maxPageSize int) (pageSize, pageNumber int) {
// Get page size from query string, parse to integer
pageSizeStr := ctx.Query("page_size")
if pageSizeStr != "" {
pageSize, _ = strconv.Atoi(pageSizeStr)
} else {
pageSize = defaultPageSize
}
// Get page number from query string, parse to integer
pageNumberStr := ctx.Query("page_number")
if pageNumberStr != "" {
pageNumber, _ = strconv.Atoi(pageNumberStr)
} else {
pageNumber = 1 // Default to first page
}
// Apply validation rules
pageSize = validateRange(pageSize, minPageSize, maxPageSize, defaultPageSize)
pageNumber = validateMin(pageNumber, 1, 1)
return pageSize, pageNumber
}

View File

@@ -0,0 +1,153 @@
package handlers
import (
"git.itzana.me/strafesnet/go-grpc/maps_extended"
"git.itzana.me/strafesnet/maps-service/pkg/public_api/dto"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"net/http"
"strconv"
)
// MapHandler handles HTTP requests related to maps.
type MapHandler struct {
*Handler
}
// NewMapHandler creates a new MapHandler with the provided options.
func NewMapHandler(options ...HandlerOption) (*MapHandler, error) {
baseHandler, err := NewHandler(options...)
if err != nil {
return nil, err
}
return &MapHandler{
Handler: baseHandler,
}, nil
}
// @Summary Get map by ID
// @Description Get a specific map by its ID
// @Tags maps
// @Produce json
// @Security ApiKeyAuth
// @Param id path int true "Map ID"
// @Success 200 {object} dto.Response[dto.Map]
// @Failure 404 {object} dto.Error "Map not found"
// @Failure default {object} dto.Error "General error response"
// @Router /map/{id} [get]
func (h *MapHandler) Get(ctx *gin.Context) {
// Extract map ID from path parameter
id := ctx.Param("id")
mapID, err := strconv.ParseInt(id, 10, 64)
if err != nil {
ctx.JSON(http.StatusBadRequest, dto.Error{
Error: "Invalid map ID format",
})
return
}
// Call the gRPC service
mapData, err := maps_extended.NewMapsServiceClient(h.mapsClient).Get(ctx, &maps_extended.MapId{
ID: mapID,
})
if err != nil {
statusCode := http.StatusInternalServerError
errorMessage := "Failed to get map"
// Check if it's a "not found" error
if status.Code(err) == codes.NotFound {
statusCode = http.StatusNotFound
errorMessage = "Map not found"
}
ctx.JSON(statusCode, dto.Error{
Error: errorMessage,
})
log.WithError(err).Error(
"Failed to get map",
)
return
}
// Convert gRPC MapResponse object to dto.Map object
var mapDto dto.Map
result := mapDto.FromGRPC(mapData)
// Return the map data
ctx.JSON(http.StatusOK, dto.Response[dto.Map]{
Data: *result,
})
}
// @Summary List maps
// @Description Get a list of maps
// @Tags maps
// @Produce json
// @Security ApiKeyAuth
// @Param page_size query int false "Page size (max 100)" default(10) minimum(1) maximum(100)
// @Param page_number query int false "Page number" default(1) minimum(1)
// @Param filter query dto.MapFilter false "Map filter parameters"
// @Success 200 {object} dto.PagedResponse[dto.Map]
// @Failure default {object} dto.Error "General error response"
// @Router /map [get]
func (h *MapHandler) List(ctx *gin.Context) {
// Extract and constrain pagination parameters
query := struct {
PageSize int `form:"page_size,default=10" binding:"min=1,max=100"`
PageNumber int `form:"page_number,default=1" binding:"min=1"`
SortBy int `form:"sort_by,default=0" binding:"min=0,max=3"`
}{}
if err := ctx.ShouldBindQuery(&query); err != nil {
ctx.JSON(http.StatusBadRequest, dto.Error{
Error: err.Error(),
})
return
}
// Get list filter
var filter dto.MapFilter
if err := ctx.ShouldBindQuery(&filter); err != nil {
ctx.JSON(http.StatusBadRequest, dto.Error{
Error: err.Error(),
})
return
}
// Call the gRPC service
mapList, err := maps_extended.NewMapsServiceClient(h.mapsClient).List(ctx, &maps_extended.ListRequest{
Filter: &maps_extended.MapFilter{
GameID: filter.GameID,
},
Page: &maps_extended.Pagination{
Size: uint32(query.PageSize),
Number: uint32(query.PageNumber),
},
})
if err != nil {
ctx.JSON(http.StatusInternalServerError, dto.Error{
Error: "Failed to list maps",
})
log.WithError(err).Error(
"Failed to list maps",
)
return
}
// Convert gRPC MapResponse objects to dto.Map objects
dtoMaps := make([]dto.Map, len(mapList.Maps))
for i, m := range mapList.Maps {
var mapDto dto.Map
dtoMaps[i] = *mapDto.FromGRPC(m)
}
// Return the paged response
ctx.JSON(http.StatusOK, dto.PagedResponse[dto.Map]{
Data: dtoMaps,
Pagination: dto.Pagination{
Page: query.PageNumber,
PageSize: query.PageSize,
},
})
}

159
pkg/public_api/router.go Normal file
View File

@@ -0,0 +1,159 @@
package api
import (
"context"
"errors"
"fmt"
"git.itzana.me/StrafesNET/dev-service/pkg/api/middleware"
"git.itzana.me/strafesnet/maps-service/docs"
"git.itzana.me/strafesnet/maps-service/pkg/public_api/handlers"
"github.com/gin-gonic/gin"
log "github.com/sirupsen/logrus"
swaggerfiles "github.com/swaggo/files"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/urfave/cli/v2"
"google.golang.org/grpc"
"net/http"
"time"
)
// Option defines a function that configures a Router
type Option func(*RouterConfig)
// RouterConfig holds all router configuration
type RouterConfig struct {
port int
devClient *grpc.ClientConn
mapsClient *grpc.ClientConn
context *cli.Context
shutdownTimeout time.Duration
}
// WithPort sets the port for the server£
func WithPort(port int) Option {
return func(cfg *RouterConfig) {
cfg.port = port
}
}
// WithContext sets the context for the server
func WithContext(ctx *cli.Context) Option {
return func(cfg *RouterConfig) {
cfg.context = ctx
}
}
// WithDevClient sets the dev gRPC client
func WithDevClient(conn *grpc.ClientConn) Option {
return func(cfg *RouterConfig) {
cfg.devClient = conn
}
}
// WithMapsClient sets the data gRPC client
func WithMapsClient(conn *grpc.ClientConn) Option {
return func(cfg *RouterConfig) {
cfg.mapsClient = conn
}
}
// WithShutdownTimeout sets the graceful shutdown timeout
func WithShutdownTimeout(timeout time.Duration) Option {
return func(cfg *RouterConfig) {
cfg.shutdownTimeout = timeout
}
}
func setupRoutes(cfg *RouterConfig) (*gin.Engine, error) {
r := gin.Default()
r.ForwardedByClientIP = true
r.Use(gin.Logger())
r.Use(gin.Recovery())
handlerOptions := []handlers.HandlerOption{
handlers.WithMapsClient(cfg.mapsClient),
}
// Maps handler
mapsHandler, err := handlers.NewMapHandler(handlerOptions...)
if err != nil {
return nil, err
}
docs.SwaggerInfo.BasePath = "/public-api/v1"
public_api := r.Group("/public-api")
{
v1 := public_api.Group("/v1")
{
// Auth middleware
v1.Use(middleware.ValidateRequest("Maps", "Read", cfg.devClient))
// Maps
v1.GET("/map", mapsHandler.List)
v1.GET("/map/:id", mapsHandler.Get)
}
// Docs
public_api.GET("/docs/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))
public_api.GET("/", func(ctx *gin.Context) {
ctx.Redirect(http.StatusPermanentRedirect, "/public-api/docs/index.html")
})
}
return r, nil
}
// NewRouter creates a new router with the given options
func NewRouter(options ...Option) error {
// Default configuration
cfg := &RouterConfig{
port: 8080, // Default port
context: nil,
shutdownTimeout: 5 * time.Second,
}
// Apply options
for _, option := range options {
option(cfg)
}
// Validate configuration
if cfg.context == nil {
return errors.New("context is required")
}
if cfg.devClient == nil {
return errors.New("dev client is required")
}
routes, err := setupRoutes(cfg)
if err != nil {
return err
}
log.Info("Starting server")
return runServer(cfg.context.Context, fmt.Sprint(":", cfg.port), routes, cfg.shutdownTimeout)
}
func runServer(ctx context.Context, addr string, r *gin.Engine, shutdownTimeout time.Duration) error {
srv := &http.Server{
Addr: addr,
Handler: r,
}
// Run the server in a separate goroutine
go func() {
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.WithError(err).Fatal("web server exit")
}
}()
// Wait for a shutdown signal
<-ctx.Done()
// Shutdown server gracefully
ctxShutdown, cancel := context.WithTimeout(context.Background(), shutdownTimeout)
defer cancel()
return srv.Shutdown(ctxShutdown)
}

View File

@@ -0,0 +1,95 @@
package roblox
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
type AssetMetadata struct {
MetadataType uint32 `json:"metadataType"`
Value string `json:"value"`
}
// Struct equivalent to Rust's AssetLocationInfo
type AssetLocationInfo struct {
Location string `json:"location"`
RequestId string `json:"requestId"`
IsArchived bool `json:"isArchived"`
AssetTypeId uint32 `json:"assetTypeId"`
AssetMetadatas []AssetMetadata `json:"assetMetadatas"`
IsRecordable bool `json:"isRecordable"`
}
// Input struct for getAssetLocation
type GetAssetLatestRequest struct {
AssetID uint64
}
// Custom error type if needed
type GetError string
func (e GetError) Error() string { return string(e) }
// Example client with a Get method
type Client struct {
HttpClient *http.Client
ApiKey string
}
func (c *Client) GetAssetLocation(config GetAssetLatestRequest) (*AssetLocationInfo, error) {
rawURL := fmt.Sprintf("https://apis.roblox.com/asset-delivery-api/v1/assetId/%d", config.AssetID)
parsedURL, err := url.Parse(rawURL)
if err != nil {
return nil, GetError("ParseError: " + err.Error())
}
req, err := http.NewRequest("GET", parsedURL.String(), nil)
if err != nil {
return nil, GetError("RequestCreationError: " + err.Error())
}
req.Header.Set("x-api-key", c.ApiKey)
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, GetError("RequestError: " + err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, GetError(fmt.Sprintf("ResponseError: status code %d", resp.StatusCode))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, GetError("ReadBodyError: " + err.Error())
}
var info AssetLocationInfo
if err := json.Unmarshal(body, &info); err != nil {
return nil, GetError("JSONError: " + err.Error())
}
return &info, nil
}
func (c *Client) DownloadAsset(info *AssetLocationInfo) (io.Reader, error) {
req, err := http.NewRequest("GET", info.Location, nil)
if err != nil {
return nil, GetError("RequestCreationError: " + err.Error())
}
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, GetError("RequestError: " + err.Error())
}
if resp.StatusCode != http.StatusOK {
return nil, GetError(fmt.Sprintf("ResponseError: status code %d", resp.StatusCode))
}
return resp.Body, nil
}

160
pkg/roblox/thumbnails.go Normal file
View File

@@ -0,0 +1,160 @@
package roblox
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// ThumbnailSize represents valid Roblox thumbnail sizes
type ThumbnailSize string
const (
Size150x150 ThumbnailSize = "150x150"
Size420x420 ThumbnailSize = "420x420"
Size768x432 ThumbnailSize = "768x432"
)
// ThumbnailFormat represents the image format
type ThumbnailFormat string
const (
FormatPng ThumbnailFormat = "Png"
FormatJpeg ThumbnailFormat = "Jpeg"
)
// ThumbnailRequest represents a single thumbnail request
type ThumbnailRequest struct {
RequestID string `json:"requestId,omitempty"`
Type string `json:"type"`
TargetID uint64 `json:"targetId"`
Size string `json:"size,omitempty"`
Format string `json:"format,omitempty"`
}
// ThumbnailData represents a single thumbnail response
type ThumbnailData struct {
TargetID uint64 `json:"targetId"`
State string `json:"state"` // "Completed", "Error", "Pending"
ImageURL string `json:"imageUrl"`
}
// BatchThumbnailsResponse represents the API response
type BatchThumbnailsResponse struct {
Data []ThumbnailData `json:"data"`
}
// GetAssetThumbnails fetches thumbnails for multiple assets in a single batch request
// Roblox allows up to 100 assets per batch
func (c *Client) GetAssetThumbnails(assetIDs []uint64, size ThumbnailSize, format ThumbnailFormat) ([]ThumbnailData, error) {
if len(assetIDs) == 0 {
return []ThumbnailData{}, nil
}
if len(assetIDs) > 100 {
return nil, GetError("batch size cannot exceed 100 assets")
}
// Build request payload - the API expects an array directly, not wrapped in an object
requests := make([]ThumbnailRequest, len(assetIDs))
for i, assetID := range assetIDs {
requests[i] = ThumbnailRequest{
Type: "Asset",
TargetID: assetID,
Size: string(size),
Format: string(format),
}
}
jsonData, err := json.Marshal(requests)
if err != nil {
return nil, GetError("JSONMarshalError: " + err.Error())
}
req, err := http.NewRequest("POST", "https://thumbnails.roblox.com/v1/batch", bytes.NewBuffer(jsonData))
if err != nil {
return nil, GetError("RequestCreationError: " + err.Error())
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, GetError("RequestError: " + err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, GetError(fmt.Sprintf("ResponseError: status code %d, body: %s", resp.StatusCode, string(body)))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, GetError("ReadBodyError: " + err.Error())
}
var response BatchThumbnailsResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, GetError("JSONUnmarshalError: " + err.Error())
}
return response.Data, nil
}
// GetUserAvatarThumbnails fetches avatar thumbnails for multiple users in a single batch request
func (c *Client) GetUserAvatarThumbnails(userIDs []uint64, size ThumbnailSize, format ThumbnailFormat) ([]ThumbnailData, error) {
if len(userIDs) == 0 {
return []ThumbnailData{}, nil
}
if len(userIDs) > 100 {
return nil, GetError("batch size cannot exceed 100 users")
}
// Build request payload - the API expects an array directly, not wrapped in an object
requests := make([]ThumbnailRequest, len(userIDs))
for i, userID := range userIDs {
requests[i] = ThumbnailRequest{
Type: "AvatarHeadShot",
TargetID: userID,
Size: string(size),
Format: string(format),
}
}
jsonData, err := json.Marshal(requests)
if err != nil {
return nil, GetError("JSONMarshalError: " + err.Error())
}
req, err := http.NewRequest("POST", "https://thumbnails.roblox.com/v1/batch", bytes.NewBuffer(jsonData))
if err != nil {
return nil, GetError("RequestCreationError: " + err.Error())
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, GetError("RequestError: " + err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, GetError(fmt.Sprintf("ResponseError: status code %d, body: %s", resp.StatusCode, string(body)))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, GetError("ReadBodyError: " + err.Error())
}
var response BatchThumbnailsResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, GetError("JSONUnmarshalError: " + err.Error())
}
return response.Data, nil
}

72
pkg/roblox/users.go Normal file
View File

@@ -0,0 +1,72 @@
package roblox
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
// UserData represents a single user's information
type UserData struct {
ID uint64 `json:"id"`
Name string `json:"name"`
DisplayName string `json:"displayName"`
}
// BatchUsersResponse represents the API response for batch user requests
type BatchUsersResponse struct {
Data []UserData `json:"data"`
}
// GetUsernames fetches usernames for multiple users in a single batch request
// Roblox allows up to 100 users per batch
func (c *Client) GetUsernames(userIDs []uint64) ([]UserData, error) {
if len(userIDs) == 0 {
return []UserData{}, nil
}
if len(userIDs) > 100 {
return nil, GetError("batch size cannot exceed 100 users")
}
// Build request payload
payload := map[string][]uint64{
"userIds": userIDs,
}
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, GetError("JSONMarshalError: " + err.Error())
}
req, err := http.NewRequest("POST", "https://users.roblox.com/v1/users", bytes.NewBuffer(jsonData))
if err != nil {
return nil, GetError("RequestCreationError: " + err.Error())
}
req.Header.Set("Content-Type", "application/json")
resp, err := c.HttpClient.Do(req)
if err != nil {
return nil, GetError("RequestError: " + err.Error())
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, GetError(fmt.Sprintf("ResponseError: status code %d, body: %s", resp.StatusCode, string(body)))
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, GetError("ReadBodyError: " + err.Error())
}
var response BatchUsersResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, GetError("JSONUnmarshalError: " + err.Error())
}
return response.Data, nil
}

View File

@@ -10,85 +10,13 @@ import (
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log
//
// POST /mapfixes/{MapfixID}/comment
func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.CreateMapfixAuditCommentReq, params api.CreateMapfixAuditCommentParams) (error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleMapfixReview()
if err != nil {
return err
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
}
if !has_role {
// Submitter has special permission to comment on their mapfix
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
if err != nil {
return err
}
if mapfix.Submitter != userId {
return ErrPermissionDeniedNeedRoleMapfixReview
}
}
data := []byte{}
_, err = req.Read(data)
if err != nil {
return err
}
Comment := string(data)
event_data := model.AuditEventDataComment{
Comment: Comment,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeComment,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ListMapfixAuditEvents invokes listMapfixAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /mapfixes/{MapfixID}/audit-events
func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMapfixAuditEventsParams) ([]api.AuditEvent, error) {
func (svc *Service) ListAuditEvents(ctx context.Context, resource model.Resource, page model.Page) ([]api.AuditEvent, error){
filter := datastore.Optional()
filter.Add("resource_type", model.ResourceMapfix)
filter.Add("resource_id", params.MapfixID)
filter.Add("resource_type", resource.Type)
filter.Add("resource_id", resource.ID)
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
items, err := svc.db.AuditEvents().List(ctx, filter, page)
if err != nil {
return nil, err
}
@@ -104,7 +32,7 @@ func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMa
idList.ID = append(idList.ID, userId)
}
userList, err := svc.Users.GetList(ctx, &idList)
userList, err := svc.users.GetList(ctx, &idList)
if err != nil {
return nil, err
}
@@ -140,60 +68,38 @@ func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMa
return resp, nil
}
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
//
// Post a comment to the audit log
//
// POST /submissions/{SubmissionID}/comment
func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.CreateSubmissionAuditCommentReq, params api.CreateSubmissionAuditCommentParams) (error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleSubmissionReview()
if err != nil {
return err
}
userId, err := userInfo.GetUserID()
if err != nil {
return err
}
if !has_role {
// Submitter has special permission to comment on their submission
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
if err != nil {
return err
}
if submission.Submitter != userId {
return ErrPermissionDeniedNeedRoleSubmissionReview
}
}
data := []byte{}
_, err = req.Read(data)
if err != nil {
return err
}
Comment := string(data)
event_data := model.AuditEventDataComment{
Comment: Comment,
}
func (svc *Service) CreateAuditEventAction(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataAction) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
func (svc *Service) CreateAuditEventComment(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataComment) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeComment,
EventData: EventData,
})
@@ -204,68 +110,129 @@ func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.Cr
return nil
}
// ListSubmissionAuditEvents invokes listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.ListSubmissionAuditEventsParams) ([]api.AuditEvent, error) {
filter := datastore.Optional()
func (svc *Service) CreateAuditEventChangeModel(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataChangeModel) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
filter.Add("resource_type", model.ResourceSubmission)
filter.Add("resource_id", params.SubmissionID)
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeChangeModel,
EventData: EventData,
})
if err != nil {
return nil, err
return err
}
idMap := make(map[int64]bool)
for _, item := range items {
idMap[int64(item.User)] = true
}
var idList users.IdList
idList.ID = make([]int64,len(idMap))
for userId := range idMap {
idList.ID = append(idList.ID, userId)
}
userList, err := svc.Users.GetList(ctx, &idList)
if err != nil {
return nil, err
}
userMap := make(map[int64]*users.UserResponse)
for _,user := range userList.Users {
userMap[user.ID] = user
}
var resp []api.AuditEvent
for _, item := range items {
EventData := api.AuditEventEventData{}
err = EventData.UnmarshalJSON(item.EventData)
if err != nil {
return nil, err
}
username := ""
if userMap[int64(item.User)] != nil {
username = userMap[int64(item.User)].Username
}
resp = append(resp, api.AuditEvent{
ID: item.ID,
Date: item.CreatedAt.Unix(),
User: int64(item.User),
Username: username,
ResourceType: int32(item.ResourceType),
ResourceID: item.ResourceID,
EventType: int32(item.EventType),
EventData: EventData,
})
}
return resp, nil
return nil
}
func (svc *Service) CreateAuditEventChangeValidatedModel(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataChangeValidatedModel) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeChangeValidatedModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
func (svc *Service) CreateAuditEventError(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataError) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeError,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
func (svc *Service) CreateAuditEventCheckList(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataCheckList) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeCheckList,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
func (svc *Service) CreateAuditEventChangeDisplayName(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataChangeName) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeChangeDisplayName,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
func (svc *Service) CreateAuditEventChangeCreator(ctx context.Context, userId uint64, resource model.Resource, event_data model.AuditEventDataChangeName) error {
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.db.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: userId,
ResourceType: resource.Type,
ResourceID: resource.ID,
EventType: model.AuditEventTypeChangeCreator,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,72 +2,149 @@ package service
import (
"context"
"time"
"git.itzana.me/strafesnet/go-grpc/maps"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// ListMaps implements listMaps operation.
//
// Get list of maps.
//
// GET /maps
func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]api.Map, error) {
filter := maps.MapFilter{}
// Optional map used to update an object
type MapUpdate datastore.OptionalMap
if params.DisplayName.IsSet(){
filter.DisplayName = &params.DisplayName.Value
}
if params.Creator.IsSet(){
filter.Creator = &params.Creator.Value
}
if params.GameID.IsSet(){
filter.GameID = &params.GameID.Value
}
mapList, err := svc.Maps.List(ctx, &maps.ListRequest{
Filter: &filter,
Page: &maps.Pagination{
Size: params.Limit,
Number: params.Page,
},
})
if err != nil {
return nil, err
}
var resp []api.Map
for _, item := range mapList.Maps {
resp = append(resp, api.Map{
ID: item.ID,
DisplayName: item.DisplayName,
Creator: item.Creator,
GameID: item.GameID,
Date: item.Date,
})
}
return resp, nil
func NewMapUpdate() MapUpdate {
update := datastore.Optional()
return MapUpdate(update)
}
// GetMap implements getScript operation.
//
// Get the specified script by ID.
//
// GET /maps/{MapID}
func (svc *Service) GetMap(ctx context.Context, params api.GetMapParams) (*api.Map, error) {
mapResponse, err := svc.Maps.Get(ctx, &maps.IdMessage{
ID: params.MapID,
func (update MapUpdate) SetDisplayName(display_name string) {
datastore.OptionalMap(update).Add("display_name", display_name)
}
func (update MapUpdate) SetCreator(creator string) {
datastore.OptionalMap(update).Add("creator", creator)
}
func (update MapUpdate) SetGameID(game_id uint32) {
datastore.OptionalMap(update).Add("game_id", game_id)
}
func (update MapUpdate) SetDate(date int64) {
datastore.OptionalMap(update).Add("date", time.Unix(date, 0))
}
func (update MapUpdate) SetSubmitter(submitter uint64) {
datastore.OptionalMap(update).Add("submitter", submitter)
}
func (update MapUpdate) SetThumbnail(thumbnail uint64) {
datastore.OptionalMap(update).Add("thumbnail", thumbnail)
}
func (update MapUpdate) SetAssetVersion(asset_version uint64) {
datastore.OptionalMap(update).Add("asset_version", asset_version)
}
func (update MapUpdate) SetModes(modes uint32) {
datastore.OptionalMap(update).Add("modes", modes)
}
// getters
func (update MapUpdate) GetDisplayName() (string, bool) {
value, ok := datastore.OptionalMap(update).Map()["display_name"].(string)
return value, ok
}
func (update MapUpdate) GetGameID() (uint32, bool) {
value, ok := datastore.OptionalMap(update).Map()["game_id"].(uint32)
return value, ok
}
func (update MapUpdate) GetThumbnail() (uint64, bool) {
value, ok := datastore.OptionalMap(update).Map()["thumbnail"].(uint64)
return value, ok
}
// Optional map used to find matching objects
type MapFilter datastore.OptionalMap
func NewMapFilter(
) MapFilter {
filter := datastore.Optional()
return MapFilter(filter)
}
func (update MapFilter) SetDisplayName(display_name string) {
datastore.OptionalMap(update).Add("display_name", display_name)
}
func (update MapFilter) SetCreator(creator string) {
datastore.OptionalMap(update).Add("creator", creator)
}
func (update MapFilter) SetGameID(game_id uint32) {
datastore.OptionalMap(update).Add("game_id", game_id)
}
func (update MapFilter) SetSubmitter(submitter uint64) {
datastore.OptionalMap(update).Add("submitter", submitter)
}
func (svc *Service) CreateMap(ctx context.Context, item model.Map) (int64, error) {
// 2 jobs:
// create map on maps-service
map_item, err := svc.db.Maps().Create(ctx, item)
if err != nil {
return 0, err
}
// create map on data-service
game_id := int32(item.GameID)
_, err = svc.maps.Create(ctx, &maps.MapRequest{
ID: item.ID,
DisplayName: &item.DisplayName,
GameID: &game_id,
Thumbnail: &item.Thumbnail,
})
if err != nil {
return nil, err
return 0, err
}
return &api.Map{
ID: mapResponse.ID,
DisplayName: mapResponse.DisplayName,
Creator: mapResponse.Creator,
GameID: mapResponse.GameID,
Date: mapResponse.Date,
}, nil
return map_item.ID, nil
}
func (svc *Service) ListMaps(ctx context.Context, filter MapFilter, page model.Page) ([]model.Map, error) {
return svc.db.Maps().List(ctx, datastore.OptionalMap(filter), page)
}
func (svc *Service) GetMapList(ctx context.Context, ids []int64) ([]model.Map, error) {
return svc.db.Maps().GetList(ctx, ids)
}
func (svc *Service) DeleteMap(ctx context.Context, id int64) error {
// Do not delete the "embedded" map, since it deletes times.
// _, err := svc.maps.Delete(ctx, &maps.IdMessage{ID: id})
return svc.db.Maps().Delete(ctx, id)
}
func (svc *Service) GetMap(ctx context.Context, id int64) (model.Map, error) {
return svc.db.Maps().Get(ctx, id)
}
func (svc *Service) UpdateMap(ctx context.Context, id int64, pmap MapUpdate) error {
// 2 jobs:
// update map on maps-service
err := svc.db.Maps().Update(ctx, id, datastore.OptionalMap(pmap))
if err != nil {
return err
}
// update map on data-service
update := maps.MapRequest{
ID: id,
}
if display_name, ok := pmap.GetDisplayName(); ok {
update.DisplayName = &display_name
}
if game_id, ok := pmap.GetGameID(); ok {
game_id_int32 := int32(game_id)
update.GameID = &game_id_int32
}
if thumbnail, ok := pmap.GetThumbnail(); ok {
update.Thumbnail = &thumbnail
}
_, err = svc.maps.Update(ctx, &update)
if err != nil {
return err
}
return nil
}
func (svc *Service) IncrementMapLoadCount(ctx context.Context, id int64) error {
return svc.db.Maps().IncrementLoadCount(ctx, id)
}

140
pkg/service/nats_mapfix.go Normal file
View File

@@ -0,0 +1,140 @@
package service
import (
"encoding/json"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
func (svc *Service) NatsCreateMapfix(
OperationID int32,
ModelID uint64,
TargetAssetID uint64,
Description string,
) error {
create_request := model.CreateMapfixRequest{
OperationID: OperationID,
ModelID: ModelID,
TargetAssetID: TargetAssetID,
Description: Description,
}
j, err := json.Marshal(create_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.mapfixes.create", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsCheckMapfix(
MapfixID int64,
ModelID uint64,
SkipChecks bool,
) error {
validate_request := model.CheckMapfixRequest{
MapfixID: MapfixID,
ModelID: ModelID,
SkipChecks: SkipChecks,
}
j, err := json.Marshal(validate_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.mapfixes.check", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsUploadMapfix(
MapfixID int64,
ModelID uint64,
ModelVersion uint64,
TargetAssetID uint64,
) error {
upload_fix_request := model.UploadMapfixRequest{
MapfixID: MapfixID,
ModelID: ModelID,
ModelVersion: ModelVersion,
TargetAssetID: TargetAssetID,
}
j, err := json.Marshal(upload_fix_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.mapfixes.upload", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsValidateMapfix(
MapfixID int64,
ModelID uint64,
ModelVersion uint64,
ValidatedAssetID uint64,
) error {
validate_request := model.ValidateMapfixRequest{
MapfixID: MapfixID,
ModelID: ModelID,
ModelVersion: ModelVersion,
ValidatedModelID: nil,
}
// sentinel values because we're not using rust
if ValidatedAssetID != 0 {
validate_request.ValidatedModelID = &ValidatedAssetID
}
j, err := json.Marshal(validate_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.mapfixes.validate", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsReleaseMapfix(
MapfixID int64,
ModelID uint64,
ModelVersion uint64,
TargetAssetID uint64,
) error {
release_fix_request := model.ReleaseMapfixRequest{
MapfixID: MapfixID,
ModelID: ModelID,
ModelVersion: ModelVersion,
TargetAssetID: TargetAssetID,
}
j, err := json.Marshal(release_fix_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.mapfixes.release", []byte(j))
if err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,142 @@
package service
import (
"encoding/json"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
func (svc *Service) NatsCreateSubmission(
OperationID int32,
ModelID uint64,
DisplayName string,
Creator string,
GameID uint32,
Status uint32,
Roles uint32,
) error {
create_request := model.CreateSubmissionRequest{
OperationID: OperationID,
ModelID: ModelID,
DisplayName: DisplayName,
Creator: Creator,
GameID: GameID,
Status: Status,
Roles: Roles,
}
j, err := json.Marshal(create_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.submissions.create", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsCheckSubmission(
SubmissionID int64,
ModelID uint64,
SkipChecks bool,
) error {
validate_request := model.CheckSubmissionRequest{
SubmissionID: SubmissionID,
ModelID: ModelID,
SkipChecks: SkipChecks,
}
j, err := json.Marshal(validate_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.submissions.check", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsUploadSubmission(
SubmissionID int64,
ModelID uint64,
ModelVersion uint64,
ModelName string,
) error {
upload_new_request := model.UploadSubmissionRequest{
SubmissionID: SubmissionID,
ModelID: ModelID,
ModelVersion: ModelVersion,
ModelName: ModelName,
}
j, err := json.Marshal(upload_new_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.submissions.upload", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsBatchReleaseSubmissions(
Submissions []model.ReleaseSubmissionRequest,
operation int32,
) error {
release_new_request := model.BatchReleaseSubmissionsRequest{
Submissions: Submissions,
OperationID: operation,
}
j, err := json.Marshal(release_new_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.submissions.batchrelease", []byte(j))
if err != nil {
return err
}
return nil
}
func (svc *Service) NatsValidateSubmission(
SubmissionID int64,
ModelID uint64,
ModelVersion uint64,
ValidatedModelID uint64,
) error {
validate_request := model.ValidateSubmissionRequest{
SubmissionID: SubmissionID,
ModelID: ModelID,
ModelVersion: ModelVersion,
ValidatedModelID: nil,
}
// sentinel values because we're not using rust
if ValidatedModelID != 0 {
validate_request.ValidatedModelID = &ValidatedModelID
}
j, err := json.Marshal(validate_request)
if err != nil {
return err
}
_, err = svc.nats.Publish("maptest.submissions.validate", []byte(j))
if err != nil {
return err
}
return nil
}

View File

@@ -2,45 +2,54 @@ package service
import (
"context"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// GetOperation implements getOperation operation.
//
// Get the specified operation by ID.
//
// GET /operations/{OperationID}
func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationParams) (*api.Operation, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
}
type OperationFailParams datastore.OptionalMap
// You must be the operation owner to read it
operation, err := svc.DB.Operations().Get(ctx, params.OperationID)
if err != nil {
return nil, err
}
userId, err := userInfo.GetUserID()
if err != nil {
return nil, err
}
// check if caller is the submitter
has_role := userId == operation.Owner
if !has_role {
return nil, ErrPermissionDeniedNotSubmitter
}
return &api.Operation{
OperationID: operation.ID,
Date: operation.CreatedAt.Unix(),
Owner: int64(operation.Owner),
Status: int32(operation.StatusID),
StatusMessage: operation.StatusMessage,
Path: operation.Path,
}, nil
func NewOperationFailParams(
status_message string,
) OperationFailParams {
filter := datastore.Optional()
filter.Add("status_id", model.OperationStatusFailed)
filter.Add("status_message", status_message)
return OperationFailParams(filter)
}
type OperationCompleteParams datastore.OptionalMap
func NewOperationCompleteParams(
path string,
) OperationCompleteParams {
filter := datastore.Optional()
filter.Add("status_id", model.OperationStatusCompleted)
filter.Add("path", path)
return OperationCompleteParams(filter)
}
func (svc *Service) CreateOperation(ctx context.Context, operation model.Operation) (model.Operation, error) {
return svc.db.Operations().Create(ctx, operation)
}
func (svc *Service) CountOperationsSince(ctx context.Context, owner int64, since time.Time) (int64, error) {
return svc.db.Operations().CountSince(ctx, owner, since)
}
func (svc *Service) DeleteOperation(ctx context.Context, id int32) error {
return svc.db.Operations().Delete(ctx, id)
}
func (svc *Service) GetOperation(ctx context.Context, id int32) (model.Operation, error) {
return svc.db.Operations().Get(ctx, id)
}
func (svc *Service) FailOperation(ctx context.Context, id int32, params OperationFailParams) error {
return svc.db.Operations().Update(ctx, id, datastore.OptionalMap(params))
}
func (svc *Service) CompleteOperation(ctx context.Context, id int32, params OperationCompleteParams) error {
return svc.db.Operations().Update(ctx, id, datastore.OptionalMap(params))
}

View File

@@ -3,169 +3,43 @@ package service
import (
"context"
"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.ScriptPolicyID, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
}
type ScriptPolicyFilter datastore.OptionalMap
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return nil, err
}
if !has_role {
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.ScriptPolicyID{
ScriptPolicyID: script.ID,
}, nil
}
// ListScriptPolicy implements listScriptPolicy operation.
//
// Get list of script policies.
//
// GET /script-policy
func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptPolicyParams) ([]api.ScriptPolicy, error) {
func NewScriptPolicyFilter() ScriptPolicyFilter {
filter := datastore.Optional()
if params.FromScriptHash.IsSet(){
hash, err := model.HashParse(params.FromScriptHash.Value)
if err != nil {
return nil, err
}
filter.Add("from_script_hash", int64(hash)) // No type safety!
}
if params.ToScriptID.IsSet(){
filter.Add("to_script_id", params.ToScriptID.Value)
}
if params.Policy.IsSet(){
filter.Add("policy", params.Policy.Value)
}
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
return nil, err
}
var resp []api.ScriptPolicy
for _, item := range items {
resp = append(resp, api.ScriptPolicy{
ID: item.ID,
FromScriptHash: model.HashFormat(uint64(item.FromScriptHash)),
ToScriptID: item.ToScriptID,
Policy: int32(item.Policy),
})
}
return resp, nil
return ScriptPolicyFilter(filter)
}
func (filter ScriptPolicyFilter) SetFromScriptHash(from_script_hash int64) {
// Finally, type safety!
datastore.OptionalMap(filter).Add("from_script_hash", from_script_hash)
}
func (filter ScriptPolicyFilter) SetToScriptID(to_script_id int64) {
datastore.OptionalMap(filter).Add("to_script_id", to_script_id)
}
func (filter ScriptPolicyFilter) SetPolicy(policy int32) {
datastore.OptionalMap(filter).Add("policy", policy)
}
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// DELETE /script-policy/{ScriptPolicyID}
func (svc *Service) DeleteScriptPolicy(ctx context.Context, params api.DeleteScriptPolicyParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return err
}
if !has_role {
return ErrPermissionDenied
}
return svc.DB.ScriptPolicy().Delete(ctx, params.ScriptPolicyID)
func (svc *Service) CreateScriptPolicy(ctx context.Context, script model.ScriptPolicy) (model.ScriptPolicy, error) {
return svc.db.ScriptPolicy().Create(ctx, script)
}
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/{ScriptPolicyID}
func (svc *Service) GetScriptPolicy(ctx context.Context, params api.GetScriptPolicyParams) (*api.ScriptPolicy, error) {
policy, err := svc.DB.ScriptPolicy().Get(ctx, params.ScriptPolicyID)
if err != nil {
return nil, err
}
return &api.ScriptPolicy{
ID: policy.ID,
FromScriptHash: model.HashFormat(uint64(policy.FromScriptHash)),
ToScriptID: policy.ToScriptID,
Policy: int32(policy.Policy),
}, nil
func (svc *Service) ListScriptPolicies(ctx context.Context, filter ScriptPolicyFilter, page model.Page) ([]model.ScriptPolicy, error) {
return svc.db.ScriptPolicy().List(ctx, datastore.OptionalMap(filter), page)
}
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// POST /script-policy/{ScriptPolicyID}
func (svc *Service) UpdateScriptPolicy(ctx context.Context, req *api.ScriptPolicyUpdate, params api.UpdateScriptPolicyParams) error {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return err
}
if !has_role {
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)
func (svc *Service) DeleteScriptPolicy(ctx context.Context, id int64) error {
return svc.db.ScriptPolicy().Delete(ctx, id)
}
func (svc *Service) GetScriptPolicy(ctx context.Context, id int64) (model.ScriptPolicy, error) {
return svc.db.ScriptPolicy().Get(ctx, id)
}
func (svc *Service) UpdateScriptPolicy(ctx context.Context, id int64, pmap ScriptPolicyFilter) error {
return svc.db.ScriptPolicy().Update(ctx, id, datastore.OptionalMap(pmap))
}

View File

@@ -3,172 +3,48 @@ package service
import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (svc *Service) CreateScript(ctx context.Context, req *api.ScriptCreate) (*api.ScriptID, error) {
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
if !ok {
return nil, ErrUserInfo
}
type ScriptFilter datastore.OptionalMap
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return nil, err
}
if !has_role {
return nil, ErrPermissionDenied
}
script, err := svc.DB.Scripts().Create(ctx, model.Script{
ID: 0,
Name: req.Name,
Hash: int64(model.HashSource(req.Source)),
Source: req.Source,
ResourceType: model.ResourceType(req.ResourceType),
ResourceID: req.ResourceID.Or(0),
})
if err != nil {
return nil, err
}
return &api.ScriptID{
ScriptID: script.ID,
}, nil
}
// ListScripts implements listScripts operation.
//
// Get list of scripts.
//
// GET /scripts
func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParams) ([]api.Script, error) {
func NewScriptFilter() ScriptFilter {
filter := datastore.Optional()
if params.Hash.IsSet(){
hash, err := model.HashParse(params.Hash.Value)
if err != nil {
return nil, err
}
filter.Add("hash", int64(hash)) // No type safety!
}
if params.Name.IsSet(){
filter.Add("name", params.Name.Value)
}
if params.Source.IsSet(){
filter.Add("source", params.Source.Value)
}
if params.ResourceType.IsSet(){
filter.Add("resource_type", params.ResourceType.Value)
}
if params.ResourceID.IsSet(){
filter.Add("resource_id", params.ResourceID.Value)
}
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
return nil, err
}
var resp []api.Script
for _, item := range items {
resp = append(resp, api.Script{
ID: item.ID,
Hash: model.HashFormat(uint64(item.Hash)),
Source: item.Source,
ResourceType: int32(item.ResourceType),
ResourceID: item.ResourceID,
})
}
return resp, nil
return ScriptFilter(filter)
}
func (filter ScriptFilter) SetName(name string) {
datastore.OptionalMap(filter).Add("name", name)
}
func (filter ScriptFilter) SetSource(source string) {
datastore.OptionalMap(filter).Add("source", source)
}
func (filter ScriptFilter) SetHash(hash int64) {
datastore.OptionalMap(filter).Add("hash", hash)
}
func (filter ScriptFilter) SetResourceType(resource_type int32) {
datastore.OptionalMap(filter).Add("resource_type", resource_type)
}
func (filter ScriptFilter) SetResourceID(resource_id int64) {
datastore.OptionalMap(filter).Add("resource_id", resource_id)
}
// 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").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return err
}
if !has_role {
return ErrPermissionDenied
}
return svc.DB.Scripts().Delete(ctx, params.ScriptID)
func (svc *Service) CreateScript(ctx context.Context, script model.Script) (model.Script, error) {
return svc.db.Scripts().Create(ctx, script)
}
// 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) {
script, err := svc.DB.Scripts().Get(ctx, params.ScriptID)
if err != nil {
return nil, err
}
return &api.Script{
ID: script.ID,
Name: script.Name,
Hash: model.HashFormat(uint64(script.Hash)),
Source: script.Source,
ResourceType: int32(script.ResourceType),
ResourceID: script.ResourceID,
}, nil
func (svc *Service) ListScripts(ctx context.Context, filter ScriptFilter, page model.Page) ([]model.Script, error) {
return svc.db.Scripts().List(ctx, datastore.OptionalMap(filter), page)
}
// 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").(UserInfoHandle)
if !ok {
return ErrUserInfo
}
has_role, err := userInfo.HasRoleScriptWrite()
if err != nil {
return err
}
if !has_role {
return ErrPermissionDenied
}
pmap := datastore.Optional()
if Name, ok := req.Name.Get(); ok {
pmap.Add("name", Name)
}
if source, ok := req.Source.Get(); ok {
pmap.Add("source", source)
pmap.Add("hash", int64(model.HashSource(source))) // No type safety!
}
if ResourceType, ok := req.ResourceType.Get(); ok {
pmap.Add("resource_type", ResourceType)
}
if ResourceID, ok := req.ResourceID.Get(); ok {
pmap.Add("resource_id", ResourceID)
}
return svc.DB.Scripts().Update(ctx, req.ID, pmap)
func (svc *Service) DeleteScript(ctx context.Context, id int64) error {
return svc.db.Scripts().Delete(ctx, id)
}
func (svc *Service) GetScript(ctx context.Context, id int64) (model.Script, error) {
return svc.db.Scripts().Get(ctx, id)
}
func (svc *Service) UpdateScript(ctx context.Context, id int64, pmap ScriptFilter) error {
return svc.db.Scripts().Update(ctx, id, datastore.OptionalMap(pmap))
}

View File

@@ -2,60 +2,66 @@ package service
import (
"context"
"errors"
"fmt"
"git.itzana.me/strafesnet/go-grpc/maps"
"git.itzana.me/strafesnet/go-grpc/users"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/roblox"
"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")
ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapfixUpload = fmt.Errorf("%w: Need Role MapfixUpload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapfixReview = fmt.Errorf("%w: Need Role MapfixReview", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
ErrNegativeID = errors.New("A negative ID was provided")
"github.com/redis/go-redis/v9"
)
type Service struct {
DB datastore.Datastore
Nats nats.JetStreamContext
Maps maps.MapsServiceClient
Users users.UsersServiceClient
db datastore.Datastore
nats nats.JetStreamContext
maps maps.MapsServiceClient
users users.UsersServiceClient
thumbnailService *ThumbnailService
}
// NewError creates *ErrorStatusCode from error returned by handler.
//
// Used for common default response.
func (svc *Service) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
status := 500
if errors.Is(err, datastore.ErrNotExist) {
status = 404
}
if errors.Is(err, ErrPermissionDenied) {
status = 403
}
if errors.Is(err, ErrUserInfo) {
status = 401
}
return &api.ErrorStatusCode{
StatusCode: status,
Response: api.Error{
Code: int64(status),
Message: err.Error(),
},
func NewService(
db datastore.Datastore,
nats nats.JetStreamContext,
maps maps.MapsServiceClient,
users users.UsersServiceClient,
robloxClient *roblox.Client,
redisClient *redis.Client,
) Service {
return Service{
db: db,
nats: nats,
maps: maps,
users: users,
thumbnailService: NewThumbnailService(robloxClient, redisClient),
}
}
// GetAssetThumbnails proxies to the thumbnail service
func (s *Service) GetAssetThumbnails(ctx context.Context, assetIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) {
return s.thumbnailService.GetAssetThumbnails(ctx, assetIDs, size)
}
// GetUserAvatarThumbnails proxies to the thumbnail service
func (s *Service) GetUserAvatarThumbnails(ctx context.Context, userIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) {
return s.thumbnailService.GetUserAvatarThumbnails(ctx, userIDs, size)
}
// GetSingleAssetThumbnail proxies to the thumbnail service
func (s *Service) GetSingleAssetThumbnail(ctx context.Context, assetID uint64, size roblox.ThumbnailSize) (string, error) {
return s.thumbnailService.GetSingleAssetThumbnail(ctx, assetID, size)
}
// GetSingleUserAvatarThumbnail proxies to the thumbnail service
func (s *Service) GetSingleUserAvatarThumbnail(ctx context.Context, userID uint64, size roblox.ThumbnailSize) (string, error) {
return s.thumbnailService.GetSingleUserAvatarThumbnail(ctx, userID, size)
}
// GetUsernames proxies to the thumbnail service
func (s *Service) GetUsernames(ctx context.Context, userIDs []uint64) (map[uint64]string, error) {
return s.thumbnailService.GetUsernames(ctx, userIDs)
}
// GetSingleUsername proxies to the thumbnail service
func (s *Service) GetSingleUsername(ctx context.Context, userID uint64) (string, error) {
return s.thumbnailService.GetSingleUsername(ctx, userID)
}

File diff suppressed because it is too large Load Diff

218
pkg/service/thumbnails.go Normal file
View File

@@ -0,0 +1,218 @@
package service
import (
"context"
"encoding/json"
"fmt"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/roblox"
"github.com/redis/go-redis/v9"
)
type ThumbnailService struct {
robloxClient *roblox.Client
redisClient *redis.Client
cacheTTL time.Duration
}
func NewThumbnailService(robloxClient *roblox.Client, redisClient *redis.Client) *ThumbnailService {
return &ThumbnailService{
robloxClient: robloxClient,
redisClient: redisClient,
cacheTTL: 24 * time.Hour, // Cache thumbnails for 24 hours
}
}
// CachedThumbnail represents a cached thumbnail entry
type CachedThumbnail struct {
ImageURL string `json:"imageUrl"`
State string `json:"state"`
CachedAt time.Time `json:"cachedAt"`
}
// GetAssetThumbnails fetches thumbnails with Redis caching and batching
func (s *ThumbnailService) GetAssetThumbnails(ctx context.Context, assetIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) {
if len(assetIDs) == 0 {
return map[uint64]string{}, nil
}
result := make(map[uint64]string)
var missingIDs []uint64
// Try to get from cache first
for _, assetID := range assetIDs {
cacheKey := fmt.Sprintf("thumbnail:asset:%d:%s", assetID, size)
cached, err := s.redisClient.Get(ctx, cacheKey).Result()
if err == redis.Nil {
// Cache miss
missingIDs = append(missingIDs, assetID)
} else if err != nil {
// Redis error - treat as cache miss
missingIDs = append(missingIDs, assetID)
} else {
// Cache hit
var thumbnail CachedThumbnail
if err := json.Unmarshal([]byte(cached), &thumbnail); err == nil && thumbnail.State == "Completed" {
result[assetID] = thumbnail.ImageURL
} else {
missingIDs = append(missingIDs, assetID)
}
}
}
// If all were cached, return early
if len(missingIDs) == 0 {
return result, nil
}
// Batch fetch missing thumbnails from Roblox API
// Split into batches of 100 (Roblox API limit)
for i := 0; i < len(missingIDs); i += 100 {
end := i + 100
if end > len(missingIDs) {
end = len(missingIDs)
}
batch := missingIDs[i:end]
thumbnails, err := s.robloxClient.GetAssetThumbnails(batch, size, roblox.FormatPng)
if err != nil {
return nil, fmt.Errorf("failed to fetch thumbnails: %w", err)
}
// Process results and cache them
for _, thumb := range thumbnails {
cached := CachedThumbnail{
ImageURL: thumb.ImageURL,
State: thumb.State,
CachedAt: time.Now(),
}
if thumb.State == "Completed" && thumb.ImageURL != "" {
result[thumb.TargetID] = thumb.ImageURL
}
// Cache the result (even if incomplete, to avoid repeated API calls)
cacheKey := fmt.Sprintf("thumbnail:asset:%d:%s", thumb.TargetID, size)
cachedJSON, _ := json.Marshal(cached)
// Use shorter TTL for incomplete thumbnails
ttl := s.cacheTTL
if thumb.State != "Completed" {
ttl = 5 * time.Minute
}
s.redisClient.Set(ctx, cacheKey, cachedJSON, ttl)
}
}
return result, nil
}
// GetUserAvatarThumbnails fetches user avatar thumbnails with Redis caching and batching
func (s *ThumbnailService) GetUserAvatarThumbnails(ctx context.Context, userIDs []uint64, size roblox.ThumbnailSize) (map[uint64]string, error) {
if len(userIDs) == 0 {
return map[uint64]string{}, nil
}
result := make(map[uint64]string)
var missingIDs []uint64
// Try to get from cache first
for _, userID := range userIDs {
cacheKey := fmt.Sprintf("thumbnail:user:%d:%s", userID, size)
cached, err := s.redisClient.Get(ctx, cacheKey).Result()
if err == redis.Nil {
// Cache miss
missingIDs = append(missingIDs, userID)
} else if err != nil {
// Redis error - treat as cache miss
missingIDs = append(missingIDs, userID)
} else {
// Cache hit
var thumbnail CachedThumbnail
if err := json.Unmarshal([]byte(cached), &thumbnail); err == nil && thumbnail.State == "Completed" {
result[userID] = thumbnail.ImageURL
} else {
missingIDs = append(missingIDs, userID)
}
}
}
// If all were cached, return early
if len(missingIDs) == 0 {
return result, nil
}
// Batch fetch missing thumbnails from Roblox API
// Split into batches of 100 (Roblox API limit)
for i := 0; i < len(missingIDs); i += 100 {
end := i + 100
if end > len(missingIDs) {
end = len(missingIDs)
}
batch := missingIDs[i:end]
thumbnails, err := s.robloxClient.GetUserAvatarThumbnails(batch, size, roblox.FormatPng)
if err != nil {
return nil, fmt.Errorf("failed to fetch user thumbnails: %w", err)
}
// Process results and cache them
for _, thumb := range thumbnails {
cached := CachedThumbnail{
ImageURL: thumb.ImageURL,
State: thumb.State,
CachedAt: time.Now(),
}
if thumb.State == "Completed" && thumb.ImageURL != "" {
result[thumb.TargetID] = thumb.ImageURL
}
// Cache the result
cacheKey := fmt.Sprintf("thumbnail:user:%d:%s", thumb.TargetID, size)
cachedJSON, _ := json.Marshal(cached)
// Use shorter TTL for incomplete thumbnails
ttl := s.cacheTTL
if thumb.State != "Completed" {
ttl = 5 * time.Minute
}
s.redisClient.Set(ctx, cacheKey, cachedJSON, ttl)
}
}
return result, nil
}
// GetSingleAssetThumbnail is a convenience method for fetching a single asset thumbnail
func (s *ThumbnailService) GetSingleAssetThumbnail(ctx context.Context, assetID uint64, size roblox.ThumbnailSize) (string, error) {
results, err := s.GetAssetThumbnails(ctx, []uint64{assetID}, size)
if err != nil {
return "", err
}
if url, ok := results[assetID]; ok {
return url, nil
}
return "", fmt.Errorf("thumbnail not available for asset %d", assetID)
}
// GetSingleUserAvatarThumbnail is a convenience method for fetching a single user avatar thumbnail
func (s *ThumbnailService) GetSingleUserAvatarThumbnail(ctx context.Context, userID uint64, size roblox.ThumbnailSize) (string, error) {
results, err := s.GetUserAvatarThumbnails(ctx, []uint64{userID}, size)
if err != nil {
return "", err
}
if url, ok := results[userID]; ok {
return url, nil
}
return "", fmt.Errorf("thumbnail not available for user %d", userID)
}

108
pkg/service/users.go Normal file
View File

@@ -0,0 +1,108 @@
package service
import (
"context"
"encoding/json"
"fmt"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/roblox"
"github.com/redis/go-redis/v9"
)
// CachedUser represents a cached user entry
type CachedUser struct {
Name string `json:"name"`
DisplayName string `json:"displayName"`
CachedAt time.Time `json:"cachedAt"`
}
// GetUsernames fetches usernames with Redis caching and batching
func (s *ThumbnailService) GetUsernames(ctx context.Context, userIDs []uint64) (map[uint64]string, error) {
if len(userIDs) == 0 {
return map[uint64]string{}, nil
}
result := make(map[uint64]string)
var missingIDs []uint64
// Try to get from cache first
for _, userID := range userIDs {
cacheKey := fmt.Sprintf("user:name:%d", userID)
cached, err := s.redisClient.Get(ctx, cacheKey).Result()
if err == redis.Nil {
// Cache miss
missingIDs = append(missingIDs, userID)
} else if err != nil {
// Redis error - treat as cache miss
missingIDs = append(missingIDs, userID)
} else {
// Cache hit
var user CachedUser
if err := json.Unmarshal([]byte(cached), &user); err == nil && user.Name != "" {
result[userID] = user.Name
} else {
missingIDs = append(missingIDs, userID)
}
}
}
// If all were cached, return early
if len(missingIDs) == 0 {
return result, nil
}
// Batch fetch missing usernames from Roblox API
// Split into batches of 100 (Roblox API limit)
for i := 0; i < len(missingIDs); i += 100 {
end := i + 100
if end > len(missingIDs) {
end = len(missingIDs)
}
batch := missingIDs[i:end]
var users []roblox.UserData
var err error
users, err = s.robloxClient.GetUsernames(batch)
if err != nil {
return nil, fmt.Errorf("failed to fetch usernames: %w", err)
}
// Process results and cache them
for _, user := range users {
cached := CachedUser{
Name: user.Name,
DisplayName: user.DisplayName,
CachedAt: time.Now(),
}
if user.Name != "" {
result[user.ID] = user.Name
}
// Cache the result
cacheKey := fmt.Sprintf("user:name:%d", user.ID)
cachedJSON, _ := json.Marshal(cached)
// Cache usernames for a long time (7 days) since they rarely change
s.redisClient.Set(ctx, cacheKey, cachedJSON, 7*24*time.Hour)
}
}
return result, nil
}
// GetSingleUsername is a convenience method for fetching a single username
func (s *ThumbnailService) GetSingleUsername(ctx context.Context, userID uint64) (string, error) {
results, err := s.GetUsernames(ctx, []uint64{userID})
if err != nil {
return "", err
}
if name, ok := results[userID]; ok {
return name, nil
}
return "", fmt.Errorf("username not available for user %d", userID)
}

View File

@@ -1,371 +0,0 @@
package service_internal
import (
"context"
"encoding/json"
"errors"
"fmt"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
var(
// prevent two mapfixes with same asset id
ActiveMapfixStatuses = []model.MapfixStatus{
model.MapfixStatusUploading,
model.MapfixStatusValidated,
model.MapfixStatusValidating,
model.MapfixStatusAcceptedUnvalidated,
model.MapfixStatusChangesRequested,
model.MapfixStatusSubmitted,
model.MapfixStatusUnderConstruction,
}
)
var(
ErrActiveMapfixSameAssetID = errors.New("There is an active mapfix with the same AssetID")
ErrNotAssetOwner = errors.New("You can only submit an asset you own")
)
// UpdateMapfixValidatedModel implements patchMapfixModel operation.
//
// Update model following role restrictions.
//
// POST /mapfixes/{MapfixID}/validated-model
func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
ValidatedModelID := uint64(params.ValidatedModelID)
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("validated_asset_id", ValidatedModelID)
pmap.Add("validated_asset_version", ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// pmap.Add("completed", false)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: ValidatedModelID,
ValidatedModelVersion: ValidatedModelVersion,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeChangeValidatedModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.ActionMapfixSubmittedParams) error {
// transaction
target_status := model.MapfixStatusSubmitted
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("asset_version", params.ModelVersion)
smap.Add("display_name", params.DisplayName)
smap.Add("creator", params.Creator)
smap.Add("game_id", params.GameID)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params internal.ActionMapfixRequestChangesParams) error {
// transaction
target_status := model.MapfixStatusChangesRequested
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
if err != nil {
return err
}
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeError,
EventData: EventData,
})
if err != nil {
return err
}
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionMapfixValidate invokes actionMapfixValidate operation.
//
// Role Validator changes status from Validating -> Validated.
//
// POST /mapfixes/{MapfixID}/status/validator-validated
func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.ActionMapfixValidatedParams) error {
// transaction
smap := datastore.Optional()
smap.Add("status_id", model.MapfixStatusValidated)
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
}
// ActionMapfixAccepted implements actionMapfixAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/validator-failed
func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
// transaction
target_status := model.MapfixStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
if err != nil {
return err
}
//push an error audit event
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeError,
EventData: EventData,
})
if err != nil {
return err
}
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/validator-uploaded
func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
// transaction
target_status := model.MapfixStatusUploaded
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceMapfix,
ResourceID: params.MapfixID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// POST /mapfixes
func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCreate) (*internal.MapfixID, error) {
// sanitization
if request.GameID<0||
request.AssetOwner<0||
request.AssetID<0||
request.AssetVersion<0||
request.TargetAssetID<0{
return nil, ErrNegativeID
}
var GameID=uint32(request.GameID);
var Submitter=uint64(request.AssetOwner);
var AssetID=uint64(request.AssetID);
var AssetVersion=uint64(request.AssetVersion);
var TargetAssetID=uint64(request.TargetAssetID);
// Check if an active mapfix with the same asset id exists
{
filter := datastore.Optional()
filter.Add("asset_id", request.AssetID)
filter.Add("asset_version", request.AssetVersion)
filter.Add("status_id", ActiveMapfixStatuses)
active_mapfixes, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
Number: 1,
Size: 1,
},datastore.ListSortDisabled)
if err != nil {
return nil, err
}
if len(active_mapfixes) != 0{
return nil, ErrActiveMapfixSameAssetID
}
}
operation, err := svc.DB.Operations().Get(ctx, request.OperationID)
if err != nil {
return nil, err
}
// check if user owns asset
// TODO: allow bypass by admin
if operation.Owner != Submitter {
return nil, ErrNotAssetOwner
}
mapfix, err := svc.DB.Mapfixes().Create(ctx, model.Mapfix{
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: GameID,
Submitter: Submitter,
AssetID: AssetID,
AssetVersion: AssetVersion,
Completed: false,
TargetAssetID: TargetAssetID,
StatusID: model.MapfixStatusUnderConstruction,
Description: request.Description,
})
if err != nil {
return nil, err
}
// mark the operation as completed and provide the path
pmap := datastore.Optional()
pmap.Add("status_id", model.OperationStatusCompleted)
pmap.Add("path", fmt.Sprintf("/mapfixes/%d", mapfix.ID))
err = svc.DB.Operations().Update(ctx, request.OperationID, pmap)
if err != nil {
return nil, err
}
return &internal.MapfixID{
MapfixID: mapfix.ID,
}, nil
}

View File

@@ -1,21 +0,0 @@
package service_internal
import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// ActionOperationFailed implements actionOperationFailed operation.
//
// Fail the specified OperationID with a StatusMessage.
//
// POST /operations/{OperationID}/status/operation-failed
func (svc *Service) ActionOperationFailed(ctx context.Context, params internal.ActionOperationFailedParams) (error) {
pmap := datastore.Optional()
pmap.Add("status_id", model.OperationStatusFailed)
pmap.Add("status_message", params.StatusMessage)
return svc.DB.Operations().Update(ctx, params.OperationID, pmap)
}

View File

@@ -1,80 +0,0 @@
package service_internal
import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
func (svc *Service) CreateScriptPolicy(ctx context.Context, req *api.ScriptPolicyCreate) (*api.ScriptPolicyID, error) {
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.ScriptPolicyID{
ScriptPolicyID: script.ID,
}, nil
}
// ListScriptPolicy implements listScriptPolicy operation.
//
// Get list of script policies.
//
// GET /script-policy
func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptPolicyParams) ([]api.ScriptPolicy, error) {
filter := datastore.Optional()
if params.FromScriptHash.IsSet(){
hash, err := model.HashParse(params.FromScriptHash.Value)
if err != nil {
return nil, err
}
filter.Add("from_script_hash", int64(hash)) // No type safety!
}
if params.ToScriptID.IsSet(){
filter.Add("to_script_id", params.ToScriptID.Value)
}
if params.Policy.IsSet(){
filter.Add("policy", params.Policy.Value)
}
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
return nil, err
}
var resp []api.ScriptPolicy
for _, item := range items {
resp = append(resp, api.ScriptPolicy{
ID: item.ID,
FromScriptHash: model.HashFormat(uint64(item.FromScriptHash)),
ToScriptID: item.ToScriptID,
Policy: int32(item.Policy),
})
}
return resp, nil
}

View File

@@ -1,103 +0,0 @@
package service_internal
import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (svc *Service) CreateScript(ctx context.Context, req *api.ScriptCreate) (*api.ScriptID, error) {
script, err := svc.DB.Scripts().Create(ctx, model.Script{
ID: 0,
Name: req.Name,
Hash: int64(model.HashSource(req.Source)),
Source: req.Source,
ResourceType: model.ResourceType(req.ResourceType),
ResourceID: req.ResourceID.Or(0),
})
if err != nil {
return nil, err
}
return &api.ScriptID{
ScriptID: script.ID,
}, nil
}
// ListScripts implements listScripts operation.
//
// Get list of scripts.
//
// GET /scripts
func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParams) ([]api.Script, error) {
filter := datastore.Optional()
if params.Hash.IsSet(){
hash, err := model.HashParse(params.Hash.Value)
if err != nil {
return nil, err
}
filter.Add("hash", int64(hash)) // No type safety!
}
if params.Name.IsSet(){
filter.Add("name", params.Name.Value)
}
if params.Source.IsSet(){
filter.Add("source", params.Source.Value)
}
if params.ResourceType.IsSet(){
filter.Add("resource_type", params.ResourceType.Value)
}
if params.ResourceID.IsSet(){
filter.Add("resource_id", params.ResourceID.Value)
}
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{
Number: params.Page,
Size: params.Limit,
})
if err != nil {
return nil, err
}
var resp []api.Script
for _, item := range items {
resp = append(resp, api.Script{
ID: item.ID,
Hash: model.HashFormat(uint64(item.Hash)),
Source: item.Source,
ResourceType: int32(item.ResourceType),
ResourceID: item.ResourceID,
})
}
return resp, nil
}
// 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) {
script, err := svc.DB.Scripts().Get(ctx, params.ScriptID)
if err != nil {
return nil, err
}
return &api.Script{
ID: script.ID,
Name: script.Name,
Hash: model.HashFormat(uint64(script.Hash)),
Source: script.Source,
ResourceType: int32(script.ResourceType),
ResourceID: script.ResourceID,
}, nil
}

View File

@@ -1,39 +0,0 @@
package service_internal
import (
"context"
"errors"
"math"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"github.com/nats-io/nats.go"
)
const (
ValidtorUserID uint64 = uint64(math.MaxInt64)
)
var (
ErrNegativeID = errors.New("A negative ID was provided")
)
type Service struct {
DB datastore.Datastore
Nats nats.JetStreamContext
}
// yay duplicate code
func (svc *Service) NewError(ctx context.Context, err error) *internal.ErrorStatusCode {
status := 500
if errors.Is(err, datastore.ErrNotExist) {
status = 404
}
return &internal.ErrorStatusCode{
StatusCode: status,
Response: internal.Error{
Code: int64(status),
Message: err.Error(),
},
}
}

View File

@@ -1,403 +0,0 @@
package service_internal
import (
"context"
"encoding/json"
"errors"
"fmt"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
var(
// prevent two mapfixes with same asset id
ActiveSubmissionStatuses = []model.SubmissionStatus{
model.SubmissionStatusUploading,
model.SubmissionStatusValidated,
model.SubmissionStatusValidating,
model.SubmissionStatusAcceptedUnvalidated,
model.SubmissionStatusChangesRequested,
model.SubmissionStatusSubmitted,
model.SubmissionStatusUnderConstruction,
}
)
var(
ErrActiveSubmissionSameAssetID = errors.New("There is an active submission with the same AssetID")
)
// UpdateSubmissionValidatedModel implements patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// POST /submissions/{SubmissionID}/validated-model
func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params internal.UpdateSubmissionValidatedModelParams) error {
ValidatedModelID := uint64(params.ValidatedModelID)
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
// check if Status is ChangesRequested|Submitted|UnderConstruction
pmap := datastore.Optional()
pmap.Add("validated_asset_id", ValidatedModelID)
pmap.Add("validated_asset_version", ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// pmap.Add("completed", false)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
if err != nil {
return err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: ValidatedModelID,
ValidatedModelVersion: ValidatedModelVersion,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeChangeValidatedModel,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /submissions/{SubmissionID}/status/validator-submitted
func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params internal.ActionSubmissionSubmittedParams) error {
// transaction
target_status := model.SubmissionStatusSubmitted
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("asset_version", params.ModelVersion)
smap.Add("display_name", params.DisplayName)
smap.Add("creator", params.Creator)
smap.Add("game_id", params.GameID)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /submissions/{SubmissionID}/status/validator-request-changes
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params internal.ActionSubmissionRequestChangesParams) error {
// transaction
target_status := model.SubmissionStatusChangesRequested
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
if err != nil {
return err
}
//push an error audit event
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeError,
EventData: EventData,
})
if err != nil {
return err
}
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionValidate invokes actionSubmissionValidate operation.
//
// Role Validator changes status from Validating -> Validated.
//
// POST /submissions/{SubmissionID}/status/validator-validated
func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error {
// transaction
target_status := model.SubmissionStatusValidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /submissions/{SubmissionID}/status/validator-failed
func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params internal.ActionSubmissionAcceptedParams) error {
// transaction
target_status := model.SubmissionStatusAcceptedUnvalidated
smap := datastore.Optional()
smap.Add("status_id", target_status)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
if err != nil {
return err
}
//push an error audit event
{
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeError,
EventData: EventData,
})
if err != nil {
return err
}
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /submissions/{SubmissionID}/status/validator-uploaded
func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error {
// transaction
target_status := model.SubmissionStatusUploaded
smap := datastore.Optional()
smap.Add("status_id", target_status)
smap.Add("uploaded_asset_id", params.UploadedAssetID)
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
if err != nil {
return err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
EventData, err := json.Marshal(event_data)
if err != nil {
return err
}
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
ID: 0,
User: ValidtorUserID,
ResourceType: model.ResourceSubmission,
ResourceID: params.SubmissionID,
EventType: model.AuditEventTypeAction,
EventData: EventData,
})
if err != nil {
return err
}
return nil
}
// POST /submissions
func (svc *Service) CreateSubmission(ctx context.Context, request *internal.SubmissionCreate) (*internal.SubmissionID, error) {
// sanitization
if request.GameID<0||
request.AssetOwner<0||
request.AssetID<0||
request.AssetVersion<0{
return nil, ErrNegativeID
}
var GameID=uint32(request.GameID);
var Submitter=uint64(request.AssetOwner);
var AssetID=uint64(request.AssetID);
var AssetVersion=uint64(request.AssetVersion);
var Status=model.SubmissionStatus(request.Status);
var roles=service.Roles(request.Roles);
// Check if an active submission with the same asset id exists
{
filter := datastore.Optional()
filter.Add("asset_id", request.AssetID)
filter.Add("asset_version", request.AssetVersion)
filter.Add("status_id", ActiveSubmissionStatuses)
active_submissions, err := svc.DB.Submissions().List(ctx, filter, model.Page{
Number: 1,
Size: 1,
},datastore.ListSortDisabled)
if err != nil {
return nil, err
}
if len(active_submissions) != 0{
return nil, ErrActiveSubmissionSameAssetID
}
}
operation, err := svc.DB.Operations().Get(ctx, request.OperationID)
if err != nil {
return nil, err
}
// check if user owns asset
is_submitter := operation.Owner == Submitter
// check if user is map admin
has_submission_review := roles & service.RolesSubmissionReview == service.RolesSubmissionReview
// if neither, u not allowed
if !is_submitter && !has_submission_review {
return nil, ErrNotAssetOwner
}
submission, err := svc.DB.Submissions().Create(ctx, model.Submission{
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: GameID,
Submitter: Submitter,
AssetID: AssetID,
AssetVersion: AssetVersion,
Completed: false,
StatusID: Status,
})
if err != nil {
return nil, err
}
// mark the operation as completed and provide the path
pmap := datastore.Optional()
pmap.Add("status_id", model.OperationStatusCompleted)
pmap.Add("path", fmt.Sprintf("/submissions/%d", submission.ID))
err = svc.DB.Operations().Update(ctx, request.OperationID, pmap)
if err != nil {
return nil, err
}
return &internal.SubmissionID{
SubmissionID: submission.ID,
}, nil
}

View File

@@ -0,0 +1,493 @@
package validator_controller
import (
"context"
"errors"
"fmt"
"git.itzana.me/strafesnet/go-grpc/validator"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
type Mapfixes struct {
*validator.UnimplementedValidatorMapfixServiceServer
inner *service.Service
}
func NewMapfixesController(
inner *service.Service,
) Mapfixes {
return Mapfixes{
inner: inner,
}
}
var(
// prevent two mapfixes with same asset id
ActiveMapfixStatuses = []model.MapfixStatus{
model.MapfixStatusReleasing,
model.MapfixStatusUploaded,
model.MapfixStatusUploading,
model.MapfixStatusValidated,
model.MapfixStatusValidating,
model.MapfixStatusAcceptedUnvalidated,
model.MapfixStatusChangesRequested,
model.MapfixStatusSubmitted,
model.MapfixStatusUnderConstruction,
}
)
var(
ErrActiveMapfixSameAssetID = errors.New("There is an active mapfix with the same AssetID")
ErrNotAssetOwner = errors.New("You can only submit an asset you own")
)
// UpdateMapfixValidatedModel implements patchMapfixModel operation.
//
// Update model following role restrictions.
//
// POST /mapfixes/{MapfixID}/validated-model
func (svc *Mapfixes) SetValidatedModel(ctx context.Context, params *validator.ValidatedModelRequest) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// check if Status is ChangesRequested|Submitted|UnderConstruction
update := service.NewMapfixUpdate()
update.SetValidatedAssetID(params.ValidatedModelID)
update.SetValidatedAssetVersion(params.ValidatedModelVersion)
// DO NOT reset completed when validated model is updated
// update.Add("completed", false)
allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
event_data := model.AuditEventDataChangeValidatedModel{
ValidatedModelID: params.ValidatedModelID,
ValidatedModelVersion: params.ValidatedModelVersion,
}
err = svc.inner.CreateAuditEventChangeValidatedModel(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
//
// Role Validator changes status from Submitting -> Submitted.
//
// POST /mapfixes/{MapfixID}/status/validator-submitted
func (svc *Mapfixes) SetStatusSubmitted(ctx context.Context, params *validator.SubmittedRequest) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusSubmitted
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
update.SetAssetVersion(uint64(params.ModelVersion))
update.SetDisplayName(params.DisplayName)
update.SetCreator(params.Creator)
update.SetGameID(uint32(params.GameID))
allow_statuses := []model.MapfixStatus{model.MapfixStatusSubmitting}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
//
// POST /mapfixes/{MapfixID}/status/validator-request-changes
func (svc *Mapfixes) SetStatusRequestChanges(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusChangesRequested
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusSubmitting}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixValidate invokes actionMapfixValidate operation.
//
// Role Validator changes status from Validating -> Validated.
//
// POST /mapfixes/{MapfixID}/status/validator-validated
func (svc *Mapfixes) SetStatusValidated(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
update := service.NewMapfixUpdate()
update.SetStatusID(model.MapfixStatusValidated)
allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixAccepted implements actionMapfixAccepted operation.
//
// (Internal endpoint) Role Validator changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/validator-failed
func (svc *Mapfixes) SetStatusNotValidated(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusAcceptedUnvalidated
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusValidating}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixUploaded implements actionMapfixUploaded operation.
//
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
//
// POST /mapfixes/{MapfixID}/status/validator-uploaded
func (svc *Mapfixes) SetStatusUploaded(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusUploaded
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusUploading}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
func (svc *Mapfixes) SetStatusNotUploaded(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusValidated
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusUploading}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionMapfixReleased implements actionMapfixReleased operation.
//
// (Internal endpoint) Role Validator changes status from Releasing -> Released.
//
// POST /mapfixes/{MapfixID}/status/validator-released
func (svc *Mapfixes) SetStatusReleased(ctx context.Context, params *validator.MapfixReleaseRequest) (*validator.NullResponse, error) {
MapfixID := int64(params.MapfixID)
// transaction
target_status := model.MapfixStatusReleased
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusReleasing}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
// metadata maintenance
map_update := service.NewMapUpdate()
map_update.SetAssetVersion(params.AssetVersion)
map_update.SetModes(params.Modes)
err = svc.inner.UpdateMap(ctx, int64(params.TargetAssetID), map_update)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
func (svc *Mapfixes) SetStatusNotReleased(ctx context.Context, params *validator.MapfixID) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
// transaction
target_status := model.MapfixStatusUploaded
update := service.NewMapfixUpdate()
update.SetStatusID(target_status)
allow_statuses := []model.MapfixStatus{model.MapfixStatusReleasing}
err := svc.inner.UpdateMapfixIfStatus(ctx, MapfixID, allow_statuses, update)
if err != nil {
return nil, err
}
// push an action audit event
event_data := model.AuditEventDataAction{
TargetStatus: uint32(target_status),
}
err = svc.inner.CreateAuditEventAction(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// CreateMapfixAuditError implements createMapfixAuditError operation.
//
// Post an error to the audit log
//
// POST /mapfixes/{MapfixID}/error
func (svc *Mapfixes) CreateAuditError(ctx context.Context, params *validator.AuditErrorRequest) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
event_data := model.AuditEventDataError{
Error: params.ErrorMessage,
}
err := svc.inner.CreateAuditEventError(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// CreateMapfixAuditCheckList implements createMapfixAuditCheckList operation.
//
// Post a checklist to the audit log
//
// POST /mapfixes/{MapfixID}/checklist
func (svc *Mapfixes) CreateAuditChecklist(ctx context.Context, params *validator.AuditChecklistRequest) (*validator.NullResponse, error) {
MapfixID := int64(params.ID)
check_list := make([]model.Check, len(params.CheckList))
for i, check := range params.CheckList {
check_list[i] = model.Check{
Name: check.Name,
Summary: check.Summary,
Passed: check.Passed,
}
}
event_data := model.AuditEventDataCheckList{
CheckList: check_list,
}
err := svc.inner.CreateAuditEventCheckList(
ctx,
model.ValidatorUserID,
model.Resource{
ID: MapfixID,
Type: model.ResourceMapfix,
},
event_data,
)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// POST /mapfixes
func (svc *Mapfixes) Create(ctx context.Context, request *validator.MapfixCreate) (*validator.MapfixID, error) {
var Submitter=request.AssetOwner;
// Check if an active mapfix with the same asset id exists
{
filter := service.NewMapfixFilter()
filter.SetAssetID(request.AssetID)
filter.SetAssetVersion(request.AssetVersion)
filter.SetStatuses(ActiveMapfixStatuses)
active_mapfixes, err := svc.inner.ListMapfixes(ctx, filter, model.Page{
Number: 1,
Size: 1,
},datastore.ListSortDisabled)
if err != nil {
return nil, err
}
if len(active_mapfixes) != 0{
return nil, ErrActiveMapfixSameAssetID
}
}
OperationID := int32(request.OperationID)
operation, err := svc.inner.GetOperation(ctx, OperationID)
if err != nil {
return nil, err
}
// check if user owns asset
// TODO: allow bypass by admin
if operation.Owner != Submitter {
return nil, ErrNotAssetOwner
}
mapfix, err := svc.inner.CreateMapfix(ctx, model.Mapfix{
ID: 0,
DisplayName: request.DisplayName,
Creator: request.Creator,
GameID: request.GameID,
Submitter: Submitter,
AssetID: request.AssetID,
AssetVersion: request.AssetVersion,
Completed: false,
TargetAssetID: request.TargetAssetID,
StatusID: model.MapfixStatusUnderConstruction,
Description: request.Description,
})
if err != nil {
return nil, err
}
// mark the operation as completed and provide the path
params := service.NewOperationCompleteParams(fmt.Sprintf("/mapfixes/%d", mapfix.ID))
err = svc.inner.CompleteOperation(ctx, OperationID, params)
if err != nil {
return nil, err
}
return &validator.MapfixID{
ID: uint64(mapfix.ID),
}, nil
}

View File

@@ -0,0 +1,49 @@
package validator_controller
import (
"context"
"git.itzana.me/strafesnet/go-grpc/validator"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
type Operations struct {
*validator.UnimplementedValidatorOperationServiceServer
inner *service.Service
}
func NewOperationsController(
inner *service.Service,
) Operations {
return Operations{
inner: inner,
}
}
func (svc *Operations) Success(ctx context.Context, params *validator.OperationSuccessRequest) (*validator.NullResponse, error) {
success_params := service.NewOperationCompleteParams(
params.Path,
)
err := svc.inner.CompleteOperation(ctx, int32(params.OperationID), success_params)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}
// ActionOperationFailed implements actionOperationFailed operation.
//
// Fail the specified OperationID with a StatusMessage.
//
// POST /operations/{OperationID}/status/operation-failed
func (svc *Operations) Fail(ctx context.Context, params *validator.OperationFailRequest) (*validator.NullResponse, error) {
fail_params := service.NewOperationFailParams(
params.StatusMessage,
)
err := svc.inner.FailOperation(ctx, int32(params.OperationID), fail_params)
if err != nil {
return nil, err
}
return &validator.NullResponse{}, nil
}

View File

@@ -0,0 +1,89 @@
package validator_controller
import (
"context"
"git.itzana.me/strafesnet/go-grpc/validator"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
type ScriptPolicy struct {
*validator.UnimplementedValidatorScriptPolicyServiceServer
inner *service.Service
}
func NewScriptPolicyController(
inner *service.Service,
) ScriptPolicy {
return ScriptPolicy{
inner: inner,
}
}
// CreateScriptPolicy implements createScriptPolicy operation.
//
// Create a new script policy.
//
// POST /script-policy
func (svc *ScriptPolicy) Create(ctx context.Context, req *validator.ScriptPolicyCreate) (*validator.ScriptPolicyID, error) {
from_script, err := svc.inner.GetScript(ctx, int64(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.inner.CreateScriptPolicy(ctx, model.ScriptPolicy{
ID: 0,
FromScriptHash: from_script.Hash,
ToScriptID: int64(req.ToScriptID),
Policy: model.Policy(req.Policy),
})
if err != nil {
return nil, err
}
return &validator.ScriptPolicyID{
ID: uint64(script.ID),
}, nil
}
// ListScriptPolicy implements listScriptPolicy operation.
//
// Get list of script policies.
//
// GET /script-policy
func (svc *ScriptPolicy) List(ctx context.Context, params *validator.ScriptPolicyListRequest) (*validator.ScriptPolicyListResponse, error) {
filter := service.NewScriptPolicyFilter()
if params.Filter.FromScriptHash != nil {
filter.SetFromScriptHash(int64(*params.Filter.FromScriptHash))
}
if params.Filter.ToScriptID != nil {
filter.SetToScriptID(int64(*params.Filter.ToScriptID))
}
if params.Filter.Policy != nil {
filter.SetPolicy(int32(*params.Filter.Policy))
}
items, err := svc.inner.ListScriptPolicies(ctx, filter, model.Page{
Number: int32(params.Page.Number),
Size: int32(params.Page.Size),
})
if err != nil {
return nil, err
}
resp := validator.ScriptPolicyListResponse{}
resp.ScriptPolicies = make([]*validator.ScriptPolicy, len(items))
for i, item := range items {
resp.ScriptPolicies[i] = &validator.ScriptPolicy{
ID: uint64(item.ID),
FromScriptHash: uint64(item.FromScriptHash),
ToScriptID: uint64(item.ToScriptID),
Policy: validator.Policy(int32(item.Policy)),
}
}
return &resp, nil
}

View File

@@ -0,0 +1,119 @@
package validator_controller
import (
"context"
"git.itzana.me/strafesnet/go-grpc/validator"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/maps-service/pkg/service"
)
type Scripts struct {
*validator.UnimplementedValidatorScriptServiceServer
inner *service.Service
}
func NewScriptsController(
inner *service.Service,
) Scripts {
return Scripts{
inner: inner,
}
}
// CreateScript implements createScript operation.
//
// Create a new script.
//
// POST /scripts
func (svc *Scripts) Create(ctx context.Context, req *validator.ScriptCreate) (*validator.ScriptID, error) {
ResourceID := int64(0)
if req.ResourceID != nil {
ResourceID = int64(*req.ResourceID)
}
script, err := svc.inner.CreateScript(ctx, model.Script{
ID: 0,
Name: req.Name,
Hash: int64(model.HashSource(req.Source)),
Source: req.Source,
ResourceType: model.ResourceType(req.ResourceType),
ResourceID: ResourceID,
})
if err != nil {
return nil, err
}
return &validator.ScriptID{
ID: uint64(script.ID),
}, nil
}
// ListScripts implements listScripts operation.
//
// Get list of scripts.
//
// GET /scripts
func (svc *Scripts) List(ctx context.Context, params *validator.ScriptListRequest) (*validator.ScriptListResponse, error) {
filter := service.NewScriptFilter()
if params.Filter.Hash != nil {
filter.SetHash(int64(*params.Filter.Hash))
}
if params.Filter.Name != nil {
filter.SetName(*params.Filter.Name)
}
if params.Filter.Source != nil {
filter.SetSource(*params.Filter.Source)
}
if params.Filter.ResourceType != nil {
filter.SetResourceType(int32(*params.Filter.ResourceType))
}
if params.Filter.ResourceID != nil {
filter.SetResourceID(int64(*params.Filter.ResourceID))
}
items, err := svc.inner.ListScripts(ctx, filter, model.Page{
Number: int32(params.Page.Number),
Size: int32(params.Page.Size),
})
if err != nil {
return nil, err
}
resp := validator.ScriptListResponse{}
resp.Scripts = make([]*validator.Script, len(items))
for i, item := range items {
resource_id := uint64(item.ResourceID)
resp.Scripts[i] = &validator.Script{
ID: uint64(item.ID),
Name: item.Name,
Hash: uint64(item.Hash),
Source: item.Source,
ResourceType: validator.ResourceType(item.ResourceType),
ResourceID: &resource_id,
}
}
return &resp, nil
}
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
func (svc *Scripts) Get(ctx context.Context, params *validator.ScriptID) (*validator.Script, error) {
ScriptID := int64(params.ID)
script, err := svc.inner.GetScript(ctx, ScriptID)
if err != nil {
return nil, err
}
ResourceID := uint64(script.ResourceID)
return &validator.Script{
ID: uint64(script.ID),
Name: script.Name,
Hash: uint64(script.Hash),
Source: script.Source,
ResourceType: validator.ResourceType(script.ResourceType),
ResourceID: &ResourceID,
}, nil
}

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