Compare commits

..

920 Commits
tidy ... master

Author SHA1 Message Date
9d9ab20952 Merge pull request 'Deploy nudges and action confirmation' (#311) from staging into master
Reviewed-on: StrafesNET/maps-service#311
2025-12-28 02:06:18 +00:00
e41d34dd3d Group buttons and add confirmation dialogues (#310)
Reviewer:
<img width="409" alt="image.png" src="attachments/a090c61e-a2d8-4685-ae64-547851d1ee84">
Submitter:
<img width="404" alt="image.png" src="attachments/9205a438-1f1f-4af4-b9a0-6a8d56580afa">
<img width="411" alt="image.png" src="attachments/7ae8115b-3376-4306-b9b9-acc12226abb3">
Admin:
<img width="392" alt="image.png" src="attachments/07a182d1-5375-4195-bfda-c14f09469cbe">
<img width="388" alt="image.png" src="attachments/ce82017d-5c1d-4a93-9247-9b5608f9030e">

Confirmation Dialogue:
<img width="545" alt="image.png" src="attachments/1efff8be-1d41-429e-8c6e-3d36b7dad128">

Example where both groups show up:
<img width="404" alt="image.png" src="attachments/b0ca4be2-7c58-4c0c-9a5f-dcd89e23b08f">

Reviewed-on: StrafesNET/maps-service#310
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
Co-authored-by: itzaname <me@sliving.io>
Co-committed-by: itzaname <me@sliving.io>
2025-12-28 00:34:58 +00:00
f49e27e230 Support editing map fix descriptions (#309)
The description can be edited by the **submitter** only if the status is Changes Requested or Under Construction.

<img width="734" alt="image.png" src="attachments/9fd7b838-f946-4091-a396-ef66f5e655bc">
<img width="724" alt="image.png" src="attachments/f65f059e-af97-448a-9627-fee827d30e59">

Reviewed-on: StrafesNET/maps-service#309
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 23:40:42 +00:00
d500462fc7 Add user nudges for certain statuses (#308)
Will show a badge icon on the audit tab if there are any validator errors/checklists to direct attention to it. Will show nudge message ONLY to the submitter.

![image.png](/attachments/f5cd9ab6-b996-40b2-ad43-fa5e9b28caf5)
![image.png](/attachments/9aba2132-ec85-4ae9-b0fa-be253ecc2355)

Closes !205

Reviewed-on: StrafesNET/maps-service#308
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 23:30:38 +00:00
ee2bc94312 Add releasing status to the processing list (#307)
Closes !269

Reviewed-on: StrafesNET/maps-service#307
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 22:25:39 +00:00
67ece176c6 Merge pull request 'Deploy script review update' (#306) from staging into master
Reviewed-on: StrafesNET/maps-service#306
2025-12-27 21:49:28 +00:00
84edc71574 Add game name to review page (#305)
Deduped all the game name usage to a single lib. Closes !281

<img width="785" alt="image.png" src="attachments/0f226438-fed1-40b2-81a9-2988dd2d4a33">

Reviewed-on: StrafesNET/maps-service#305
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 19:56:33 +00:00
7c5d8a2163 Add script review page (#304)
Closes !2

Added review dashboard button as well.

<img width="1313" alt="image.png" src="attachments/a2abd430-7ff6-431a-9261-82e026de58f5">

![image.png](/attachments/e1ba3536-2869-4661-b46c-007ddaff8f3e)

Reviewed-on: StrafesNET/maps-service#304
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 19:56:19 +00:00
b31b3bed5f Merge pull request 'Deploy workflow timeline' (#302) from staging into master
Reviewed-on: StrafesNET/maps-service#302
2025-12-27 08:28:42 +00:00
7eaa84a0ed Change Timeline Text (#301)
Some tweaks to the descriptions.  Evidently I didn't read carefully enough.

Reviewed-on: StrafesNET/maps-service#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)
Closes !232

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

Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#294
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
2025-12-27 04:51:03 +00:00
5a1fe60a7b fix quat docker 2025-12-26 19:13:03 -08:00
01cfe67848 Just exclude rejected and released for active list 2025-12-26 20:38:18 -05:00
a19bc4d380 Add mapfix history on maps page 2025-12-26 20:32:55 -05:00
ae006565d6 Merge pull request 'Fix overflow on mapfix/submission' (#293) from fix/overflow into staging
Reviewed-on: StrafesNET/maps-service#293
Reviewed-by: Rhys Lloyd <quaternions@noreply@itzana.me>
2025-12-27 00:44:26 +00:00
57bca99109 Fix overflow 2025-12-26 19:42:36 -05:00
058455efd2 Merge pull request 'Deploy updates' (#291) from staging into master
Reviewed-on: StrafesNET/maps-service#291
2025-12-26 04:46:53 +00:00
cd09c9b18e Populate username for map fixes by author id 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)
Pull in validator changes and full ui rework to remove nextjs.

Co-authored-by: Rhys Lloyd <krakow20@gmail.com>
Reviewed-on: StrafesNET/maps-service#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 2025-12-25 22:10:29 -05:00
f2bb1b078d Fix content width and standardize on skeleton loading 2025-12-25 21:37:23 -05:00
66878fba4e Switch loading text to skeleton 2025-12-25 21:02:15 -05:00
bda99550be Fix submission icon 2025-12-25 21:00:28 -05:00
8a216c7e82 Add username api 2025-12-25 20:55:15 -05:00
e5277c05a1 Avatar image loading 2025-12-25 20:38:17 -05:00
e4af76cfd4 Fix api endpoint 2025-12-25 20:22:24 -05:00
30db1cc375 Fix the build issues 2025-12-25 19:52:01 -05:00
b50c84f8cf Use port 3000 2025-12-25 19:49:52 -05:00
7589ef7df6 Fix dockerfile for spa 2025-12-25 19:49:06 -05:00
8ab8c441b0 Home page and header fixes 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 2025-12-25 18:58:52 -05:00
ca401d4b96 Add batch thumbnail endpoint (#285)
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: StrafesNET/maps-service#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 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 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
Reviewed-on: StrafesNET/maps-service#283
2025-12-06 04:48:21 +00:00
e6ef4e33ac mui 2025-12-05 20:44:16 -08:00
aeba355d6c format 2025-12-05 20:27:02 -08:00
8ad94bcdc8 bug 2025-12-05 20:27:02 -08:00
66f02a2f45 docker: update bun 2025-12-05 20:16:51 -08:00
c6a685310e bun update 2025-12-05 20:14:19 -08:00
72b95ae271 drone: update bun 2025-12-05 20:13:51 -08:00
7c04cc5c23 drone: update rust 2025-11-27 16:36:25 -08:00
a3bf111b4e update deps 2025-11-27 15:56:03 -08:00
d82f44e9d2 remove unused type 2025-11-09 09:30:03 -08:00
4c5a8c39c1 update deps 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 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
Reviewed-on: StrafesNET/maps-service#282
2025-09-29 02:14:51 +00:00
ce9b26378c submissions: Fix Maps.Update Date 2025-09-28 19:09:59 -07:00
df8f6463da bruh 2025-09-23 17:26:03 -07:00
6ccc56cc55 submissions: fix release date mixup 2025-09-23 16:31:50 -07:00
89ab25dfb9 Merge pull request 'deploy fixes' (#279) from staging into master
Reviewed-on: StrafesNET/maps-service#279
2025-09-23 22:41:35 +00:00
ffa1308e73 update deps 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: StrafesNET/maps-service#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 2025-09-23 15:12:20 -07:00
8abee39d15 web: do not show Admin Submit button on mapfixes 2025-09-17 14:24:25 -07:00
b0b5ff0725 Merge pull request 'web: add missing button lost in refactor' (#275) from staging into master
Reviewed-on: StrafesNET/maps-service#275
2025-09-17 00:12:15 +00:00
456b62104b web: add missing button lost in refactor
This was lost in 8f2a0b53e4
2025-09-16 16:56:31 -07:00
574a05424d update readme 2025-08-18 15:54:46 -07:00
0532965d37 Merge pull request 'Maps Metadata Maintenance' (#267) from staging into master
Reviewed-on: StrafesNET/maps-service#267
2025-08-16 06:24:19 +00:00
51ba05df69 backend: remove mapfixes migrate endpoint 2025-08-15 23:20:08 -07:00
30b594b345 backend: fix completely wrong gorm thing 2025-08-15 23:05:40 -07:00
ab361dffd1 backend: fix completely wrong gorm thing 2025-08-15 23:01:37 -07:00
d30a94e42d backend: add mission interface method 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 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 2025-08-15 22:17:54 -07:00
a45aa700d8 make: frontend image builds from scratch 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 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
Reviewed-on: StrafesNET/maps-service#264
2025-08-16 02:47:28 +00:00
55b79b8f9b backend: typo 2025-08-15 19:40:24 -07:00
1ce09e3f9b docker: add env vars to compose.yml 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 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 2025-08-15 18:41:04 -07:00
6ee8816eed submissions-api-rs: add get_mapfixes endpoint 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 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 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 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 2025-08-12 15:48:59 -07:00
63458aee09 Merge pull request 'Update Metadata on Mapfix' (#263) from metadata-maintenance into staging
Reviewed-on: StrafesNET/maps-service#263
2025-08-12 21:56:07 +00:00
8297ed165b readme: document env vars 2025-08-11 17:50:39 -07:00
c98c3fe47e validator: update modes on mapfix 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 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
Reviewed-on: StrafesNET/maps-service#256
2025-08-08 22:07:37 +00:00
295b1d842b Sequential Modes Check (#260)
Closes #242

Reviewed-on: StrafesNET/maps-service#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 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 2025-08-06 20:15:53 -07:00
8a0cd50b68 fix public api 2025-08-06 20:04:33 -07:00
08753d36b4 Cut Down Maps Fields (#257)
Remove usages of Creator & Date, add Thumbnail.

Reviewed-on: StrafesNET/maps-service#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 2025-08-05 23:08:21 -07:00
d196da949c Public API (#253)
Closes #229

This is a MVP and only includes maps.

Reviewed-on: StrafesNET/maps-service#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)
Refactor docker to use makefile build commands

Reviewed-on: StrafesNET/maps-service#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 2025-08-05 22:16:31 -07:00
f9455e7317 validator: update deps 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
Reviewed-on: StrafesNET/maps-service#251
2025-07-28 12:04:50 +00:00
ac05f4acdc submissions: remove migration operation 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
Reviewed-on: StrafesNET/maps-service#250
2025-07-26 03:29:09 +00:00
692c915af8 Merge pull request 'Extend Maps With New Fields' (#249) from webapi-maps into staging
Reviewed-on: StrafesNET/maps-service#249
2025-07-26 02:31:24 +00:00
d35c331b76 submissions: fill out new fields 2025-07-25 19:19:39 -07:00
9ce8b75f0f openapi: generate 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
Reviewed-on: StrafesNET/maps-service#248
2025-07-26 01:26:26 +00:00
2578a74ddb submissions: use unsigned ints in maps struct 2025-07-23 23:18:54 -07:00
45a58145ed Merge pull request 'Fix Null Pointer Deref' (#246) from maps into staging
Reviewed-on: StrafesNET/maps-service#246
2025-07-24 05:21:14 +00:00
a4cefd263d submissions: maps: guard against null pointers 2025-07-23 22:19:42 -07:00
1b18649cb6 Merge pull request 'Implement Maps' (#241) from maps into staging
Reviewed-on: StrafesNET/maps-service#241
2025-07-24 04:29:01 +00:00
bdfd1a0b23 submissions: temporary migration endpoint 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
Reviewed-on: StrafesNET/maps-service#245
2025-07-23 09:32:27 +00:00
76903656c2 Merge pull request 'Change to Proxy Download' (#208) from pr1 into staging
Reviewed-on: StrafesNET/maps-service#208
2025-07-23 09:17:21 +00:00
3e353b2ec6 web: change to proxy download 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
currently unused
2025-07-23 01:54:04 -07:00
e1a2f6f075 Merge pull request 'Fix gRPC' (#244) from staging into master
Reviewed-on: StrafesNET/maps-service#244
2025-07-23 04:53:29 +00:00
70bbba6003 submissions: fix gRPC (the code is completely wrong)
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 2025-07-22 21:30:33 -07:00
1cfdb3668a validator: connect_lazy 2025-07-22 21:01:39 -07:00
dad904cd86 Merge pull request 'Convert Validator API to gRPC' (#239) from staging into master
Reviewed-on: StrafesNET/maps-service#239
2025-07-22 04:32:04 +00:00
740e6368b1 Merge pull request 'Convert Internal API to gRPC' (#238) from grpc into staging
Reviewed-on: StrafesNET/maps-service#238
2025-07-22 02:25:12 +00:00
746ac8e8a7 validator: convert to gRPC 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
Reviewed-on: StrafesNET/maps-service#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 2025-07-17 20:51:03 -07:00
27a646c006 openapi: fix up tags 2025-07-17 19:28:02 -07:00
dde6f3ebdb submissions: rename services 2025-07-17 19:07:59 -07:00
3d08b144b1 submissions: move Roles to model 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)
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: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#234
2025-07-16 06:47:29 +00:00
391a0fe6f9 Maps Data Model (#233)
Create a data model to be used for maps.

Reviewed-on: StrafesNET/maps-service#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)
Unanchored parts are always invalid.  Make a check to detect them.

Reviewed-on: StrafesNET/maps-service#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 2025-07-07 16:33:17 -07:00
70cb80ab9b submissions: order audit events by id ascending 2025-07-05 06:07:50 -07:00
6d0af22485 submissions-api: v0.8.2 derive Hash for ID newtypes 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
Reviewed-on: StrafesNET/maps-service#221
2025-07-01 12:40:26 +00:00
727b823fef update rbx_asset 2025-07-01 04:57:29 -07:00
efefaa5e62 submissions: check rows affected (#220)
Closes #218.

Reviewed-on: StrafesNET/maps-service#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)
Mapfixes should check to see if you already have a mapfix for the target asset upon creation.

Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#217
2025-07-01 08:47:27 +00:00
ca008f8fcf Update Roblox Api (#216)
Same api different language

Reviewed-on: StrafesNET/maps-service#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)
Roblox api changed, see 9f1bdd6a1f

Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#214
2025-06-30 10:20:03 +00:00
a31a92f131 Merge pull request 'submissions: check role for map location' (#213) from pr2 into staging
Reviewed-on: StrafesNET/maps-service#213
2025-06-30 09:46:50 +00:00
a5187be8a6 submissions: check role for map location 2025-06-30 02:42:19 -07:00
825b2aa91a Clickable titles and show active mapfix (#211)
Closes #144

Co-authored-by: ic3w0lf <bob@ic3.space>
Reviewed-on: StrafesNET/maps-service#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)
Co-authored-by: ic3w0lf <bob@ic3.space>
Reviewed-on: StrafesNET/maps-service#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 2025-06-24 05:07:03 -07:00
dc446c545f Fix Bypass Submit + Audit Checklist + Map Download Button (#207)
Reviewed-on: StrafesNET/maps-service#207
2025-06-24 06:41:56 +00:00
e234a87d05 Replace Bypass Submit With Submit Unchecked + Error Endpoint (#200)
Reviewed-on: StrafesNET/maps-service#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)"
This reverts commit abd233ce65.
2025-06-23 23:34:58 -07:00
976adf2b66 Move Download Button Below Title (#206)
Senior itzaname envisioned the button existing elsewhere.

Reviewed-on: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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 2025-06-18 03:55:03 -07:00
42cc783887 validation: fixups 2025-06-13 22:04:25 -07:00
ed7109270f Audit Event CheckList (#181)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
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: StrafesNET/maps-service#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)
Reviewed-on: StrafesNET/maps-service#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)
Also uses enums over ints for GameID.

Reviewed-on: StrafesNET/maps-service#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)
Reviewed-on: StrafesNET/maps-service#193
2025-06-10 23:53:07 +00:00
d7c2ad3dde submissions: actually fix script names (#192)
Actually closes #165.

Reviewed-on: StrafesNET/maps-service#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)
Closes #165.

Reviewed-on: StrafesNET/maps-service#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)
- 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) StrafesNET/maps-service#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: StrafesNET/maps-service#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)
Closes #187.

Reviewed-on: StrafesNET/maps-service#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)
Reviewed-on: StrafesNET/maps-service#185
2025-06-09 01:09:17 +00:00
b60d2b6186 Submissions: Fix Comments (#184)
Closes #163.

Reviewed-on: StrafesNET/maps-service#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)
Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#179
2025-06-08 05:49:11 +00:00
7b3af95f3d Merge pull request 'Remove class_is_a' (#178) from pr1 into staging
Reviewed-on: StrafesNET/maps-service#178
2025-06-08 05:48:55 +00:00
4d78a9b2c5 submissions: add missing audit even when requesting changes for a mapfix 2025-06-07 22:42:39 -07:00
ec59a83379 validation: include more details in duplicates error 2025-06-07 22:34:57 -07:00
54bf3f55a0 Rework submission/mapfix/maps list views (#173)
Refactored maps/landing/mapfix/submission and navbar

Reviewed-on: StrafesNET/maps-service#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
Reviewed-on: StrafesNET/maps-service#177
Reviewed-by: itzaname <itzaname@noreply@itzana.me>
2025-06-08 00:21:21 +00:00
0e1d2fe50a openapi: generate 2025-06-07 17:09:51 -07:00
ada8c322da openapi: add descriptions to enum fields 2025-06-07 17:07:47 -07:00
84d2bfef20 remove class_is_a 2025-06-07 16:29:06 -07:00
170e7c64b6 Merge pull request 'submissions-api: add external delete endpoints' (#166) from pr1 into staging
Reviewed-on: StrafesNET/maps-service#166
2025-06-07 05:38:30 +00:00
b443866dd6 Merge pull request 'update deps' (#169) from deps into staging
Reviewed-on: StrafesNET/maps-service#169
2025-06-07 05:35:45 +00:00
ebe37ad6a2 update deps 2025-06-06 22:29:35 -07:00
131dad7ae0 submissions-api: v0.7.2 script policy delete endpoints 2025-06-06 22:28:07 -07:00
7689001e74 Merge pull request '404 / 500 Thumbnails + Fix Regex Capture Groups' (#168) from staging into master
Reviewed-on: StrafesNET/maps-service#168
2025-06-07 04:02:26 +00:00
127402fa77 Merge pull request 'fix regex capture groups' (#167) from pr2 into staging
Reviewed-on: StrafesNET/maps-service#167
2025-06-07 03:58:16 +00:00
40f83a4e30 fix regex capture groups 2025-06-06 20:52:17 -07:00
b6d4ce4f80 submissions-api: add external delete endpoints 2025-06-06 17:14:27 -07:00
07391a84cb Merge pull request 'thumbnail fix - will this WORK THIS TIME?' (#154) from thumbnail-fix-1 into staging
Reviewed-on: StrafesNET/maps-service#154
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
2025-06-06 02:51:35 +00:00
ic3w0lf
3f848a35c8 implement cache de-exister 2025-06-05 17:42:34 -06:00
e89abed3d5 Merge pull request 'Thumbnail Fixes + Bypass Submit Button' (#161) from staging into master
Reviewed-on: StrafesNET/maps-service#161
2025-06-05 01:34:35 +00:00
e5e2387502 Merge pull request 'Refactor MapChecks Summary' (#160) from summary into staging
Reviewed-on: StrafesNET/maps-service#160
2025-06-05 01:25:56 +00:00
90d13d28ae use closure instead of iterator 2025-06-04 18:18:18 -07:00
513b9722b1 Merge pull request 'Add Bypass Submit Button' (#159) from force-submit into staging
Reviewed-on: StrafesNET/maps-service#159
2025-06-05 00:56:37 +00:00
3da8e414e6 submissions: fix comment 2025-06-04 17:53:21 -07:00
2acc30e18c submissions: add bypass-submit 2025-06-04 17:53:13 -07:00
a990ed458c submissions: optimize trigger-submit 2025-06-04 17:41:40 -07:00
4055ef550e openapi: generate 2025-06-04 17:32:44 -07:00
555844e6ee openapi: bypass-submit endpoints 2025-06-04 17:30:10 -07:00
80f30d20fa web: introduce Force Submit button 2025-06-04 17:28:51 -07:00
489a8c9c10 web: rename force submit to admin submit 2025-06-04 17:22:53 -07:00
534598ba70 box list to appease clippy 2025-06-04 17:13:33 -07:00
fdc0240698 MapCheckSummary 2025-06-04 17:05:38 -07:00
b0829bc1fc refactor WormholeID 2025-06-04 14:52:19 -07:00
845f8e69d9 refactor ModeID 2025-06-04 14:52:19 -07:00
0d8937e896 refactor SpawnID 2025-06-04 14:46:30 -07:00
2927afd848 Merge pull request 'web: use invalid id for submit to invoke error' (#155) from empty-submit into staging
Reviewed-on: StrafesNET/maps-service#155
2025-06-04 05:32:34 +00:00
8f6c543f81 Merge pull request 'validation: log errors' (#156) from log into staging
Reviewed-on: StrafesNET/maps-service#156
2025-06-04 05:09:57 +00:00
7c95f8ddd0 validation: log errors 2025-06-03 22:07:39 -07:00
24964407bd web: use invalid id for submit to invoke error 2025-06-03 21:55:19 -07:00
ic3w0lf
8d5bd9e523 Fix error & include error message in response headers 2025-06-03 20:52:43 -06:00
ic3w0lf
e1fc637619 Implement errorImageResponse 2025-06-03 20:42:37 -06:00
ic3w0lf
762ee874a0 thumbnail fix - will this WORK THIS TIME? 2025-06-03 20:03:09 -06:00
a1c84ff225 Merge pull request 'web: fix api middleware' (#153) from pr1 into staging
Reviewed-on: StrafesNET/maps-service#153
2025-06-04 01:45:36 +00:00
cea6242dd7 web: fix api middleware 2025-06-03 18:42:21 -07:00
fefe116611 Merge pull request 'Allow Submitter Comments' (#151) from submitter-can-comment into staging
Reviewed-on: StrafesNET/maps-service#151
2025-06-04 00:19:35 +00:00
0ada77421f fix bug 2025-06-03 17:17:59 -07:00
fa2d611534 submissions: allow submitter special permission to comment on their posts
Previously only map council could comment.
2025-06-03 17:11:53 -07:00
81539a606c Merge pull request 'API_HOST changes, thumbnail fix & cache, "list is empty" fix' (#150) from thumbnail-fix into staging
Reviewed-on: StrafesNET/maps-service#150
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
2025-06-03 23:54:13 +00:00
32095296c2 Merge branch 'staging' into thumbnail-fix 2025-06-03 23:53:55 +00:00
8ea5ee2d41 use null instead of sentinel value 2025-06-03 16:29:29 -07:00
954dbaeac6 env var name change requires deployment configuration change 2025-06-03 16:27:42 -07:00
5b7efa2426 Merge pull request 'Add a favicon (#141)' (#149) from aidan9382/maps-service:favicon into staging
Reviewed-on: StrafesNET/maps-service#149
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
2025-06-03 23:16:38 +00:00
ic3w0lf
740e3c8932 API_HOST changes, thumbnail fix & cache, "list is empty" fix
API_HOST was replaced in order for thumbnail/any redirects to work properly, this also assumes the API will be at `{BASE_URL}/api`, assuming the reverse proxy causes issues with the way redirects were initially setup to work.

Also no more "Submissions list is empty." while it's loading.
2025-06-03 15:58:33 -06:00
4f31f8c75a Add a favicon (#141) 2025-06-03 22:32:43 +01:00
b792d33164 Merge pull request 'Update Rust Dependencies (Roblox Format Zstd Support)' (#142) from staging into master
Reviewed-on: StrafesNET/maps-service#142
2025-06-01 23:13:58 +00:00
d39a8c0208 submissions-api v0.7.1 make error type smaller 2025-05-14 00:50:34 -07:00
636282b993 submissions-api: make error type smaller 2025-05-14 00:50:34 -07:00
e3667fec0c validation: refactor some goofy roblox functions 2025-05-14 00:50:34 -07:00
0dff464561 validation: checks: write many documentation 2025-05-14 00:50:34 -07:00
e30fb5f916 validation: checks: named dummy types for readability 2025-05-14 00:50:34 -07:00
9dd7156f38 validation: avoid passing large struct in Err 2025-05-14 00:50:34 -07:00
fc9aae4235 submissions-api: appease clippy 2025-05-14 00:50:34 -07:00
a11a0d2fd5 validation: clippy fixes 2025-05-14 00:50:34 -07:00
9dad1a6b4d validation: update deps 2025-05-14 00:50:34 -07:00
929b5949f0 Merge pull request 'Snapshot "Working" Code' (#139) from staging into master
Reviewed-on: StrafesNET/maps-service#139
2025-04-27 21:21:05 +00:00
a95e6b7a9a docker: add AUTH_HOST env var to docker compose 2025-04-15 18:55:34 -07:00
ic3w0lf
4c1aef9113 Update README 2025-04-15 18:57:35 -06:00
ic3w0lf
c98d170423 Remove hardcoded auth URLs 2025-04-15 18:50:40 -06:00
6d14047f57 web: unused imports 2025-04-15 16:49:05 -07:00
41663624d3 web: conditionally show avatar when logged in 2025-04-15 16:49:05 -07:00
49b9b41085 web: create login button 2025-04-15 16:20:52 -07:00
3614018794 web: remove redirect 2025-04-15 16:20:48 -07:00
872b98aa74 web: explain admin buttons a bit better 2025-04-15 15:56:52 -07:00
d5c8477869 web: const enum typescript xD 2025-04-15 15:45:16 -07:00
b600ca582b web: show submit button for admin on ChangesRequested status 2025-04-15 15:45:16 -07:00
adbcbed9ac submissions: allow admin to submit from changes requested 2025-04-15 15:45:16 -07:00
8f8d685f71 validator: plumb fields 2025-04-15 15:45:16 -07:00
a669de3c0b submissions: allow bypass by admin in internal CreateSubmission 2025-04-15 15:45:16 -07:00
649b941d5f submissions: implement CreateSubmissionAdmin endpoint 2025-04-15 15:45:16 -07:00
1b4456f30a submissions: add initial fields 2025-04-15 15:31:55 -07:00
d34a5c7091 openapi: generate 2025-04-15 15:13:53 -07:00
2f36877cb6 openapi: admin create endpoint 2025-04-15 15:13:44 -07:00
3a124b8190 web: add hidden admin submit page 2025-04-15 14:23:25 -07:00
6cc6da4879 web: display username in audit events 2025-04-15 12:46:35 -07:00
123b0c9a81 web: add Username field to AuditEvent 2025-04-15 12:43:36 -07:00
54b0abbbf3 web: tweak submit button text 2025-04-13 17:16:55 -07:00
1b0384da11 submissions: fetch usernames from data service 2025-04-13 17:14:44 -07:00
e0cebfd80e submissions: rename svc.Client to svc.Maps 2025-04-13 17:14:21 -07:00
5ba52ecb57 openapi: generate 2025-04-13 17:02:31 -07:00
9e42050a65 openapi: include usernames in AuditEvent 2025-04-13 17:02:28 -07:00
c817bfc8c8 validator: flatten check matches 2025-04-13 16:33:23 -07:00
8f97ca6690 validator: tweak error message 2025-04-12 21:01:23 -07:00
f220cb62bc validator: fix empty check 2025-04-12 12:31:05 -07:00
f090fd7d68 validator: fix duplicate checks 2025-04-12 12:29:17 -07:00
404e1281ff validator: improve "extra" error messages 2025-04-12 12:02:34 -07:00
e4f710c83f validator: include original names of some objects in error message 2025-04-12 11:58:27 -07:00
a942c81ea8 validator: add teleport and wormhole set difference checks 2025-04-12 11:39:25 -07:00
109b24061a validator: pluralize some error messages 2025-04-12 11:33:32 -07:00
ddef30984f validator: remove placeholder comments 2025-04-11 23:42:43 -07:00
9331f37d70 validator: remove explicit StringEmptyCheck newtype 2025-04-11 23:20:48 -07:00
c4f910c1f0 validator: comment ModelInfo::check 2025-04-11 23:11:59 -07:00
343a4011dd validator: tweak write_zone macro 2025-04-11 23:06:10 -07:00
c63997d161 validator: implement dangling anticheat zone check 2025-04-11 22:59:37 -07:00
ea58fcedc9 validator: save some loc with default 2025-04-11 22:30:55 -07:00
50e3fb283c validator: comment ModelInfo::check 2025-04-11 22:25:49 -07:00
aa513a7973 validator: code tweaks 2025-04-11 22:20:59 -07:00
eff9097456 validator: remove newline 2025-04-11 21:59:37 -07:00
668c5fef51 validator: move function call so get_model_info is infallible 2025-04-11 21:46:44 -07:00
57db5f738e todo 2025-04-11 21:03:57 -07:00
3789755a19 submissions: add updated info to validator-submitted 2025-04-11 21:01:58 -07:00
ee6c37ab9d openapi: generate 2025-04-11 21:01:58 -07:00
12bfbfb0a0 openapi: add updated info to validator-submitted 2025-04-11 21:01:58 -07:00
c57a53692d validator: code tweaks 2025-04-11 21:01:58 -07:00
ccf07c5931 validator: rename AtLeastOneMatchingAndNoExtraCheck to SetDifferenceCheck 2025-04-11 20:37:37 -07:00
6efab4f411 validator: annotate MapCheck fields 2025-04-11 20:19:49 -07:00
34d1db02a5 web: implement audit log on submissions 2025-04-11 19:36:54 -07:00
d86ed0cdf5 web: marginally improve audit events 2025-04-11 19:27:25 -07:00
d19763349e web: fetch audit events and generate comments 2025-04-11 19:03:01 -07:00
5846e92924 validator: write check error message 2025-04-11 18:03:45 -07:00
34b8d7475d validator: rustify map check 2025-04-11 17:55:59 -07:00
a5daa2df4a validator: update metadata on Submitted 2025-04-11 17:38:21 -07:00
1b73af9fe2 validator: allow create without valid metadata 2025-04-11 17:38:21 -07:00
8433030562 web: add submission fields 2025-04-11 17:38:21 -07:00
8372665fd3 submissions: fields plumbing 2025-04-11 17:38:21 -07:00
d24b342738 openapi: generate 2025-04-11 13:11:51 -07:00
796f31aadf openapi: add fields to submission create 2025-04-11 13:08:22 -07:00
44f8736838 web: add description on mapfix page 2025-04-11 13:04:52 -07:00
b7e5d82c13 web: add description form field 2025-04-11 13:04:52 -07:00
169007f16e validator: description plumbing 2025-04-11 13:04:52 -07:00
2519c9faa1 submissions: description plumbing 2025-04-11 13:04:52 -07:00
1ff6bdbd4c openapi: generate 2025-04-11 13:00:10 -07:00
d1ca9bdab9 openapi: add Description to mapfix create 2025-04-11 12:59:42 -07:00
c76ff3b687 validation: use to_string instead of format 2025-04-11 01:51:32 +00:00
a42501d254 submissions-api: change StatusMessage to ErrorMessage 2025-04-11 01:51:32 +00:00
f915c51ba4 web: remove StatusMessage 2025-04-11 01:51:32 +00:00
ff9da333eb submissions: push audit error event on error endpoints 2025-04-11 01:51:32 +00:00
1dabd216aa openapi: generate 2025-04-11 01:51:32 +00:00
cc7e890580 openapi: change StatusMessage to ErrorMessage 2025-04-11 01:51:32 +00:00
99d1b38535 submissions: remove StatusMessage 2025-04-11 01:51:32 +00:00
12ca1b7dab submissions: AuditEventTypeError 2025-04-11 01:51:32 +00:00
fa1b44f172 update deps 2025-04-10 17:21:45 -07:00
03519e9337 validator: marginally improve map check clarity 2025-04-09 21:04:51 -07:00
60b6d30379 validator: fix map check bug 2025-04-09 20:53:25 -07:00
19b8f7b7a2 validator: use newlines in check report 2025-04-09 20:37:58 -07:00
4f586c6176 web: add reset submit button 2025-04-09 19:55:38 -07:00
d1a70509b7 submissions: implement map checks 2025-04-09 19:50:17 -07:00
95bfb87c6e validator: implement map checks 2025-04-09 19:50:17 -07:00
de0cf37918 validator: add heck + lazy_regex deps 2025-04-09 19:48:44 -07:00
f1fd826c62 submissions-api: implement validator-submitted endpoint 2025-04-09 19:48:44 -07:00
1380a00872 submissions: receive asset version 2025-04-09 19:39:13 -07:00
174a210f81 submissions: implement validator-request-changes endpoints 2025-04-09 19:39:13 -07:00
67a03f394f openapi: generate 2025-04-09 19:39:13 -07:00
6eebe404d5 openapi: validator-request-changes endpoint 2025-04-09 19:39:13 -07:00
1d409218a5 validation: factor out asset download 2025-04-09 19:39:13 -07:00
e2c72c90c7 validator: prepare for checks 2025-04-08 17:06:54 -07:00
7334e88b55 validation: update api to yield a better error 2025-04-08 16:56:48 -07:00
b93c813dec submissions: fix faulty endpoints 2025-04-08 16:40:39 -07:00
926a90329b submissions-api: v0.7.0 2025-04-08 14:22:55 -07:00
18abbd92ce web: implement trigger-submit + transpose weakly associated action list 2025-04-08 13:45:53 -07:00
c923a8a076 submissions: implement validator-submitted endpoint 2025-04-08 13:21:07 -07:00
d6da6f003e submissions: implement reset-submitting endpoint 2025-04-08 13:17:39 -07:00
0dc7aec395 submissions: rename endpoints 2025-04-08 13:12:13 -07:00
c85cb63639 openapi: generate 2025-04-08 13:06:35 -07:00
6c865e8841 openapi: prepare for map checks 2025-04-08 13:06:26 -07:00
99a082afb5 submisions: improve error precision 2025-04-08 12:56:07 -07:00
434cd295f5 submissions: implement audit endpoints 2025-04-08 12:49:16 -07:00
bfc2a2cbca openapi: generate 2025-04-08 12:41:56 -07:00
c24db2c3a0 openapi: allow listing 0 items 2025-04-08 12:41:16 -07:00
68f2311658 openapi: audit endpoints 2025-04-08 12:41:15 -07:00
163412a253 openapi: extend api StatusID maximum to match changes 2025-04-08 00:01:07 -07:00
044033cabf submissions: implement audit logging
- use uint for Operation.Owner
- remove IsSubmitter
2025-04-07 20:29:32 -07:00
219a15f656 submissions: audit events db table 2025-04-07 20:29:29 -07:00
383bc783a4 submissions: audit model 2025-04-07 20:29:29 -07:00
24a5baae77 web: todo: hide Reset buttons for 10 seconds 2025-04-07 13:35:41 -07:00
4ba3b5cd01 web: change up status ids 2025-04-07 13:35:41 -07:00
f610fc1c0f submissions: change up status ids in preparation of submission validation 2025-04-07 13:35:41 -07:00
e67d679901 submissions: rename mapfix const to match submissions 2025-04-07 13:10:24 -07:00
3c3d09c4a7 web: display target asset thumbnail alongside mapfix 2025-04-06 16:09:00 -07:00
d02e3776f3 web: fix page dots 2025-04-06 15:50:08 -07:00
77222c84db web: plumb target asset id and submitter 2025-04-06 15:48:37 -07:00
412f34817c submissions: more filtering options for listing submissions 2025-04-06 15:31:45 -07:00
cac288d73b openapi: generate 2025-04-06 15:29:50 -07:00
29e414d6e7 openapi: more filtering options for listing submissions 2025-04-06 15:29:27 -07:00
c9ba2e3e6e web: use date descending sort 2025-04-06 15:15:31 -07:00
0666685a49 web: implement new list api with Total field for pages 2025-04-06 15:15:19 -07:00
ff9237e453 submissions: count total items 2025-04-06 15:13:27 -07:00
9b5f7e0b0c openapi: generate 2025-04-06 15:13:24 -07:00
e28c7e8149 openapi: include total count in list requests 2025-04-06 15:13:20 -07:00
220ea84e22 submissions: AddNotNil is for pointers 2025-04-05 19:36:36 -07:00
7648f407c5 openapi: generate 2025-04-05 19:27:55 -07:00
e0266c5d24 openapi: set minimum for all integers, maximum for some 2025-04-05 19:27:44 -07:00
9ab2e23fa9 submissions: do not allow changing model after submit 2025-04-05 19:00:08 -07:00
6b2f5e29e7 api: improve consistency with internal api 2025-04-05 18:56:39 -07:00
d42e89fcb4 submissions: switch to unsigned integers in database and nats messages 2025-04-05 17:26:35 -07:00
7e881e6ac5 submissions: omit user info check 2025-04-05 17:12:19 -07:00
2d57b945f2 submissions: what??? how did this ever work? 2025-04-05 17:11:10 -07:00
005e99424e validator: update rbx_asset to fix model info download 2025-04-05 14:54:26 -07:00
a330b1c43b validator: update rbx_asset api 2025-04-05 14:39:42 -07:00
d2662eb833 validator: switch to cloud api where possible 2025-04-05 14:39:42 -07:00
3ba599114d validator: relax read_dom trait bound 2025-04-05 14:39:42 -07:00
d53f61fb5b submissions: fix operations CountSince (#99)
Reviewed-on: StrafesNET/maps-service#99
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-04-05 19:41:42 +00:00
5d259e20f2 submissions: rate limit submit 2025-04-04 20:08:48 -07:00
21b6903943 submissions: count recent operations 2025-04-04 20:07:09 -07:00
14c7979310 web: activate ai dark mode 2025-04-04 19:33:48 -07:00
e376e02dc1 web: ai the maps page 2025-04-04 19:33:38 -07:00
4e7ee9dc5a rename "Accepted" status to "AcceptedUnvalidated" 2025-04-04 19:04:48 -07:00
ceaec14242 submissions-api: fix validated-model request 2025-04-04 18:41:33 -07:00
9372caa157 web: fix mapfix thumbnails 2025-04-04 17:11:41 -07:00
f73c274367 web: move _map to _mapImage 2025-04-04 17:11:32 -07:00
c50a28443e web: remove ratings 2025-04-04 17:02:51 -07:00
c7150f1e23 web: fix mapfixes cards linking to submissions 2025-04-04 17:02:51 -07:00
f16a817da2 web: maps: format date 2025-04-04 16:26:37 -07:00
e858d252ab web: add map image to map page 2025-04-04 16:13:22 -07:00
66e0d22ccd web: add bare bones map info 2025-04-04 15:56:18 -07:00
986ecfc7ad docker: use tagged muslrust 2025-04-04 15:42:43 -07:00
66890ccd44 validation: detect nats filter_subject mismatch and update consumer 2025-04-04 15:36:52 -07:00
ec15c1f2e5 Hide Irrelevant Review Buttons (#86)
Closes #17.

Reviewed-on: StrafesNET/maps-service#86
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-04-04 22:10:31 +00:00
8be9475ee5 web: route to provided path on operation success 2025-04-03 20:03:48 -07:00
0cb2bec6e0 web: fix mapfix submit 2025-04-03 19:24:43 -07:00
cf1906acaa web: fix mapfix href 2025-04-04 02:10:44 +00:00
7e93807298 docker: use itzaname docker proxy to avoid getting rate-limited 2025-04-03 19:05:15 -07:00
ee5b3331b4 validator: write correct asset version 2025-04-03 16:18:31 -07:00
29c0acf3b2 web: add fix map button 2025-04-03 15:47:44 -07:00
a844c4e90a validation: skip upload if model validates as-is 2025-04-03 15:36:06 -07:00
5ed15a6847 validation: rename error 2025-04-03 15:25:02 -07:00
1ff1cae709 web: reduce polling interval
The operations will usually take half a second.
2025-04-03 15:12:18 -07:00
ic3w0lf
c6ebe5a360 stop polling on completeion/fail 2025-04-03 15:45:59 -06:00
15dd6b4178 web: tweak header + add maps link 2025-04-03 14:22:39 -07:00
ca1676db00 validation: catch final error 2025-04-03 14:01:40 -07:00
56681f8862 submissions: mark operation as completed 2025-04-03 14:01:39 -07:00
fe2c20bd72 openapi: generate 2025-04-03 14:01:39 -07:00
027a55661b openapi: be consistent 2025-04-03 14:01:39 -07:00
a3d644f572 validator: use different endpoints to fill in the submission details 2025-04-03 14:01:39 -07:00
d0634fc141 validator: update rbx_asset 2025-04-03 14:01:39 -07:00
719ef95b6d submissions-api: use explicit ID types 2025-04-03 18:17:25 +00:00
c9041168e5 submissions: use explicit ID types 2025-04-03 18:17:25 +00:00
1e012af52e openapi: generate 2025-04-03 18:17:25 +00:00
54b4cf2d13 openapi: make explicit types for returned IDs 2025-04-03 18:17:25 +00:00
ic3w0lf
91ac3a5e36 Operation Page 2025-04-03 18:03:11 +00:00
ic3w0lf
fc5519e744 bad code 2025-04-03 04:46:44 -06:00
170e194ac9 web: use client 2025-04-03 08:00:59 +00:00
liquidwater0
739c9354a6 turn maps page into client component 2025-04-03 08:00:59 +00:00
73f559f049 web: useParams 2025-04-03 08:00:59 +00:00
liquidwater0
3f377f4605 log the error 2025-04-03 08:00:59 +00:00
liquidwater0
edc1ed5459 maybe fix build errors 2025-04-03 08:00:59 +00:00
c9212a5ec8 drone: do not attempt to deploy pull requests 2025-04-03 00:46:13 -07:00
liquidwater0
adaa088efe add routes for maps page 2025-04-03 00:57:04 -05:00
e85e3f130f web: add mapfixes link to header 2025-04-02 21:13:27 -07:00
0462788c53 validator: report operation failure 2025-04-03 03:44:32 +00:00
2c31a9585b submissions-api: add operation failed endpoint 2025-04-03 03:44:32 +00:00
3699ce5cbb validator: implement create operations 2025-04-03 03:44:32 +00:00
8776936e96 submissions-api: add create internal endpoints 2025-04-03 03:44:32 +00:00
e466af7d27 validator: rename errors 2025-04-03 03:44:32 +00:00
abed5c6227 validator: refactor again 2025-04-03 03:44:32 +00:00
a639b81988 submissions: implement operation failed internal endpoint 2025-04-03 03:44:32 +00:00
5aa27c08a5 openapi: generate 2025-04-03 03:44:32 +00:00
577ab5cdd0 openapi: internal operation failed endpoint 2025-04-03 03:44:32 +00:00
a72be13843 submissions: deny mapfix targeting nonexistent map 2025-04-03 03:44:32 +00:00
d4e8edbb6e submissions: implement internal submission create 2025-04-03 03:44:32 +00:00
19c4e36990 submissions: trigger validator to create submissions & mapfixes 2025-04-03 03:44:32 +00:00
56dec20189 openapi: generate 2025-04-03 03:44:32 +00:00
34d37d8c1c openapi: move create endpoints to internal 2025-04-03 03:44:32 +00:00
508d41506a submissions: naively implement operations 2025-04-03 03:44:32 +00:00
493c6d084a openapi: generate 2025-04-03 03:44:32 +00:00
722ac5178f openapi: long-running operations 2025-04-03 03:44:32 +00:00
df39101102 web: remove all fields from submission forms except Asset ID 2025-04-03 03:44:32 +00:00
e877ba4788 Merge pull request 'Change the map thumbnails to use the roblox api' (#64) from thumbnails into staging
Reviewed-on: StrafesNET/maps-service#64
Reviewed-by: Quaternions <quaternions@noreply@itzana.me>
2025-04-03 03:33:18 +00:00
ic3w0lf
8a28d6cfcf model/user thumbnails 2025-04-02 21:20:30 -06:00
e9f79241f1 submissions: maps endpoints 2025-04-01 16:52:55 -07:00
bfd287f3cc openapi: generate 2025-04-01 16:46:18 -07:00
082c573ffb openapi: maps endpoints 2025-04-01 16:45:55 -07:00
3bda4803aa submissions: refine roles 2025-04-01 16:21:48 -07:00
c401d24366 submissions: fix mapfixes auto migrate 2025-04-01 15:27:05 -07:00
a119c4292e web: change submit text to match mapfix submit page 2025-04-01 15:07:25 -07:00
4cf7889db9 web: add submit page at /maps/[mapId]/fix 2025-04-01 15:07:25 -07:00
146d627534 web: mapfixes: rename all occurrences of submission with mapfix 2025-04-01 14:45:21 -07:00
97180ab263 web: clone submissions page for mapfixes 2025-04-01 14:44:42 -07:00
37560ac5d2 submissions: reintroduce mapfix fields 2025-04-01 14:34:23 -07:00
de8f869b5b openapi: generate 2025-04-01 14:34:23 -07:00
b6ae600a93 openapi: reintroduce mapfix fields 2025-04-01 14:34:20 -07:00
96ace736f4 validator: add mapfix capability 2025-04-01 13:51:40 -07:00
9dd7a41d8f submissions-api: add simple mapfixes endpoints 2025-04-01 13:51:40 -07:00
cc7df064be submissions-api: deduplicate simple endpoints with crazy macro 2025-04-01 13:51:37 -07:00
732598266c submissions: mapfixes 2025-04-01 13:44:42 -07:00
6d420c3a82 openapi: generate 2025-04-01 13:44:06 -07:00
2e65d071e0 openapi: mapfixes 2025-04-01 13:43:59 -07:00
e36b49a31e submissions: datastore: duplicate submissions as mapfixes 2025-04-01 13:34:23 -07:00
1d7f6ea79a nats: rename types 2025-04-01 13:33:23 -07:00
b0f1e42a06 web: fix SubmissionInfo type 2025-03-31 19:57:48 -07:00
8925d71bcd submissions: fix compile 2025-03-31 19:42:57 -07:00
8de5bcba68 openapi: generate 2025-03-31 19:34:05 -07:00
a048d713da openapi: missing fields 2025-03-31 19:33:28 -07:00
581c65594d openapi: generate 2025-03-31 19:31:05 -07:00
4e22933e34 openapi: fix /scripts endpoint 2025-03-31 19:31:05 -07:00
758c2254eb submissions-api: create new error variant 2025-03-31 19:23:59 -07:00
ade54ee662 validator: refactor + remove mapfix capability 2025-03-31 19:23:59 -07:00
01785bb190 validator: move files 2025-03-31 18:14:08 -07:00
8366b84d90 submissions: tweak script data model 2025-03-31 18:13:31 -07:00
746c7aa9b7 openapi: generate 2025-03-31 18:09:50 -07:00
930eb47096 openapi: tweak script data model 2025-03-31 18:09:25 -07:00
9671c357f4 submissions: ruin script data model 2025-03-31 18:06:39 -07:00
3404251c14 nats: rename events 2025-03-31 16:51:36 -07:00
ffcba57408 validation: tweak validator-uploaded endpoint 2025-03-31 16:27:42 -07:00
a60ccd22f0 submissions: remove prints 2025-03-31 16:27:42 -07:00
f7d7a0891d submissions: tweak validator-uploaded endpoint 2025-03-31 16:27:42 -07:00
e5e85db1fd openapi-internal: generate 2025-03-31 16:27:42 -07:00
0b64440975 openapi-internal: tweak validator-uploaded endpoint 2025-03-31 16:27:42 -07:00
0e29ca98dd web: remove TargetAssetID 2025-03-31 16:27:42 -07:00
9740cbe91a openapi: generate 2025-03-31 16:27:42 -07:00
2d2691b551 openapi: tweak Submission fields 2025-03-31 16:27:42 -07:00
dfc2a605f4 submissions: prepare for separate mapfixes 2025-03-31 16:27:42 -07:00
88c3866654 Revert "submissions: add AcceptedBy, UploadedBy fields to model"
This reverts commit 4c17a3c9e9.
2025-03-31 14:39:06 -07:00
92226e768d submissions: allow map council to upload maps 2025-03-28 23:57:34 -07:00
4515eb6da2 submissions: typo in error variable names 2025-03-28 23:55:07 -07:00
f2d8c49647 submissions: move pipeline restriction to accept rather than create 2025-03-28 19:10:29 -07:00
2c75cfa67f submissions: remove StatusUploaded from ActiveSubmissionStatuses 2025-03-28 19:00:26 -07:00
f3689f4916 rename part 2: rename all occurrences of "publish" to "upload" 2025-03-28 15:56:47 -07:00
e855ace229 rename part 1: move files 2025-03-28 15:56:47 -07:00
6e21447d4b validation: update deps 2025-03-28 15:56:47 -07:00
49fea314ec submissions: log accepter and uploader 2025-03-28 22:34:51 +00:00
4c17a3c9e9 submissions: add AcceptedBy, UploadedBy fields to model 2025-03-28 22:34:51 +00:00
a7784bdaf5 web: fix api types 2025-03-28 18:26:59 -04:00
f0e18a5963 web: Validate button calls retry-validate endpoint 2025-03-28 15:07:07 -07:00
661fa17fa7 submissions: implement ActionSubmissionRetryValidate 2025-03-28 15:01:22 -07:00
cc1d5f4bda submissions: remove Accepted from valid src status in ActionSubmissionTriggerValidate 2025-03-28 15:01:09 -07:00
e7a66ebe0d openapi: generate 2025-03-28 14:48:48 -07:00
977f3902b7 openapi: split trigger-validate into two cases 2025-03-28 14:48:27 -07:00
af9f413b49 validation: refactor get_partial_path 2025-03-27 22:53:39 +00:00
b02b3d205e Switch to using /api/session/validate for determining if the user is not logged in (#34)
My apologies for being stupid not knowing the NextJS framework fully, as I have little experience with it and its non intuitive SSR and CSR workflow

Code successfully built locally running `bun run build`

Reviewed-on: StrafesNET/maps-service#34
Co-authored-by: rhpidfyre <brandon@rhpidfyre.io>
Co-committed-by: rhpidfyre <brandon@rhpidfyre.io>
2025-03-27 21:47:03 +00:00
2f2241612a openapi: generate 2025-03-26 20:53:25 -07:00
a7c72163eb openapi: user session is required for SessionValidate 2025-03-26 20:53:02 -07:00
c8077482f3 submissions: do not validate session in HandleCookieAuth 2025-03-26 20:53:02 -07:00
79c21b62d8 openapi: generate 2025-03-26 20:17:03 -07:00
032f0e8739 openapi: opt out of security for get requests 2025-03-26 20:16:44 -07:00
251a24efae web: Revert auth redirect 2025-03-26 17:23:21 -07:00
a9afdf38cf web: auth redirect fix 2025-03-26 16:27:32 -07:00
d3edb6b3da validation: include script path in ScriptFlaggedIllegalKeyword 2025-03-26 16:23:44 -07:00
188fbd2a6d submissions: rename VersionID to ValidatedModelVersion 2025-03-26 15:41:46 -07:00
1468a9edc2 openapi: generate 2025-03-26 15:41:19 -07:00
1053719eab openapi: rename field 2025-03-26 15:40:57 -07:00
2867da4b21 submissions: detect sentinel value 2025-03-26 15:33:47 -07:00
85a144e276 submissions-api: v0.6.1 2025-03-26 14:58:28 -07:00
4227f18992 validator: name model correctly 2025-03-26 21:30:12 +00:00
123bc8af47 validator: write and use tragic script name function 2025-03-26 21:30:12 +00:00
cd82954b73 validator: refactor errors to improve information and clarity 2025-03-26 21:30:12 +00:00
ce08b57e18 submissions-api: include get_scripts & get_script_from_hash in internal api 2025-03-26 21:30:12 +00:00
1ca0348924 submissions-api: derive Clone, Debug on many types 2025-03-26 21:30:12 +00:00
936a1f93aa web: use --turbopack for dev 2025-03-26 21:29:07 +00:00
d5d0e5ffc9 web: redirect if the user is not logged in based on session_id cookie's presence 2025-03-26 21:29:07 +00:00
039309c75a submissions: include status message 2025-03-26 13:08:56 -07:00
7cc0b5da7f openapi: generate 2025-03-26 13:08:41 -07:00
f0c44fb4a8 openapi: include status message 2025-03-26 13:08:22 -07:00
4fec1bba47 validation: do not implicitly append url 2025-03-26 12:53:35 -07:00
5ae287f3f2 docker: fix API_HOST 2025-03-26 12:46:54 -07:00
bf6c8af21a docker: add group id env var 2025-03-26 12:34:27 -07:00
65e63431a3 docker: use staging auth image 2025-03-26 12:26:37 -07:00
a8dc6cd35a submissions: introduce new role SubmissionRelease 2025-03-26 12:07:06 -07:00
539e09fe06 validator: correct enum item name 2025-03-26 12:07:06 -07:00
87fd7adb93 submissions: rename SubmissionPublish to SubmissionUpload 2025-03-26 12:07:06 -07:00
7d57d1ac4d submissions: improve error granularity 2025-03-26 12:07:06 -07:00
636bb1fb94 submissions: fix roles bug 2025-03-25 19:42:39 -07:00
295ec3cd8b submissions: refactor UserInfoHandle.GetRoles 2025-03-25 19:32:48 -07:00
6af006f802 fix docker compose 2025-03-25 19:27:26 -07:00
d16bb8ad02 submissions: refactor roles again 2025-03-25 18:07:37 -07:00
1af7d7e941 submissions: implement session endpoints 2025-03-25 17:53:50 -07:00
1feca92f7d submissions: add UserInfoHandle.Validate 2025-03-25 17:44:49 -07:00
7213948a26 submissions: add UserInfoHandle.GetUserInfo function 2025-03-25 17:44:49 -07:00
783d0e843c submissions: refactor roles 2025-03-25 17:44:13 -07:00
977d1d20c2 submissions: rename UserInfo to UserInfoHandle 2025-03-25 17:44:13 -07:00
d7634de9ec openapi: generate 2025-03-25 17:44:13 -07:00
8da1c9346b openapi: add session endpoints 2025-03-25 17:44:08 -07:00
894851c0e8 openapi: fix operation summary 2025-03-25 16:35:50 -07:00
3da4023466 web: throw error on failure status (#16)
Thanks to ai for knowing javascript

Co-authored-by: rhpidfyre <brandon@rhpidfyre.io>
Reviewed-on: StrafesNET/maps-service#16
Co-authored-by: Quaternions <krakow20@gmail.com>
Co-committed-by: Quaternions <krakow20@gmail.com>
2025-03-24 23:03:53 +00:00
08a4e913a9 Enable auto deploy 2025-03-23 19:13:36 -04:00
6748cb4324 submissions: submitter cannot accept their own submission 2025-03-19 18:12:18 -07:00
73e5c76e75 submissions: reject reset unless validator is stale 2025-03-19 18:05:50 -07:00
b4be174d98 web: implement reset from softlock 2025-03-19 17:49:26 -07:00
f52e0a91a2 openapi: generate 2025-03-19 17:43:17 -07:00
0b1e7085e3 openapi: implement reset from softlock 2025-03-19 17:42:38 -07:00
31f1db6446 submissions: implement reset from softlock 2025-03-19 17:38:40 -07:00
b377405762 web: display validation error 2025-03-18 16:45:41 -07:00
b496f8c0d8 submissions-api: v0.6.0 2025-03-18 16:13:10 -07:00
0c247fbb43 submissions-api: add status message to validation failure 2025-03-18 16:12:42 -07:00
483ffd1d66 submissions: add StatusMessage to submissions 2025-03-18 16:06:47 -07:00
ff01abdd63 openapi: generate 2025-03-18 16:05:02 -07:00
0271ba4d28 openapi: add status message to validation failure 2025-03-18 16:04:28 -07:00
c6b31b7c73 submissions: tweak group roles to allow developers proper staging permissions 2025-03-18 15:12:10 -07:00
80e7d735be openapi: generate 2025-03-18 14:47:19 -07:00
e66513e88d Revert "openapi: no security for get submission requests"
This reverts commit 11e801443f.
2025-03-18 14:47:05 -07:00
355161c3b1 submissions: publish validated model 2025-03-18 14:26:19 -07:00
e5a1dcf144 submissions-api: v0.5.0 2025-03-18 14:20:21 -07:00
99e320d17f submissions-api: validated-model 2025-03-18 14:19:12 -07:00
57d714fdd7 submissions: implement internal validated model 2025-03-18 14:17:18 -07:00
d77bf02185 openapi: generate 2025-03-18 14:16:48 -07:00
47129e2d1f openapi: internal operation updates validated model 2025-03-18 14:16:16 -07:00
b542dba739 submissions: add ValidatedModelID to submissions model 2025-03-18 14:16:16 -07:00
f5c4868dc4 validation: v0.1.1 2025-03-18 13:33:01 -07:00
1341f87bf8 submissions-api: v0.4.0 2025-03-18 13:33:01 -07:00
57544f3f64 submissions-api: external is default usage 2025-03-18 13:32:28 -07:00
ecb88c14a4 validation: explicitly append url (TODO: update deployment env var) 2025-03-18 13:23:48 -07:00
e1645e7c46 validation: use cargo workspace 2025-03-18 12:37:20 -07:00
49e767f027 web: note when submissions list is loaded but empty 2025-03-18 12:32:48 -07:00
91a72ccf8b openapi: generate 2025-03-18 12:08:56 -07:00
11e801443f openapi: no security for get submission requests 2025-03-18 12:08:56 -07:00
8338a71470 submissions: modernize loops 2025-03-18 12:08:56 -07:00
59e5e529c6 Strip /api prefix 2025-03-17 20:25:02 -04:00
a82a78c938 middleware: oops, thats the wrong path 2025-03-16 20:38:49 -04:00
b6c7c76900 document the middleware 2025-03-16 16:42:44 -04:00
75e8d2b7b2 middleware 2025-03-16 16:33:16 -04:00
8dbdfbdb3f document environment variables 2025-03-16 12:11:07 -07:00
28990e2dbe submissions: implement sort functionality for listSubmissions 2025-01-13 20:34:04 -08:00
a39e2892ef openapi: generate 2025-01-13 05:01:04 -08:00
8e223d432e openapi: add sort parameter to listSubmissions 2025-01-13 05:00:51 -08:00
ic3w0lf
040488d85f small changes 2025-01-13 04:31:33 -07:00
e43f4bd0f0 openapi-internal: remove unused endpoint 2025-01-02 18:33:38 -08:00
ca1e007b07 docker: update compose 2024-12-30 20:11:09 -08:00
952ceab014 submissions: ReleaseSubmissions operation 2024-12-30 20:11:09 -08:00
952b77b3db submissions: connect to maps grpc 2024-12-30 20:11:09 -08:00
0794e7ba46 openapi: generate 2024-12-30 19:16:58 -08:00
bc8b7b68d2 openapi: add release-submissions endpoint 2024-12-30 19:14:49 -08:00
c04ba33f9c submissions: reject duplicate submissions
closes #6
2024-12-28 17:20:27 -08:00
c95d10a0d4 web: submit GameID 2024-12-27 18:50:36 -08:00
94abe3137b web: submit TargetAssetID 2024-12-27 18:50:24 -08:00
78db4eeba7 web: display model id 2024-12-27 18:31:49 -08:00
56ff5670dd web: fix status codes 2024-12-27 18:24:54 -08:00
d584ee2c03 web: submit page navigates to newly created submission 2024-12-27 18:14:02 -08:00
f629ac2998 web: submission page reload after action request completes 2024-12-27 18:00:26 -08:00
07ef22bc02 submissions: limit active submissions to 20 2024-12-27 17:42:29 -08:00
8bf2c92df3 submissions: refactor auth to only make requests when needed 2024-12-27 17:25:18 -08:00
0d549a46d4 TEMP: validation: force model upload to prevent model validation bait and switch 2024-12-27 16:48:41 -08:00
1b58bfd096 web: describe when each button should be visible 2024-12-26 18:28:26 -08:00
cd57ead995 web: remove maptest button 2024-12-26 18:18:59 -08:00
c085ea9b7d submissions: implement ScriptWrite permission 2024-12-26 17:54:42 -08:00
25dbc038ca submissions-api: incorrectly named field 2024-12-26 17:46:45 -08:00
f038b9cda6 submissions-api: wrong url 2024-12-26 17:41:05 -08:00
8b3aa158c9 submissions-api: lazily export other error to avoid importing reqwest elsewhere 2024-12-21 22:39:59 -08:00
a45b4f2f0c validation: flag illegal keywords 2024-12-21 21:08:03 -08:00
ca846972c1 submissions-api: openapi expects optional fields to be omitted
The default serde configuration is to serialize optional values as "null"
2024-12-19 17:48:58 -08:00
a511246d78 bruh 2024-12-19 17:23:46 -08:00
f04ab4f653 submissions: postgres does not support unsigned integers, so let's pretend they are signed 2024-12-19 17:23:46 -08:00
b3ffbe4b50 submissions-api: fix cookie 2024-12-19 16:27:11 -08:00
a7e9dbb94d web: fix up
When possible you should not use inline styling and instead use SCSS files for following convention and keeping consistency, Grid is also a deprecated React component in Material UI
You should also separate components that are client only to its own .tsx module rather than having it be mixed with components that aren't required for being client only
2024-12-19 02:30:45 -05:00
ic3w0lf
b0b16c91dc compilable:) 2024-12-18 22:55:12 -07:00
ic3w0lf
9bd3eb69f9 Huge mess 2024-12-18 22:12:15 -07:00
02d77ab421 submissions-api: v0.3.0 refactor 2024-12-18 19:12:06 -08:00
8dbb4517fa submissions-api: silence lint 2024-12-18 19:12:06 -08:00
b782b1ae64 submissions-api: add eq to select types 2024-12-18 18:57:52 -08:00
246b8a7dc8 validation: update api 2024-12-18 17:01:12 -08:00
621edbdbe0 submissions: normalize get from hash as list requests 2024-12-18 15:46:37 -08:00
516bd7a439 openapi: generate 2024-12-18 15:06:42 -08:00
6a8805b91a openapi: normalize get policy from hash as list request 2024-12-18 15:06:42 -08:00
518327820d submissions-api: reintroduce external api 2024-12-18 14:28:11 -08:00
964fc24e26 submissions-api: optional cookie 2024-12-18 14:28:11 -08:00
a94ae5d61e submissions: flatten list query params 2024-12-17 21:39:04 -08:00
76d36bea5c openapi: generate 2024-12-17 21:36:40 -08:00
88dfc92bc6 openapi: flatten list query parameters 2024-12-17 21:36:22 -08:00
e905d96917 submissions: fix list requests 2024-12-17 21:03:39 -08:00
b238e4c21d submissions: update openapi 2024-12-17 20:51:34 -08:00
1d3e553390 openapi: generate 2024-12-17 20:50:25 -08:00
6545fa703d openapi: make pagination match game-rpc 2024-12-17 20:50:02 -08:00
a28ec58ce8 openapi: generate 2024-12-17 20:42:31 -08:00
fe0a1e0e0f openapi: remove required ID field on Filter schemas 2024-12-17 20:42:15 -08:00
9070d77f41 validation: set status on failure 2024-12-17 20:32:10 -08:00
0dc39121c8 submissions-api: need stupid dependency to do this 2024-12-17 20:32:10 -08:00
3ea881e724 docker: .dockerignore 2024-12-17 20:32:10 -08:00
6064a1e48f submissions-api: hardcode header to application/json 2024-12-17 20:32:10 -08:00
e7234a614d submissions-api: use goofy function to make errors include more information 2024-12-17 20:08:14 -08:00
299f994f32 openapi: generate 2024-12-17 20:08:14 -08:00
49db6e35ce openapi: no minimum length for script names 2024-12-17 20:08:14 -08:00
185a1d147f sumbissions: return correct http error code 2024-12-17 20:08:14 -08:00
b5bb79c6ef docker: internal only + path copy 2024-12-17 20:08:14 -08:00
f7101e2b84 validation: api is internal only 2024-12-17 20:08:14 -08:00
f3af65aa13 validation: use path 2024-12-17 18:29:47 -08:00
833ed66844 validation: subsume submissions-api 2024-12-17 18:29:14 -08:00
67651633d8 submissions: UpdateSubmissionModel internal endpoint
not quite duplicate code, hooray
2024-12-17 18:26:32 -08:00
7a7e158ec3 submissions: legendary code duplication 2024-12-17 18:23:18 -08:00
7ad4ffc7e0 openapi: generate 2024-12-17 18:23:18 -08:00
e46f9fc6ea openapi: legendary levels of duplicate code 2024-12-17 18:23:18 -08:00
2ad219cf77 submissions: tweak comments 2024-12-17 18:23:00 -08:00
9bdf98635e submissions: comment on unclear status name 2024-12-17 18:10:40 -08:00
3a6dd311bf submissions: wrong query 2024-12-17 17:12:06 -08:00
298a68fa97 submissions: fix unhandled error path causing silent failure 2024-12-17 16:15:33 -08:00
6bab1e1b6b submissions: centralize hashing and formatting 2024-12-17 15:57:39 -08:00
8c45736cf4 validation: fix hash formatting 2024-12-17 15:57:39 -08:00
db52b1dcd4 scripts: name property 2024-12-17 15:45:09 -08:00
f4abc30c21 submissions: return 404 when ErrNotExist 2024-12-17 15:45:06 -08:00
332578ec94 validation: upload new scripts 2024-12-17 15:45:06 -08:00
64e9e2b263 docker: use staging cookie and group 2024-12-17 15:45:00 -08:00
ffadaa44be web: review buttons are no longer hard-coded for submission id 1 2024-12-17 18:31:59 -05:00
9a7270d2f9 submissions: chatgpt solution #2 2024-12-15 03:20:52 -08:00
cb736628d7 validation: plumb group id into publish functions 2024-12-15 02:31:28 -08:00
ec414a0f42 submissions-api: v0.2.2 wrong url in action_submission_uploaded 2024-12-15 02:10:31 -08:00
2342981643 submissions: fix null pointer deref 2024-12-15 01:50:41 -08:00
3cfcbff253 submissions: chatgpt solution 2024-12-15 01:47:43 -08:00
ce59d7c947 submissions-api: v0.2.1 feature flag for external 2024-12-15 01:41:13 -08:00
ed68af80b0 docker: rename stuff for no reason 2024-12-15 01:41:13 -08:00
11846c32e6 docker: use env file because env var is broken 2024-12-15 01:05:51 -08:00
ecbd102aef docker: split internal & external api 2024-12-15 01:05:51 -08:00
cf1fdb4099 submissions-api-rs: v0.2.0 split internal & external 2024-12-15 01:05:51 -08:00
33d272ab04 nats: edit PublishNewRequest message 2024-12-15 01:05:51 -08:00
75d8cafc7b web: change buttons 2024-12-15 01:05:51 -08:00
7d2147779a submissions-api: v0.1.1 2024-12-15 01:05:51 -08:00
7e940cdfb1 submissions: update ActionSubmissionUploaded 2024-12-15 01:05:51 -08:00
47c30ad2db openapi-internal: optionally change TargetAssetID on upload 2024-12-15 01:05:51 -08:00
29b77f14de roles: potential future roles 2024-12-15 01:05:51 -08:00
9e022ca265 submissions: refactor publishing model 2024-12-15 01:05:51 -08:00
95675c51e6 openapi: generate 2024-12-15 00:07:09 -08:00
7a30dc4ec3 openapi: public endpoints use cookieAuth by default 2024-12-15 00:07:01 -08:00
cd9bb17370 openapi: move internal functions to separate api spec 2024-12-15 00:07:01 -08:00
4ce5d5e535 validation: pull out submissions api 2024-12-14 11:18:25 -08:00
1450c0f3a2 validation: remove map publishing 2024-12-14 04:02:34 -08:00
76abcf0a34 validation: fs unneeded 2024-12-14 03:17:34 -08:00
d4303612ac web: material ui form inputs on the submission page, "Target" radio buttons 2024-12-14 03:25:04 -05:00
5e5caae6c3 Add drone ci 2024-12-14 02:14:19 -05:00
673152bc0d openapi: list filter belongs in request body 2024-12-13 22:54:22 -08:00
203ae67384 web: maybe /submit instead of /submission_new 2024-12-14 01:53:44 -05:00
e31dec6424 web: form page base concept 2024-12-14 01:49:36 -05:00
00fdbd9611 openapi: GET /script-policy endpoint to list script policies 2024-12-13 22:15:05 -08:00
346f49610d script review: introduce None policy 2024-12-13 21:50:19 -08:00
ae6e968135 web: remove Roblox.ts 2024-12-14 00:37:52 -05:00
dff37906c6 web: reorder status buttons 2024-12-13 21:22:23 -08:00
50911af656 web: fix proxy 2024-12-13 21:22:23 -08:00
1243203085 web: do not overwrite existing cookie 2024-12-13 21:22:23 -08:00
7ae2775c3f docker: pass through environment variable 2024-12-13 21:05:33 -08:00
fcd74b54cc validation: fix writer 2024-12-13 21:05:33 -08:00
b090a80f03 validation: update deps 2024-12-13 21:05:33 -08:00
3a6a62fb7c nats: periods and underscores are forbidden and cause silent failure 2024-12-13 21:05:33 -08:00
3739ff011e docker: silence authrpc container logging 2024-12-13 21:05:33 -08:00
046d95c5b3 web: change hardcoded dev address 2024-12-13 21:05:33 -08:00
090c794c24 docker: use images instead of build 2024-12-13 21:05:33 -08:00
4373ca4ba9 validation: print payload 2024-12-12 19:27:39 -08:00
f77dd14ac9 validation: parallel request processing 2024-12-12 19:27:39 -08:00
727e358cf9 validation: connect to nats and grpc concurrently 2024-12-12 17:52:43 -08:00
8250686477 validation: refactor to use a single consumer 2024-12-12 17:52:43 -08:00
1f96b5facb validation: incorrect nats assumption 2024-12-12 16:58:16 -08:00
22086e772c validation: listen for sigkill 2024-12-12 16:58:16 -08:00
c99608aaff docker: add all 8 services to single compose file 2024-12-12 16:50:48 -08:00
fdc1f1aadf Unquatification 2024-12-12 17:29:20 -05:00
3c0028f308 web: working Container file 2024-12-12 14:24:07 -08:00
a2c6981d36 web: proxy the dev port 3000 to 8081 for api calls 2024-12-12 14:24:07 -08:00
d37cc9cdf2 CSS variables for coloring 2024-12-12 14:24:07 -08:00
0eaf9aa164 docker: fix validation 2024-12-12 14:24:07 -08:00
d37964764e docker: fix maps-service 2024-12-12 14:24:07 -08:00
55b5516782 docker: secrets! 2024-12-12 13:52:25 -08:00
4c5d9e420d validation: fix cargo chef 2024-12-12 12:51:44 -08:00
dee563e12a update docker stuff 2024-12-12 12:29:15 -08:00
5ef2de6f50 validation: add strafesnet registry 2024-12-12 12:29:12 -08:00
95e9b4d8b3 nats: work queue policy 2024-12-11 23:02:59 -08:00
eea57786ff nats: use subjects 2024-12-11 21:08:04 -08:00
64d6fe6059 validation: consumers are not durable 2024-12-11 21:07:57 -08:00
7f1054d509 maps-service: nats jetstream 2024-12-11 19:56:09 -08:00
ecaff95ca7 validation: nats jetstream 2024-12-11 19:55:16 -08:00
7c2e8f00ad web: custom action per review button 2024-12-11 18:11:36 -08:00
1a747bee80 openapi: rename unclear endpoints 2024-12-11 18:11:36 -08:00
a9a4eaa20d validation: implement publish_fix 2024-12-11 18:11:36 -08:00
796935da86 validation: implement publish_new 2024-12-11 17:45:38 -08:00
6677a698be plumb game id 2024-12-11 17:45:38 -08:00
aea340fe97 Submission buttons working? 2024-12-11 19:07:54 -05:00
2a04efb10b change error message to make more sense 2024-12-11 15:39:10 -08:00
119bb79a88 Update readme for web 2024-12-11 18:36:47 -05:00
c630b44ad3 Containerfile for web 2024-12-11 17:07:15 -05:00
bc5b84d447 buttons exist for making api requests 2024-12-11 03:30:55 -05:00
89fda96e7a implicitly assume validator endpoints are authorized 2024-12-10 22:32:56 -08:00
803223d331 validation: fix url 2024-12-10 22:29:15 -08:00
dad5a40a09 validation: fix method 2024-12-10 22:28:52 -08:00
88056344f4 openapi: generate 2024-12-10 22:23:08 -08:00
0bc8eeffb3 openapi: set http return code according to standard 2024-12-10 22:22:37 -08:00
afa78a1260 openapi: implement cookie auth only on select requests 2024-12-10 22:22:12 -08:00
590627870a implement some basic status codes for errors 2024-12-10 21:49:03 -08:00
ca5c67cb4b check rows affected to see if anything happened 2024-12-10 21:38:12 -08:00
e3360a6c6b the gorm way 2024-12-10 21:31:18 -08:00
1975f3ea4a validation: mtls is handled at a higher level 2024-12-10 21:25:53 -08:00
03e71f09fc validation: golang public fields must be upper case gg 2024-12-10 20:25:40 -08:00
1d545f4413 explicitly specify the port for bun run start 2024-12-10 23:17:58 -05:00
2e379f7077 successfully builds for production 2024-12-10 23:01:22 -05:00
6ce2cd799f update README for web 2024-12-10 22:59:13 -05:00
305f18adb3 send nats
dunk on golang
2024-12-10 19:27:15 -08:00
e185712da5 nasty 2024-12-10 19:25:21 -08:00
3e58d75b87 userids and asset ids are uint64 2024-12-10 19:25:21 -08:00
b49ae10a10 fix roles 2024-12-10 18:23:23 -08:00
24e88c5a0a validation: change error enum names to be more descriptive 2024-12-10 17:47:17 -08:00
c029939ee2 validation: use environment variables 2024-12-10 17:39:08 -08:00
dedbdb2899 validation: silence "unused" code lint 2024-12-10 17:38:47 -08:00
1324fa106f validation: use incremental model version id 2024-12-10 17:38:21 -08:00
f110d82402 docker compose 2024-12-10 17:03:18 -08:00
cf488101a0 add eslint + update nextjs to remove a library deprecation warning on dev start
* requires running `bun install` again, or `bun update`
2024-12-10 17:55:16 -05:00
fbc183f408 change the routing from DOMAIN/map/[map_name] to DOMAIN/submissions/[submission_id] 2024-12-10 17:53:57 -05:00
1a5f58a3b1 map page now builds and heavily refactored
+ Handle no commenters by displaying the message "There are no commenters."
+ Text fallback: "Fetching map image..."
+ Handle the validation status message (still has no css coloring for 80% of the statuses)
- Disable the roblox api for fetching the asset image and avatar headshot images, but keep the module
2024-12-10 03:54:19 -05:00
37e4e29f04 use gorm model 2024-12-09 22:27:52 -08:00
69047eacb0 update golang side 2024-12-09 22:09:52 -08:00
ccb9c17e7f openapi: generate 2024-12-09 22:07:43 -08:00
7b343fc686 openapi: deduplicate parameter ids 2024-12-09 22:05:47 -08:00
7aaa89b69b openapi: change patch to post 2024-12-09 21:57:35 -08:00
3cc1c8a5d9 openapi: limit string lengths for user facing objects 2024-12-09 21:48:52 -08:00
04520edca7 fix IfStatusThenUpdate 2024-12-09 21:38:27 -08:00
fe3562325f fix user info 2024-12-09 21:38:27 -08:00
b3ba9c2301 openapi: unused 2024-12-09 21:38:27 -08:00
1c0ed6574f openapi: remove redundant SubmissionType 2024-12-09 20:51:00 -08:00
576c3a187a produce less garbage 2024-12-09 20:10:36 -08:00
e495a8423f openapi: try session_id 2024-12-09 20:10:36 -08:00
fb6b0ad7c7 cli flag for auth rpc host 2024-12-09 19:33:01 -08:00
8c3e9cf9ea remove empty readme and tweak .gitignore, next.config.ts, and package.json 2024-12-09 22:24:16 -05:00
76792fd144 README: write instructions for each component 2024-12-09 18:35:49 -08:00
9097c551c4 not using openapi-generator (it's java) 2024-12-09 18:28:44 -08:00
0b46ee28a4 open source 2024-12-09 18:16:07 -08:00
6adf9a8977 web folder (dont use this code) 2024-12-09 21:14:54 -05:00
fe6a88a479 tweak submission comment 2024-12-09 17:34:55 -08:00
c3b559f6a6 tweak openapi description 2024-12-09 17:34:46 -08:00
dac135f624 partially implement publish_new 2024-12-06 21:00:19 -08:00
2aacb4c87c split publishing for new maps and map fixes 2024-12-06 20:31:28 -08:00
f46df3a8eb apparently you can just do it, thanks rust 2024-12-06 20:07:15 -08:00
bf3698c1db tweak comment 2024-12-06 19:47:06 -08:00
a019e61556 remove unnecessary data structure 2024-12-06 19:45:44 -08:00
572e51961c validation: mark submission as validated 2024-12-06 19:43:06 -08:00
3289376f8e rust api: action_submission_validate 2024-12-06 19:43:06 -08:00
f99dbb1b9d fallible functions cannot exist in the error suppressor 2024-12-06 19:43:06 -08:00
1a5e6e90c6 presumptuously rename error 2024-12-06 19:36:10 -08:00
c77a34804d i64 😭 2024-12-06 19:27:20 -08:00
b7d04da9e0 rust api: implement update_submission_model 2024-12-06 19:19:01 -08:00
1133e00ccc fix api 2024-12-06 19:02:57 -08:00
56fefbe52d fat concurrent script fetching 2024-12-06 18:59:33 -08:00
0977943834 fix hash 2024-12-06 18:57:11 -08:00
bc6613f235 implement script policy 2024-12-06 18:19:35 -08:00
33ea38d35f unused 2024-12-06 18:19:35 -08:00
86121bbfc1 implement siphash (confirmed identical hash) 2024-12-06 18:19:35 -08:00
a97738b378 implement scripts crud 2024-12-05 20:26:51 -08:00
2dcae799da script always has a SubmissionID, it's just 0 2024-12-05 20:26:27 -08:00
ee7e5371a8 tweak roles 2024-12-05 19:10:09 -08:00
0c2ee16bde openapi: not optional 2024-12-05 18:56:44 -08:00
005f2ddaee rust api: patch 2024-12-05 18:49:09 -08:00
329eb1663c new api skeleton 2024-12-05 16:50:35 -08:00
80425813c3 fix non-optional values 2024-12-05 16:50:35 -08:00
5899efd759 openapi: generate 2024-12-05 16:50:35 -08:00
3b85c98e10 openapi: massive crud 2024-12-05 16:50:35 -08:00
1a48a4fb5a tweak policy 2024-12-05 16:50:35 -08:00
8f74a3f783 common service errors 2024-12-05 16:50:35 -08:00
8c254aef6e scripts & script policy 2024-12-05 16:50:35 -08:00
e7375cde11 openapi: script stuff 2024-12-04 19:07:40 -08:00
4ed70dbcad custom rust api client for maps-service 2024-12-04 19:07:40 -08:00
a457faef56 delete openapi-generator rust code - it's awful and doesn't even compile 2024-12-04 19:04:14 -08:00
0d2c412fd4 add reflection database back, not making a strafesnet roblox map lib 2024-12-04 19:00:31 -08:00
d0e6233d68 scripts can be rejected lol 2024-12-03 20:23:06 -08:00
ce5d84a646 openapi: add scripts operations 2024-12-03 19:29:59 -08:00
799346aee6 openapi: remove junk 2024-12-03 19:29:50 -08:00
6a6e68e8df add api dependency 2024-12-03 19:18:40 -08:00
42935ce990 generate api for rust 2024-12-03 19:13:29 -08:00
dd193e6e8f wip: write some script validation code 2024-12-03 18:54:33 -08:00
dc7645319e remove sqlx 2024-12-03 17:43:37 -08:00
fad27b6792 do not reply with nats 2024-12-03 17:37:33 -08:00
6c3942e37d cloud only needed to upload places 2024-12-02 23:34:25 -08:00
1124f8adea wip: validator 2024-12-02 23:27:58 -08:00
92fe223d96 json 2024-12-02 23:27:58 -08:00
895a3f1249 validator can invalidate 2024-12-02 22:52:17 -08:00
c7f3cdc0d6 the natsy 2024-12-02 22:36:44 -08:00
7375842089 prep deps 2024-12-02 22:09:51 -08:00
ade10e8476 reuse validated model for multiple review cycles 2024-12-02 18:23:15 -08:00
ec5f225866 auth 2024-11-29 15:39:47 -08:00
1933a0914a openapi cookie 2024-11-29 15:39:47 -08:00
f3b41c6b25 read itzaname code and simplify wacky string stuff 2024-11-27 22:47:30 -08:00
712ff32552 fixup: api: SubmissionCreate in request body 2024-11-27 19:22:42 -08:00
bb46697277 pseudocode 2024-11-27 19:06:21 -08:00
86204e877e use transaction check for PatchSubmissionModel 2024-11-27 19:06:21 -08:00
f5fb895aeb construct transactional update 2024-11-27 18:58:49 -08:00
f4fea2963d implement status actions 2024-11-27 18:19:19 -08:00
cdd9488ace prepend status with namespacing
bruh golang moment
2024-11-27 17:59:29 -08:00
b31a8a90ff generate and edit submissions interface 2024-11-27 17:48:01 -08:00
414731dea4 model each action with its own request 2024-11-27 17:44:42 -08:00
b085b244fe status action template 2024-11-27 17:44:42 -08:00
6f4df29d2e allow submitter to revoke submission 2024-11-27 17:32:49 -08:00
e68d78bcb7 notes about permissions 2024-11-27 17:28:11 -08:00
23ffa45db2 submission Status enum 2024-11-27 17:28:11 -08:00
1984dd00bc completed is set to false when the model updates 2024-11-27 17:28:11 -08:00
680c21ca11 completed is implicitly true 2024-11-27 17:27:50 -08:00
1119c91da3 implement patch methods 2024-11-27 16:47:28 -08:00
1af6962b12 implement ListSubmissions 2024-11-27 16:38:22 -08:00
acece12737 api: SubmissionCreate in request body 2024-11-27 16:13:55 -08:00
f7aff4bbaa change api to do IdMessage 2024-11-27 16:13:43 -08:00
f87c4dab8f hooray functions copy pasted 2024-11-27 16:12:05 -08:00
b8cb49c1cb where is v1 2024-11-26 16:13:20 -08:00
2504572cb3 fix port 2024-11-26 16:06:43 -08:00
1bfec3d35e fix migrate 2024-11-26 15:59:52 -08:00
cf9cb7c6c3 implement GetSubmission 2024-11-26 15:55:56 -08:00
b05a4d5659 modify Submission struct 2024-11-26 15:55:50 -08:00
66ddcbabd6 run generate 2024-11-26 15:43:54 -08:00
6fefd90c91 extend submission object 2024-11-26 15:41:13 -08:00
4c3c42143e Missing changes 2024-11-26 18:30:58 -05:00
8bcb8d3f20 Refactor 😮‍💨 2024-11-26 18:28:48 -05:00
237 changed files with 85517 additions and 5131 deletions

2
.cargo/config.toml Normal file
View File

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

154
.drone.yml Normal file
View File

@@ -0,0 +1,154 @@
---
kind: pipeline
type: docker
platform:
os: linux
arch: amd64
steps:
- 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
repo: registry.itzana.me/strafesnet/maptest-api
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
dockerfile: Dockerfile
context: .
depends_on:
- build-backend
when:
branch:
- master
- staging
event:
- push
- name: image-frontend
image: plugins/docker
settings:
registry: registry.itzana.me
repo: registry.itzana.me/strafesnet/maptest-frontend
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
dockerfile: web/Containerfile
context: web
when:
branch:
- master
- staging
event:
- push
- name: image-validator
image: plugins/docker
settings:
registry: registry.itzana.me
repo: registry.itzana.me/strafesnet/maptest-validator
tags:
- ${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- ${DRONE_BRANCH}
username:
from_secret: REGISTRY_USER
password:
from_secret: REGISTRY_PASS
dockerfile: validation/Containerfile
context: .
depends_on:
- build-validator
when:
branch:
- master
- staging
event:
- push
- name: deploy
image: argoproj/argocd:latest
commands:
- argocd login --grpc-web cd.stricity.com --username $USERNAME --password $PASSWORD
- argocd app --grpc-web set ${DRONE_BRANCH}-maps-service --kustomize-image registry.itzana.me/strafesnet/maptest-api:${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- argocd app --grpc-web set ${DRONE_BRANCH}-maps-service --kustomize-image registry.itzana.me/strafesnet/maptest-frontend:${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
- argocd app --grpc-web set ${DRONE_BRANCH}-maps-service --kustomize-image registry.itzana.me/strafesnet/maptest-validator:${DRONE_BRANCH}-${DRONE_BUILD_NUMBER}
environment:
USERNAME:
from_secret: ARGO_USER
PASSWORD:
from_secret: ARGO_PASS
depends_on:
- image-backend
- image-frontend
- image-validator
when:
branch:
- master
- staging
event:
- push
# pr dry run
- name: build-pr
image: alpine
commands:
- echo "Success!"
depends_on:
- build-backend
- build-validator
- build-frontend
when:
event:
- pull_request
---
kind: signature
hmac: 6de9d4b91f14b30561856daf275d1fd523e1ce7a5a3651b660f0d8907b4692fb
...

3
.gitignore vendored Normal file
View File

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

3030
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

6
Cargo.toml Normal file
View File

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

3
Dockerfile Normal file
View File

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

23
LICENSE Normal file
View File

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

41
Makefile Normal file
View File

@@ -0,0 +1,41 @@
clean:
rm -rf build
rm -rf web/build
# build
build-backend:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o build/server cmd/maps-service/service.go
build-validator:
cargo build --release --target x86_64-unknown-linux-musl --bin maps-validation
build-frontend:
rm -rf web/build
cd web && bun install --frozen-lockfile
cd web && bun run build
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

@@ -1,14 +1,73 @@
# STRAFES.NET API
# STRAFES.NET Map Submission System
## How to Begin Development
## Components
- Submissions API (golang) `pkg/` `cmd/`
- Website `/web/`
- Script Validation (rust) `validation/`
## How to Begin Development on Each Component
### Submissions API
Prerequisite: golang installed
1. Run `go generate` to ensure the generated API is up-to-date. This project uses [ogen](https://github.com/ogen-go/ogen).
```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`.
### Website
Prerequisite: bun installed
The environment variables `API_HOST` and `AUTH_HOST` will need to be set for the middleware.
Example `.env` in web's root:
```
API_HOST="http://localhost:8082/"
AUTH_HOST="http://localhost:8083/"
```
1. `cd web`
2. `bun install`
#### For development:
3. `bun run dev`
#### For production:
3. `bun run build`
4. `bun run start` (optionally start a node server)
### Script Validation
Prerequisite: rust installed
1. `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
<sup>
Licensed under <a href="LICENSE">MIT license</a>.
</sup>
<br>
<sub>
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in this project by you, shall be licensed as above, without any
additional terms or conditions.
</sub>

View File

@@ -1,724 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
"net/url"
"strings"
"time"
"github.com/go-faster/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"go.opentelemetry.io/otel/trace"
"github.com/ogen-go/ogen/conv"
ht "github.com/ogen-go/ogen/http"
"github.com/ogen-go/ogen/otelogen"
"github.com/ogen-go/ogen/uri"
)
// Invoker invokes operations described by OpenAPI v3 specification.
type Invoker interface {
// CreateSubmission invokes createSubmission operation.
//
// Create new submission.
//
// POST /submissions
CreateSubmission(ctx context.Context) (*Submission, error)
// GetSubmission invokes getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
// ListSubmissions invokes listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error)
// PatchSubmissionCompleted invokes patchSubmissionCompleted operation.
//
// Retrieve map with ID.
//
// PATCH /submissions/{SubmissionID}/completed
PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error
// PatchSubmissionModel invokes patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// PATCH /submissions/{SubmissionID}/model
PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error
// PatchSubmissionStatus invokes patchSubmissionStatus operation.
//
// Update status following role restrictions.
//
// PATCH /submissions/{SubmissionID}/status
PatchSubmissionStatus(ctx context.Context, params PatchSubmissionStatusParams) error
}
// Client implements OAS client.
type Client struct {
serverURL *url.URL
baseClient
}
type errorHandler interface {
NewError(ctx context.Context, err error) *ErrorStatusCode
}
var _ Handler = struct {
errorHandler
*Client
}{}
func trimTrailingSlashes(u *url.URL) {
u.Path = strings.TrimRight(u.Path, "/")
u.RawPath = strings.TrimRight(u.RawPath, "/")
}
// NewClient initializes new Client defined by OAS.
func NewClient(serverURL string, opts ...ClientOption) (*Client, error) {
u, err := url.Parse(serverURL)
if err != nil {
return nil, err
}
trimTrailingSlashes(u)
c, err := newClientConfig(opts...).baseClient()
if err != nil {
return nil, err
}
return &Client{
serverURL: u,
baseClient: c,
}, nil
}
type serverURLKey struct{}
// WithServerURL sets context key to override server URL.
func WithServerURL(ctx context.Context, u *url.URL) context.Context {
return context.WithValue(ctx, serverURLKey{}, u)
}
func (c *Client) requestURL(ctx context.Context) *url.URL {
u, ok := ctx.Value(serverURLKey{}).(*url.URL)
if !ok {
return c.serverURL
}
return u
}
// CreateSubmission invokes createSubmission operation.
//
// Create new submission.
//
// POST /submissions
func (c *Client) CreateSubmission(ctx context.Context) (*Submission, error) {
res, err := c.sendCreateSubmission(ctx)
return res, err
}
func (c *Client) sendCreateSubmission(ctx context.Context) (res *Submission, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("createSubmission"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/submissions"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "CreateSubmission",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/submissions"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "POST", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeCreateSubmissionResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// GetSubmission invokes getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
func (c *Client) GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error) {
res, err := c.sendGetSubmission(ctx, params)
return res, err
}
func (c *Client) sendGetSubmission(ctx context.Context, params GetSubmissionParams) (res *Submission, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("getSubmission"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "GetSubmission",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [2]string
pathParts[0] = "/submissions/"
{
// Encode "SubmissionID" parameter.
e := uri.NewPathEncoder(uri.PathEncoderConfig{
Param: "SubmissionID",
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
}(); err != nil {
return res, errors.Wrap(err, "encode path")
}
encoded, err := e.Result()
if err != nil {
return res, errors.Wrap(err, "encode path")
}
pathParts[1] = encoded
}
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "GET", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeGetSubmissionResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// ListSubmissions invokes listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
func (c *Client) ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error) {
res, err := c.sendListSubmissions(ctx, params)
return res, err
}
func (c *Client) sendListSubmissions(ctx context.Context, params ListSubmissionsParams) (res []Submission, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("listSubmissions"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/submissions"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "ListSubmissions",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [1]string
pathParts[0] = "/submissions"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "page" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "page",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return params.Page.EncodeURI(e)
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "filter" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "filter",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
if val, ok := params.Filter.Get(); ok {
return val.EncodeURI(e)
}
return nil
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "GET", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodeListSubmissionsResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// PatchSubmissionCompleted invokes patchSubmissionCompleted operation.
//
// Retrieve map with ID.
//
// PATCH /submissions/{SubmissionID}/completed
func (c *Client) PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error {
_, err := c.sendPatchSubmissionCompleted(ctx, params)
return err
}
func (c *Client) sendPatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) (res *PatchSubmissionCompletedOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionCompleted"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/completed"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "PatchSubmissionCompleted",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [3]string
pathParts[0] = "/submissions/"
{
// Encode "SubmissionID" parameter.
e := uri.NewPathEncoder(uri.PathEncoderConfig{
Param: "SubmissionID",
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
}(); err != nil {
return res, errors.Wrap(err, "encode path")
}
encoded, err := e.Result()
if err != nil {
return res, errors.Wrap(err, "encode path")
}
pathParts[1] = encoded
}
pathParts[2] = "/completed"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "Completed" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "Completed",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.BoolToString(params.Completed))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "PATCH", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodePatchSubmissionCompletedResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// PatchSubmissionModel invokes patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// PATCH /submissions/{SubmissionID}/model
func (c *Client) PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error {
_, err := c.sendPatchSubmissionModel(ctx, params)
return err
}
func (c *Client) sendPatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) (res *PatchSubmissionModelOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionModel"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/model"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "PatchSubmissionModel",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [3]string
pathParts[0] = "/submissions/"
{
// Encode "SubmissionID" parameter.
e := uri.NewPathEncoder(uri.PathEncoderConfig{
Param: "SubmissionID",
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
}(); err != nil {
return res, errors.Wrap(err, "encode path")
}
encoded, err := e.Result()
if err != nil {
return res, errors.Wrap(err, "encode path")
}
pathParts[1] = encoded
}
pathParts[2] = "/model"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "ModelID" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "ModelID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.Int64ToString(params.ModelID))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
{
// Encode "VersionID" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "VersionID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.Int64ToString(params.VersionID))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "PATCH", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodePatchSubmissionModelResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}
// PatchSubmissionStatus invokes patchSubmissionStatus operation.
//
// Update status following role restrictions.
//
// PATCH /submissions/{SubmissionID}/status
func (c *Client) PatchSubmissionStatus(ctx context.Context, params PatchSubmissionStatusParams) error {
_, err := c.sendPatchSubmissionStatus(ctx, params)
return err
}
func (c *Client) sendPatchSubmissionStatus(ctx context.Context, params PatchSubmissionStatusParams) (res *PatchSubmissionStatusOK, err error) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionStatus"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status"),
}
// Run stopwatch.
startTime := time.Now()
defer func() {
// Use floating point division here for higher precision (instead of Millisecond method).
elapsedDuration := time.Since(startTime)
c.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), metric.WithAttributes(otelAttrs...))
}()
// Increment request counter.
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
// Start a span for this request.
ctx, span := c.cfg.Tracer.Start(ctx, "PatchSubmissionStatus",
trace.WithAttributes(otelAttrs...),
clientSpanKind,
)
// Track stage for error reporting.
var stage string
defer func() {
if err != nil {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
}
span.End()
}()
stage = "BuildURL"
u := uri.Clone(c.requestURL(ctx))
var pathParts [3]string
pathParts[0] = "/submissions/"
{
// Encode "SubmissionID" parameter.
e := uri.NewPathEncoder(uri.PathEncoderConfig{
Param: "SubmissionID",
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
}(); err != nil {
return res, errors.Wrap(err, "encode path")
}
encoded, err := e.Result()
if err != nil {
return res, errors.Wrap(err, "encode path")
}
pathParts[1] = encoded
}
pathParts[2] = "/status"
uri.AddPathParts(u, pathParts[:]...)
stage = "EncodeQueryParams"
q := uri.NewQueryEncoder()
{
// Encode "Status" parameter.
cfg := uri.QueryParameterEncodingConfig{
Name: "Status",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
return e.EncodeValue(conv.Int32ToString(params.Status))
}); err != nil {
return res, errors.Wrap(err, "encode query")
}
}
u.RawQuery = q.Values().Encode()
stage = "EncodeRequest"
r, err := ht.NewRequest(ctx, "PATCH", u)
if err != nil {
return res, errors.Wrap(err, "create request")
}
stage = "SendRequest"
resp, err := c.cfg.Client.Do(r)
if err != nil {
return res, errors.Wrap(err, "do request")
}
defer resp.Body.Close()
stage = "DecodeResponse"
result, err := decodePatchSubmissionStatusResponse(resp)
if err != nil {
return res, errors.Wrap(err, "decode response")
}
return result, nil
}

View File

@@ -1,760 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
"net/http"
"time"
"github.com/go-faster/errors"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/metric"
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
"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"
)
// handleCreateSubmissionRequest handles createSubmission operation.
//
// Create new submission.
//
// POST /submissions
func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("createSubmission"),
semconv.HTTPRequestMethodKey.String("POST"),
semconv.HTTPRouteKey.String("/submissions"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "CreateSubmission",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
)
var response *Submission
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "CreateSubmission",
OperationSummary: "Create new submission",
OperationID: "createSubmission",
Body: nil,
Params: middleware.Parameters{},
Raw: r,
}
type (
Request = struct{}
Params = struct{}
Response = *Submission
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
nil,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.CreateSubmission(ctx)
return response, err
},
)
} else {
response, err = s.h.CreateSubmission(ctx)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeCreateSubmissionResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleGetSubmissionRequest handles getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
func (s *Server) handleGetSubmissionRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("getSubmission"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "GetSubmission",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: "GetSubmission",
ID: "getSubmission",
}
)
params, err := decodeGetSubmissionParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response *Submission
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "GetSubmission",
OperationSummary: "Retrieve map with ID",
OperationID: "getSubmission",
Body: nil,
Params: middleware.Parameters{
{
Name: "SubmissionID",
In: "path",
}: params.SubmissionID,
},
Raw: r,
}
type (
Request = struct{}
Params = GetSubmissionParams
Response = *Submission
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackGetSubmissionParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.GetSubmission(ctx, params)
return response, err
},
)
} else {
response, err = s.h.GetSubmission(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeGetSubmissionResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handleListSubmissionsRequest handles listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
func (s *Server) handleListSubmissionsRequest(args [0]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("listSubmissions"),
semconv.HTTPRequestMethodKey.String("GET"),
semconv.HTTPRouteKey.String("/submissions"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "ListSubmissions",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: "ListSubmissions",
ID: "listSubmissions",
}
)
params, err := decodeListSubmissionsParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response []Submission
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "ListSubmissions",
OperationSummary: "Get list of submissions",
OperationID: "listSubmissions",
Body: nil,
Params: middleware.Parameters{
{
Name: "page",
In: "query",
}: params.Page,
{
Name: "filter",
In: "query",
}: params.Filter,
},
Raw: r,
}
type (
Request = struct{}
Params = ListSubmissionsParams
Response = []Submission
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackListSubmissionsParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
response, err = s.h.ListSubmissions(ctx, params)
return response, err
},
)
} else {
response, err = s.h.ListSubmissions(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodeListSubmissionsResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handlePatchSubmissionCompletedRequest handles patchSubmissionCompleted operation.
//
// Retrieve map with ID.
//
// PATCH /submissions/{SubmissionID}/completed
func (s *Server) handlePatchSubmissionCompletedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionCompleted"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/completed"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "PatchSubmissionCompleted",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: "PatchSubmissionCompleted",
ID: "patchSubmissionCompleted",
}
)
params, err := decodePatchSubmissionCompletedParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response *PatchSubmissionCompletedOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "PatchSubmissionCompleted",
OperationSummary: "Retrieve map with ID",
OperationID: "patchSubmissionCompleted",
Body: nil,
Params: middleware.Parameters{
{
Name: "SubmissionID",
In: "path",
}: params.SubmissionID,
{
Name: "Completed",
In: "query",
}: params.Completed,
},
Raw: r,
}
type (
Request = struct{}
Params = PatchSubmissionCompletedParams
Response = *PatchSubmissionCompletedOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackPatchSubmissionCompletedParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.PatchSubmissionCompleted(ctx, params)
return response, err
},
)
} else {
err = s.h.PatchSubmissionCompleted(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodePatchSubmissionCompletedResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handlePatchSubmissionModelRequest handles patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// PATCH /submissions/{SubmissionID}/model
func (s *Server) handlePatchSubmissionModelRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionModel"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/model"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "PatchSubmissionModel",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: "PatchSubmissionModel",
ID: "patchSubmissionModel",
}
)
params, err := decodePatchSubmissionModelParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response *PatchSubmissionModelOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "PatchSubmissionModel",
OperationSummary: "Update model following role restrictions",
OperationID: "patchSubmissionModel",
Body: nil,
Params: middleware.Parameters{
{
Name: "SubmissionID",
In: "path",
}: params.SubmissionID,
{
Name: "ModelID",
In: "query",
}: params.ModelID,
{
Name: "VersionID",
In: "query",
}: params.VersionID,
},
Raw: r,
}
type (
Request = struct{}
Params = PatchSubmissionModelParams
Response = *PatchSubmissionModelOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackPatchSubmissionModelParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.PatchSubmissionModel(ctx, params)
return response, err
},
)
} else {
err = s.h.PatchSubmissionModel(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodePatchSubmissionModelResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}
// handlePatchSubmissionStatusRequest handles patchSubmissionStatus operation.
//
// Update status following role restrictions.
//
// PATCH /submissions/{SubmissionID}/status
func (s *Server) handlePatchSubmissionStatusRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
otelAttrs := []attribute.KeyValue{
otelogen.OperationID("patchSubmissionStatus"),
semconv.HTTPRequestMethodKey.String("PATCH"),
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status"),
}
// Start a span for this request.
ctx, span := s.cfg.Tracer.Start(r.Context(), "PatchSubmissionStatus",
trace.WithAttributes(otelAttrs...),
serverSpanKind,
)
defer span.End()
// Add Labeler to context.
labeler := &Labeler{attrs: otelAttrs}
ctx = contextWithLabeler(ctx, labeler)
// Run stopwatch.
startTime := time.Now()
defer func() {
elapsedDuration := time.Since(startTime)
attrOpt := metric.WithAttributeSet(labeler.AttributeSet())
// Increment request counter.
s.requests.Add(ctx, 1, attrOpt)
// Use floating point division here for higher precision (instead of Millisecond method).
s.duration.Record(ctx, float64(float64(elapsedDuration)/float64(time.Millisecond)), attrOpt)
}()
var (
recordError = func(stage string, err error) {
span.RecordError(err)
span.SetStatus(codes.Error, stage)
s.errors.Add(ctx, 1, metric.WithAttributeSet(labeler.AttributeSet()))
}
err error
opErrContext = ogenerrors.OperationContext{
Name: "PatchSubmissionStatus",
ID: "patchSubmissionStatus",
}
)
params, err := decodePatchSubmissionStatusParams(args, argsEscaped, r)
if err != nil {
err = &ogenerrors.DecodeParamsError{
OperationContext: opErrContext,
Err: err,
}
defer recordError("DecodeParams", err)
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
var response *PatchSubmissionStatusOK
if m := s.cfg.Middleware; m != nil {
mreq := middleware.Request{
Context: ctx,
OperationName: "PatchSubmissionStatus",
OperationSummary: "Update status following role restrictions",
OperationID: "patchSubmissionStatus",
Body: nil,
Params: middleware.Parameters{
{
Name: "SubmissionID",
In: "path",
}: params.SubmissionID,
{
Name: "Status",
In: "query",
}: params.Status,
},
Raw: r,
}
type (
Request = struct{}
Params = PatchSubmissionStatusParams
Response = *PatchSubmissionStatusOK
)
response, err = middleware.HookMiddleware[
Request,
Params,
Response,
](
m,
mreq,
unpackPatchSubmissionStatusParams,
func(ctx context.Context, request Request, params Params) (response Response, err error) {
err = s.h.PatchSubmissionStatus(ctx, params)
return response, err
},
)
} else {
err = s.h.PatchSubmissionStatus(ctx, params)
}
if err != nil {
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
if err := encodeErrorResponse(errRes, w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if errors.Is(err, ht.ErrNotImplemented) {
s.cfg.ErrorHandler(ctx, w, r, err)
return
}
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
defer recordError("Internal", err)
}
return
}
if err := encodePatchSubmissionStatusResponse(response, w, span); err != nil {
defer recordError("EncodeResponse", err)
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
s.cfg.ErrorHandler(ctx, w, r, err)
}
return
}
}

View File

@@ -1,516 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"math/bits"
"strconv"
"github.com/go-faster/errors"
"github.com/go-faster/jx"
"github.com/ogen-go/ogen/validate"
)
// Encode implements json.Marshaler.
func (s *Error) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *Error) encodeFields(e *jx.Encoder) {
{
e.FieldStart("code")
e.Int64(s.Code)
}
{
e.FieldStart("message")
e.Str(s.Message)
}
}
var jsonFieldsNameOfError = [2]string{
0: "code",
1: "message",
}
// Decode decodes Error from json.
func (s *Error) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Error to nil")
}
var requiredBitSet [1]uint8
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "code":
requiredBitSet[0] |= 1 << 0
if err := func() error {
v, err := d.Int64()
s.Code = int64(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"code\"")
}
case "message":
requiredBitSet[0] |= 1 << 1
if err := func() error {
v, err := d.Str()
s.Message = string(v)
if err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"message\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Error")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(jsonFieldsNameOfError) {
name = jsonFieldsNameOfError[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *Error) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *Error) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode encodes bool as json.
func (o OptBool) Encode(e *jx.Encoder) {
if !o.Set {
return
}
e.Bool(bool(o.Value))
}
// Decode decodes bool from json.
func (o *OptBool) Decode(d *jx.Decoder) error {
if o == nil {
return errors.New("invalid: unable to decode OptBool to nil")
}
o.Set = true
v, err := d.Bool()
if err != nil {
return err
}
o.Value = bool(v)
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s OptBool) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *OptBool) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode encodes int32 as json.
func (o OptInt32) Encode(e *jx.Encoder) {
if !o.Set {
return
}
e.Int32(int32(o.Value))
}
// Decode decodes int32 from json.
func (o *OptInt32) Decode(d *jx.Decoder) error {
if o == nil {
return errors.New("invalid: unable to decode OptInt32 to nil")
}
o.Set = true
v, err := d.Int32()
if err != nil {
return err
}
o.Value = int32(v)
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s OptInt32) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *OptInt32) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode encodes int64 as json.
func (o OptInt64) Encode(e *jx.Encoder) {
if !o.Set {
return
}
e.Int64(int64(o.Value))
}
// Decode decodes int64 from json.
func (o *OptInt64) Decode(d *jx.Decoder) error {
if o == nil {
return errors.New("invalid: unable to decode OptInt64 to nil")
}
o.Set = true
v, err := d.Int64()
if err != nil {
return err
}
o.Value = int64(v)
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s OptInt64) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *OptInt64) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode encodes string as json.
func (o OptString) Encode(e *jx.Encoder) {
if !o.Set {
return
}
e.Str(string(o.Value))
}
// Decode decodes string from json.
func (o *OptString) Decode(d *jx.Decoder) error {
if o == nil {
return errors.New("invalid: unable to decode OptString to nil")
}
o.Set = true
v, err := d.Str()
if err != nil {
return err
}
o.Value = string(v)
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s OptString) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *OptString) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}
// Encode implements json.Marshaler.
func (s *Submission) Encode(e *jx.Encoder) {
e.ObjStart()
s.encodeFields(e)
e.ObjEnd()
}
// encodeFields encodes fields.
func (s *Submission) encodeFields(e *jx.Encoder) {
{
if s.ID.Set {
e.FieldStart("ID")
s.ID.Encode(e)
}
}
{
if s.DisplayName.Set {
e.FieldStart("DisplayName")
s.DisplayName.Encode(e)
}
}
{
if s.Creator.Set {
e.FieldStart("Creator")
s.Creator.Encode(e)
}
}
{
if s.GameID.Set {
e.FieldStart("GameID")
s.GameID.Encode(e)
}
}
{
if s.Date.Set {
e.FieldStart("Date")
s.Date.Encode(e)
}
}
{
if s.Submitter.Set {
e.FieldStart("Submitter")
s.Submitter.Encode(e)
}
}
{
if s.AssetID.Set {
e.FieldStart("AssetID")
s.AssetID.Encode(e)
}
}
{
if s.AssetVersion.Set {
e.FieldStart("AssetVersion")
s.AssetVersion.Encode(e)
}
}
{
if s.Completed.Set {
e.FieldStart("Completed")
s.Completed.Encode(e)
}
}
{
if s.SubmissionType.Set {
e.FieldStart("SubmissionType")
s.SubmissionType.Encode(e)
}
}
{
if s.TargetAssetID.Set {
e.FieldStart("TargetAssetID")
s.TargetAssetID.Encode(e)
}
}
{
if s.StatusID.Set {
e.FieldStart("StatusID")
s.StatusID.Encode(e)
}
}
}
var jsonFieldsNameOfSubmission = [12]string{
0: "ID",
1: "DisplayName",
2: "Creator",
3: "GameID",
4: "Date",
5: "Submitter",
6: "AssetID",
7: "AssetVersion",
8: "Completed",
9: "SubmissionType",
10: "TargetAssetID",
11: "StatusID",
}
// Decode decodes Submission from json.
func (s *Submission) Decode(d *jx.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Submission to nil")
}
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
switch string(k) {
case "ID":
if err := func() error {
s.ID.Reset()
if err := s.ID.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"ID\"")
}
case "DisplayName":
if err := func() error {
s.DisplayName.Reset()
if err := s.DisplayName.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"DisplayName\"")
}
case "Creator":
if err := func() error {
s.Creator.Reset()
if err := s.Creator.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Creator\"")
}
case "GameID":
if err := func() error {
s.GameID.Reset()
if err := s.GameID.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"")
}
case "Date":
if err := func() error {
s.Date.Reset()
if err := s.Date.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Date\"")
}
case "Submitter":
if err := func() error {
s.Submitter.Reset()
if err := s.Submitter.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Submitter\"")
}
case "AssetID":
if err := func() error {
s.AssetID.Reset()
if err := s.AssetID.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"AssetID\"")
}
case "AssetVersion":
if err := func() error {
s.AssetVersion.Reset()
if err := s.AssetVersion.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"AssetVersion\"")
}
case "Completed":
if err := func() error {
s.Completed.Reset()
if err := s.Completed.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Completed\"")
}
case "SubmissionType":
if err := func() error {
s.SubmissionType.Reset()
if err := s.SubmissionType.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"SubmissionType\"")
}
case "TargetAssetID":
if err := func() error {
s.TargetAssetID.Reset()
if err := s.TargetAssetID.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"TargetAssetID\"")
}
case "StatusID":
if err := func() error {
s.StatusID.Reset()
if err := s.StatusID.Decode(d); err != nil {
return err
}
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"StatusID\"")
}
default:
return d.Skip()
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Submission")
}
return nil
}
// MarshalJSON implements stdjson.Marshaler.
func (s *Submission) MarshalJSON() ([]byte, error) {
e := jx.Encoder{}
s.Encode(&e)
return e.Bytes(), nil
}
// UnmarshalJSON implements stdjson.Unmarshaler.
func (s *Submission) UnmarshalJSON(data []byte) error {
d := jx.DecodeBytes(data)
return s.Decode(d)
}

View File

@@ -1,551 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"net/http"
"net/url"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/conv"
"github.com/ogen-go/ogen/middleware"
"github.com/ogen-go/ogen/ogenerrors"
"github.com/ogen-go/ogen/uri"
"github.com/ogen-go/ogen/validate"
)
// GetSubmissionParams is parameters of getSubmission operation.
type GetSubmissionParams struct {
SubmissionID int64
}
func unpackGetSubmissionParams(packed middleware.Parameters) (params GetSubmissionParams) {
{
key := middleware.ParameterKey{
Name: "SubmissionID",
In: "path",
}
params.SubmissionID = packed[key].(int64)
}
return params
}
func decodeGetSubmissionParams(args [1]string, argsEscaped bool, r *http.Request) (params GetSubmissionParams, _ error) {
// Decode path: SubmissionID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "SubmissionID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.SubmissionID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "SubmissionID",
In: "path",
Err: err,
}
}
return params, nil
}
// ListSubmissionsParams is parameters of listSubmissions operation.
type ListSubmissionsParams struct {
Page Pagination
Filter OptSubmissionFilter
}
func unpackListSubmissionsParams(packed middleware.Parameters) (params ListSubmissionsParams) {
{
key := middleware.ParameterKey{
Name: "page",
In: "query",
}
params.Page = packed[key].(Pagination)
}
{
key := middleware.ParameterKey{
Name: "filter",
In: "query",
}
if v, ok := packed[key]; ok {
params.Filter = v.(OptSubmissionFilter)
}
}
return params
}
func decodeListSubmissionsParams(args [0]string, argsEscaped bool, r *http.Request) (params ListSubmissionsParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode query: page.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "page",
Style: uri.QueryStyleForm,
Explode: true,
Fields: []uri.QueryParameterObjectField{{Name: "Page", Required: true}, {Name: "Limit", Required: true}},
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
return params.Page.DecodeURI(d)
}); err != nil {
return err
}
if err := func() error {
if err := params.Page.Validate(); err != nil {
return err
}
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "page",
In: "query",
Err: err,
}
}
// Decode query: filter.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "filter",
Style: uri.QueryStyleForm,
Explode: true,
Fields: []uri.QueryParameterObjectField{{Name: "ID", Required: false}, {Name: "DisplayName", Required: false}, {Name: "Creator", Required: false}, {Name: "GameID", Required: false}, {Name: "Date", Required: false}},
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
var paramsDotFilterVal SubmissionFilter
if err := func() error {
return paramsDotFilterVal.DecodeURI(d)
}(); err != nil {
return err
}
params.Filter.SetTo(paramsDotFilterVal)
return nil
}); err != nil {
return err
}
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "filter",
In: "query",
Err: err,
}
}
return params, nil
}
// PatchSubmissionCompletedParams is parameters of patchSubmissionCompleted operation.
type PatchSubmissionCompletedParams struct {
SubmissionID int64
Completed bool
}
func unpackPatchSubmissionCompletedParams(packed middleware.Parameters) (params PatchSubmissionCompletedParams) {
{
key := middleware.ParameterKey{
Name: "SubmissionID",
In: "path",
}
params.SubmissionID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "Completed",
In: "query",
}
params.Completed = packed[key].(bool)
}
return params
}
func decodePatchSubmissionCompletedParams(args [1]string, argsEscaped bool, r *http.Request) (params PatchSubmissionCompletedParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: SubmissionID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "SubmissionID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.SubmissionID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "SubmissionID",
In: "path",
Err: err,
}
}
// Decode query: Completed.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "Completed",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToBool(val)
if err != nil {
return err
}
params.Completed = c
return nil
}); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "Completed",
In: "query",
Err: err,
}
}
return params, nil
}
// PatchSubmissionModelParams is parameters of patchSubmissionModel operation.
type PatchSubmissionModelParams struct {
SubmissionID int64
ModelID int64
VersionID int64
}
func unpackPatchSubmissionModelParams(packed middleware.Parameters) (params PatchSubmissionModelParams) {
{
key := middleware.ParameterKey{
Name: "SubmissionID",
In: "path",
}
params.SubmissionID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "ModelID",
In: "query",
}
params.ModelID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "VersionID",
In: "query",
}
params.VersionID = packed[key].(int64)
}
return params
}
func decodePatchSubmissionModelParams(args [1]string, argsEscaped bool, r *http.Request) (params PatchSubmissionModelParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: SubmissionID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "SubmissionID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.SubmissionID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "SubmissionID",
In: "path",
Err: err,
}
}
// Decode query: ModelID.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "ModelID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.ModelID = c
return nil
}); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "ModelID",
In: "query",
Err: err,
}
}
// Decode query: VersionID.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "VersionID",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.VersionID = c
return nil
}); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "VersionID",
In: "query",
Err: err,
}
}
return params, nil
}
// PatchSubmissionStatusParams is parameters of patchSubmissionStatus operation.
type PatchSubmissionStatusParams struct {
SubmissionID int64
Status int32
}
func unpackPatchSubmissionStatusParams(packed middleware.Parameters) (params PatchSubmissionStatusParams) {
{
key := middleware.ParameterKey{
Name: "SubmissionID",
In: "path",
}
params.SubmissionID = packed[key].(int64)
}
{
key := middleware.ParameterKey{
Name: "Status",
In: "query",
}
params.Status = packed[key].(int32)
}
return params
}
func decodePatchSubmissionStatusParams(args [1]string, argsEscaped bool, r *http.Request) (params PatchSubmissionStatusParams, _ error) {
q := uri.NewQueryDecoder(r.URL.Query())
// Decode path: SubmissionID.
if err := func() error {
param := args[0]
if argsEscaped {
unescaped, err := url.PathUnescape(args[0])
if err != nil {
return errors.Wrap(err, "unescape path")
}
param = unescaped
}
if len(param) > 0 {
d := uri.NewPathDecoder(uri.PathDecoderConfig{
Param: "SubmissionID",
Value: param,
Style: uri.PathStyleSimple,
Explode: false,
})
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
params.SubmissionID = c
return nil
}(); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "SubmissionID",
In: "path",
Err: err,
}
}
// Decode query: Status.
if err := func() error {
cfg := uri.QueryParameterDecodingConfig{
Name: "Status",
Style: uri.QueryStyleForm,
Explode: true,
}
if err := q.HasParam(cfg); err == nil {
if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt32(val)
if err != nil {
return err
}
params.Status = c
return nil
}); err != nil {
return err
}
} else {
return validate.ErrFieldRequired
}
return nil
}(); err != nil {
return params, &ogenerrors.DecodeParamError{
Name: "Status",
In: "query",
Err: err,
}
}
return params, nil
}

View File

@@ -1,3 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api

View File

@@ -1,3 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api

View File

@@ -1,434 +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 decodeCreateSubmissionResponse(resp *http.Response) (res *Submission, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Submission
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeGetSubmissionResponse(resp *http.Response) (res *Submission, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Submission
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodeListSubmissionsResponse(resp *http.Response) (res []Submission, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response []Submission
if err := func() error {
response = make([]Submission, 0)
if err := d.Arr(func(d *jx.Decoder) error {
var elem Submission
if err := elem.Decode(d); err != nil {
return err
}
response = append(response, elem)
return nil
}); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
// Validate response.
if err := func() error {
if response == nil {
return errors.New("nil is invalid value")
}
return nil
}(); err != nil {
return res, errors.Wrap(err, "validate")
}
return response, nil
default:
return res, validate.InvalidContentType(ct)
}
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodePatchSubmissionCompletedResponse(resp *http.Response) (res *PatchSubmissionCompletedOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
return &PatchSubmissionCompletedOK{}, nil
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodePatchSubmissionModelResponse(resp *http.Response) (res *PatchSubmissionModelOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
return &PatchSubmissionModelOK{}, nil
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}
func decodePatchSubmissionStatusResponse(resp *http.Response) (res *PatchSubmissionStatusOK, _ error) {
switch resp.StatusCode {
case 200:
// Code 200.
return &PatchSubmissionStatusOK{}, nil
}
// Convenient error response.
defRes, err := func() (res *ErrorStatusCode, err error) {
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if err != nil {
return res, errors.Wrap(err, "parse media type")
}
switch {
case ct == "application/json":
buf, err := io.ReadAll(resp.Body)
if err != nil {
return res, err
}
d := jx.DecodeBytes(buf)
var response Error
if err := func() error {
if err := response.Decode(d); err != nil {
return err
}
if err := d.Skip(); err != io.EOF {
return errors.New("unexpected trailing data")
}
return nil
}(); err != nil {
err = &ogenerrors.DecodeBodyError{
ContentType: ct,
Body: buf,
Err: err,
}
return res, err
}
return &ErrorStatusCode{
StatusCode: resp.StatusCode,
Response: response,
}, nil
default:
return res, validate.InvalidContentType(ct)
}
}()
if err != nil {
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
}
return res, errors.Wrap(defRes, "error")
}

View File

@@ -1,108 +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 encodeCreateSubmissionResponse(response *Submission, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
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)
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 encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
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 encodePatchSubmissionCompletedResponse(response *PatchSubmissionCompletedOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
return nil
}
func encodePatchSubmissionModelResponse(response *PatchSubmissionModelOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
return nil
}
func encodePatchSubmissionStatusResponse(response *PatchSubmissionStatusOK, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
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
}

View File

@@ -1,435 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"net/http"
"net/url"
"strings"
"github.com/ogen-go/ogen/uri"
)
func (s *Server) cutPrefix(path string) (string, bool) {
prefix := s.cfg.Prefix
if prefix == "" {
return path, true
}
if !strings.HasPrefix(path, prefix) {
// Prefix doesn't match.
return "", false
}
// Cut prefix from the path.
return strings.TrimPrefix(path, prefix), true
}
// ServeHTTP serves http request as defined by OpenAPI v3 specification,
// calling handler that matches the path or returning not found error.
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
elem := r.URL.Path
elemIsEscaped := false
if rawPath := r.URL.RawPath; rawPath != "" {
if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
elem = normalized
elemIsEscaped = strings.ContainsRune(elem, '%')
}
}
elem, ok := s.cutPrefix(elem)
if !ok || len(elem) == 0 {
s.notFound(w, r)
return
}
args := [1]string{}
// Static code generated router with unwrapped path search.
switch {
default:
if len(elem) == 0 {
break
}
switch elem[0] {
case '/': // Prefix: "/submissions"
origElem := elem
if l := len("/submissions"); len(elem) >= l && elem[0:l] == "/submissions" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch r.Method {
case "GET":
s.handleListSubmissionsRequest([0]string{}, elemIsEscaped, w, r)
case "POST":
s.handleCreateSubmissionRequest([0]string{}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET,POST")
}
return
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
// Param: "SubmissionID"
// Match until "/"
idx := strings.IndexByte(elem, '/')
if idx < 0 {
idx = len(elem)
}
args[0] = elem[:idx]
elem = elem[idx:]
if len(elem) == 0 {
switch r.Method {
case "GET":
s.handleGetSubmissionRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "GET")
}
return
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'c': // Prefix: "completed"
origElem := elem
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "PATCH":
s.handlePatchSubmissionCompletedRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "PATCH")
}
return
}
elem = origElem
case 'm': // Prefix: "model"
origElem := elem
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "PATCH":
s.handlePatchSubmissionModelRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "PATCH")
}
return
}
elem = origElem
case 's': // Prefix: "status"
origElem := elem
if l := len("status"); len(elem) >= l && elem[0:l] == "status" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch r.Method {
case "PATCH":
s.handlePatchSubmissionStatusRequest([1]string{
args[0],
}, elemIsEscaped, w, r)
default:
s.notAllowed(w, r, "PATCH")
}
return
}
elem = origElem
}
elem = origElem
}
elem = origElem
}
elem = origElem
}
}
s.notFound(w, r)
}
// Route is route object.
type Route struct {
name string
summary string
operationID string
pathPattern string
count int
args [1]string
}
// Name returns ogen operation name.
//
// It is guaranteed to be unique and not empty.
func (r Route) Name() string {
return r.name
}
// Summary returns OpenAPI summary.
func (r Route) Summary() string {
return r.summary
}
// OperationID returns OpenAPI operationId.
func (r Route) OperationID() string {
return r.operationID
}
// PathPattern returns OpenAPI path.
func (r Route) PathPattern() string {
return r.pathPattern
}
// Args returns parsed arguments.
func (r Route) Args() []string {
return r.args[:r.count]
}
// FindRoute finds Route for given method and path.
//
// Note: this method does not unescape path or handle reserved characters in path properly. Use FindPath instead.
func (s *Server) FindRoute(method, path string) (Route, bool) {
return s.FindPath(method, &url.URL{Path: path})
}
// FindPath finds Route for given method and URL.
func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
var (
elem = u.Path
args = r.args
)
if rawPath := u.RawPath; rawPath != "" {
if normalized, ok := uri.NormalizeEscapedPath(rawPath); ok {
elem = normalized
}
defer func() {
for i, arg := range r.args[:r.count] {
if unescaped, err := url.PathUnescape(arg); err == nil {
r.args[i] = unescaped
}
}
}()
}
elem, ok := s.cutPrefix(elem)
if !ok {
return r, false
}
// Static code generated router with unwrapped path search.
switch {
default:
if len(elem) == 0 {
break
}
switch elem[0] {
case '/': // Prefix: "/submissions"
origElem := elem
if l := len("/submissions"); len(elem) >= l && elem[0:l] == "/submissions" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
switch method {
case "GET":
r.name = "ListSubmissions"
r.summary = "Get list of submissions"
r.operationID = "listSubmissions"
r.pathPattern = "/submissions"
r.args = args
r.count = 0
return r, true
case "POST":
r.name = "CreateSubmission"
r.summary = "Create new submission"
r.operationID = "createSubmission"
r.pathPattern = "/submissions"
r.args = args
r.count = 0
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
// Param: "SubmissionID"
// Match until "/"
idx := strings.IndexByte(elem, '/')
if idx < 0 {
idx = len(elem)
}
args[0] = elem[:idx]
elem = elem[idx:]
if len(elem) == 0 {
switch method {
case "GET":
r.name = "GetSubmission"
r.summary = "Retrieve map with ID"
r.operationID = "getSubmission"
r.pathPattern = "/submissions/{SubmissionID}"
r.args = args
r.count = 1
return r, true
default:
return
}
}
switch elem[0] {
case '/': // Prefix: "/"
origElem := elem
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
break
}
switch elem[0] {
case 'c': // Prefix: "completed"
origElem := elem
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "PATCH":
r.name = "PatchSubmissionCompleted"
r.summary = "Retrieve map with ID"
r.operationID = "patchSubmissionCompleted"
r.pathPattern = "/submissions/{SubmissionID}/completed"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
case 'm': // Prefix: "model"
origElem := elem
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "PATCH":
r.name = "PatchSubmissionModel"
r.summary = "Update model following role restrictions"
r.operationID = "patchSubmissionModel"
r.pathPattern = "/submissions/{SubmissionID}/model"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
case 's': // Prefix: "status"
origElem := elem
if l := len("status"); len(elem) >= l && elem[0:l] == "status" {
elem = elem[l:]
} else {
break
}
if len(elem) == 0 {
// Leaf node.
switch method {
case "PATCH":
r.name = "PatchSubmissionStatus"
r.summary = "Update status following role restrictions"
r.operationID = "patchSubmissionStatus"
r.pathPattern = "/submissions/{SubmissionID}/status"
r.args = args
r.count = 1
return r, true
default:
return
}
}
elem = origElem
}
elem = origElem
}
elem = origElem
}
elem = origElem
}
}
return r, false
}

View File

@@ -1,524 +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)
}
// 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
}
// NewOptBool returns new OptBool with value set to v.
func NewOptBool(v bool) OptBool {
return OptBool{
Value: v,
Set: true,
}
}
// OptBool is optional bool.
type OptBool struct {
Value bool
Set bool
}
// IsSet returns true if OptBool was set.
func (o OptBool) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptBool) Reset() {
var v bool
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptBool) SetTo(v bool) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptBool) Get() (v bool, ok bool) {
if !o.Set {
return v, false
}
return o.Value, true
}
// Or returns value if set, or given parameter if does not.
func (o OptBool) Or(d bool) bool {
if v, ok := o.Get(); ok {
return v
}
return d
}
// NewOptInt32 returns new OptInt32 with value set to v.
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
}
// NewOptSubmissionFilter returns new OptSubmissionFilter with value set to v.
func NewOptSubmissionFilter(v SubmissionFilter) OptSubmissionFilter {
return OptSubmissionFilter{
Value: v,
Set: true,
}
}
// OptSubmissionFilter is optional SubmissionFilter.
type OptSubmissionFilter struct {
Value SubmissionFilter
Set bool
}
// IsSet returns true if OptSubmissionFilter was set.
func (o OptSubmissionFilter) IsSet() bool { return o.Set }
// Reset unsets value.
func (o *OptSubmissionFilter) Reset() {
var v SubmissionFilter
o.Value = v
o.Set = false
}
// SetTo sets value to v.
func (o *OptSubmissionFilter) SetTo(v SubmissionFilter) {
o.Set = true
o.Value = v
}
// Get returns value and boolean that denotes whether value was set.
func (o OptSubmissionFilter) Get() (v SubmissionFilter, 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 OptSubmissionFilter) Or(d SubmissionFilter) SubmissionFilter {
if v, ok := o.Get(); ok {
return v
}
return d
}
// Ref: #/components/schemas/Pagination
type Pagination struct {
Page int32 `json:"Page"`
Limit int32 `json:"Limit"`
}
// GetPage returns the value of Page.
func (s *Pagination) GetPage() int32 {
return s.Page
}
// GetLimit returns the value of Limit.
func (s *Pagination) GetLimit() int32 {
return s.Limit
}
// SetPage sets the value of Page.
func (s *Pagination) SetPage(val int32) {
s.Page = val
}
// SetLimit sets the value of Limit.
func (s *Pagination) SetLimit(val int32) {
s.Limit = val
}
// PatchSubmissionCompletedOK is response for PatchSubmissionCompleted operation.
type PatchSubmissionCompletedOK struct{}
// PatchSubmissionModelOK is response for PatchSubmissionModel operation.
type PatchSubmissionModelOK struct{}
// PatchSubmissionStatusOK is response for PatchSubmissionStatus operation.
type PatchSubmissionStatusOK struct{}
// Ref: #/components/schemas/Submission
type Submission struct {
ID OptInt64 `json:"ID"`
DisplayName OptString `json:"DisplayName"`
Creator OptString `json:"Creator"`
GameID OptInt32 `json:"GameID"`
Date OptInt64 `json:"Date"`
Submitter OptInt64 `json:"Submitter"`
AssetID OptInt64 `json:"AssetID"`
AssetVersion OptInt64 `json:"AssetVersion"`
Completed OptBool `json:"Completed"`
SubmissionType OptInt32 `json:"SubmissionType"`
TargetAssetID OptInt64 `json:"TargetAssetID"`
StatusID OptInt32 `json:"StatusID"`
}
// GetID returns the value of ID.
func (s *Submission) GetID() OptInt64 {
return s.ID
}
// GetDisplayName returns the value of DisplayName.
func (s *Submission) GetDisplayName() OptString {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *Submission) GetCreator() OptString {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *Submission) GetGameID() OptInt32 {
return s.GameID
}
// GetDate returns the value of Date.
func (s *Submission) GetDate() OptInt64 {
return s.Date
}
// GetSubmitter returns the value of Submitter.
func (s *Submission) GetSubmitter() OptInt64 {
return s.Submitter
}
// GetAssetID returns the value of AssetID.
func (s *Submission) GetAssetID() OptInt64 {
return s.AssetID
}
// GetAssetVersion returns the value of AssetVersion.
func (s *Submission) GetAssetVersion() OptInt64 {
return s.AssetVersion
}
// GetCompleted returns the value of Completed.
func (s *Submission) GetCompleted() OptBool {
return s.Completed
}
// GetSubmissionType returns the value of SubmissionType.
func (s *Submission) GetSubmissionType() OptInt32 {
return s.SubmissionType
}
// GetTargetAssetID returns the value of TargetAssetID.
func (s *Submission) GetTargetAssetID() OptInt64 {
return s.TargetAssetID
}
// GetStatusID returns the value of StatusID.
func (s *Submission) GetStatusID() OptInt32 {
return s.StatusID
}
// SetID sets the value of ID.
func (s *Submission) SetID(val OptInt64) {
s.ID = val
}
// SetDisplayName sets the value of DisplayName.
func (s *Submission) SetDisplayName(val OptString) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *Submission) SetCreator(val OptString) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *Submission) SetGameID(val OptInt32) {
s.GameID = val
}
// SetDate sets the value of Date.
func (s *Submission) SetDate(val OptInt64) {
s.Date = val
}
// SetSubmitter sets the value of Submitter.
func (s *Submission) SetSubmitter(val OptInt64) {
s.Submitter = val
}
// SetAssetID sets the value of AssetID.
func (s *Submission) SetAssetID(val OptInt64) {
s.AssetID = val
}
// SetAssetVersion sets the value of AssetVersion.
func (s *Submission) SetAssetVersion(val OptInt64) {
s.AssetVersion = val
}
// SetCompleted sets the value of Completed.
func (s *Submission) SetCompleted(val OptBool) {
s.Completed = val
}
// SetSubmissionType sets the value of SubmissionType.
func (s *Submission) SetSubmissionType(val OptInt32) {
s.SubmissionType = val
}
// SetTargetAssetID sets the value of TargetAssetID.
func (s *Submission) SetTargetAssetID(val OptInt64) {
s.TargetAssetID = val
}
// SetStatusID sets the value of StatusID.
func (s *Submission) SetStatusID(val OptInt32) {
s.StatusID = val
}
// Ref: #/components/schemas/SubmissionFilter
type SubmissionFilter struct {
ID OptInt64 `json:"ID"`
DisplayName OptString `json:"DisplayName"`
Creator OptString `json:"Creator"`
GameID OptInt32 `json:"GameID"`
Date OptInt64 `json:"Date"`
}
// GetID returns the value of ID.
func (s *SubmissionFilter) GetID() OptInt64 {
return s.ID
}
// GetDisplayName returns the value of DisplayName.
func (s *SubmissionFilter) GetDisplayName() OptString {
return s.DisplayName
}
// GetCreator returns the value of Creator.
func (s *SubmissionFilter) GetCreator() OptString {
return s.Creator
}
// GetGameID returns the value of GameID.
func (s *SubmissionFilter) GetGameID() OptInt32 {
return s.GameID
}
// GetDate returns the value of Date.
func (s *SubmissionFilter) GetDate() OptInt64 {
return s.Date
}
// SetID sets the value of ID.
func (s *SubmissionFilter) SetID(val OptInt64) {
s.ID = val
}
// SetDisplayName sets the value of DisplayName.
func (s *SubmissionFilter) SetDisplayName(val OptString) {
s.DisplayName = val
}
// SetCreator sets the value of Creator.
func (s *SubmissionFilter) SetCreator(val OptString) {
s.Creator = val
}
// SetGameID sets the value of GameID.
func (s *SubmissionFilter) SetGameID(val OptInt32) {
s.GameID = val
}
// SetDate sets the value of Date.
func (s *SubmissionFilter) SetDate(val OptInt64) {
s.Date = val
}

View File

@@ -1,70 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
)
// Handler handles operations described by OpenAPI v3 specification.
type Handler interface {
// CreateSubmission implements createSubmission operation.
//
// Create new submission.
//
// POST /submissions
CreateSubmission(ctx context.Context) (*Submission, error)
// GetSubmission implements getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error)
// PatchSubmissionCompleted implements patchSubmissionCompleted operation.
//
// Retrieve map with ID.
//
// PATCH /submissions/{SubmissionID}/completed
PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error
// PatchSubmissionModel implements patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// PATCH /submissions/{SubmissionID}/model
PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error
// PatchSubmissionStatus implements patchSubmissionStatus operation.
//
// Update status following role restrictions.
//
// PATCH /submissions/{SubmissionID}/status
PatchSubmissionStatus(ctx context.Context, params PatchSubmissionStatusParams) 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,76 +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{}
// CreateSubmission implements createSubmission operation.
//
// Create new submission.
//
// POST /submissions
func (UnimplementedHandler) CreateSubmission(ctx context.Context) (r *Submission, _ error) {
return r, ht.ErrNotImplemented
}
// GetSubmission implements getSubmission operation.
//
// Retrieve map with ID.
//
// GET /submissions/{SubmissionID}
func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmissionParams) (r *Submission, _ error) {
return r, ht.ErrNotImplemented
}
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r []Submission, _ error) {
return r, ht.ErrNotImplemented
}
// PatchSubmissionCompleted implements patchSubmissionCompleted operation.
//
// Retrieve map with ID.
//
// PATCH /submissions/{SubmissionID}/completed
func (UnimplementedHandler) PatchSubmissionCompleted(ctx context.Context, params PatchSubmissionCompletedParams) error {
return ht.ErrNotImplemented
}
// PatchSubmissionModel implements patchSubmissionModel operation.
//
// Update model following role restrictions.
//
// PATCH /submissions/{SubmissionID}/model
func (UnimplementedHandler) PatchSubmissionModel(ctx context.Context, params PatchSubmissionModelParams) error {
return ht.ErrNotImplemented
}
// PatchSubmissionStatus implements patchSubmissionStatus operation.
//
// Update status following role restrictions.
//
// PATCH /submissions/{SubmissionID}/status
func (UnimplementedHandler) PatchSubmissionStatus(ctx context.Context, params PatchSubmissionStatusParams) 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,314 +0,0 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"math/bits"
"strconv"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/conv"
"github.com/ogen-go/ogen/uri"
"github.com/ogen-go/ogen/validate"
)
// EncodeURI encodes Pagination as URI form.
func (s *Pagination) EncodeURI(e uri.Encoder) error {
if err := e.EncodeField("Page", func(e uri.Encoder) error {
return e.EncodeValue(conv.Int32ToString(s.Page))
}); err != nil {
return errors.Wrap(err, "encode field \"Page\"")
}
if err := e.EncodeField("Limit", func(e uri.Encoder) error {
return e.EncodeValue(conv.Int32ToString(s.Limit))
}); err != nil {
return errors.Wrap(err, "encode field \"Limit\"")
}
return nil
}
var uriFieldsNameOfPagination = [2]string{
0: "Page",
1: "Limit",
}
// DecodeURI decodes Pagination from URI form.
func (s *Pagination) DecodeURI(d uri.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode Pagination to nil")
}
var requiredBitSet [1]uint8
if err := d.DecodeFields(func(k string, d uri.Decoder) error {
switch k {
case "Page":
requiredBitSet[0] |= 1 << 0
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt32(val)
if err != nil {
return err
}
s.Page = c
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Page\"")
}
case "Limit":
requiredBitSet[0] |= 1 << 1
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt32(val)
if err != nil {
return err
}
s.Limit = c
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Limit\"")
}
default:
return nil
}
return nil
}); err != nil {
return errors.Wrap(err, "decode Pagination")
}
// Validate required fields.
var failures []validate.FieldError
for i, mask := range [1]uint8{
0b00000011,
} {
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
// Mask only required fields and check equality to mask using XOR.
//
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
// Bits of fields which would be set are actually bits of missed fields.
missed := bits.OnesCount8(result)
for bitN := 0; bitN < missed; bitN++ {
bitIdx := bits.TrailingZeros8(result)
fieldIdx := i*8 + bitIdx
var name string
if fieldIdx < len(uriFieldsNameOfPagination) {
name = uriFieldsNameOfPagination[fieldIdx]
} else {
name = strconv.Itoa(fieldIdx)
}
failures = append(failures, validate.FieldError{
Name: name,
Error: validate.ErrFieldRequired,
})
// Reset bit.
result &^= 1 << bitIdx
}
}
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}
// EncodeURI encodes SubmissionFilter as URI form.
func (s *SubmissionFilter) EncodeURI(e uri.Encoder) error {
if err := e.EncodeField("ID", func(e uri.Encoder) error {
if val, ok := s.ID.Get(); ok {
return e.EncodeValue(conv.Int64ToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"ID\"")
}
if err := e.EncodeField("DisplayName", func(e uri.Encoder) error {
if val, ok := s.DisplayName.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"DisplayName\"")
}
if err := e.EncodeField("Creator", func(e uri.Encoder) error {
if val, ok := s.Creator.Get(); ok {
return e.EncodeValue(conv.StringToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"Creator\"")
}
if err := e.EncodeField("GameID", func(e uri.Encoder) error {
if val, ok := s.GameID.Get(); ok {
return e.EncodeValue(conv.Int32ToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"GameID\"")
}
if err := e.EncodeField("Date", func(e uri.Encoder) error {
if val, ok := s.Date.Get(); ok {
return e.EncodeValue(conv.Int64ToString(val))
}
return nil
}); err != nil {
return errors.Wrap(err, "encode field \"Date\"")
}
return nil
}
var uriFieldsNameOfSubmissionFilter = [5]string{
0: "ID",
1: "DisplayName",
2: "Creator",
3: "GameID",
4: "Date",
}
// DecodeURI decodes SubmissionFilter from URI form.
func (s *SubmissionFilter) DecodeURI(d uri.Decoder) error {
if s == nil {
return errors.New("invalid: unable to decode SubmissionFilter to nil")
}
if err := d.DecodeFields(func(k string, d uri.Decoder) error {
switch k {
case "ID":
if err := func() error {
var sDotIDVal int64
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
sDotIDVal = c
return nil
}(); err != nil {
return err
}
s.ID.SetTo(sDotIDVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"ID\"")
}
case "DisplayName":
if err := func() error {
var sDotDisplayNameVal string
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
sDotDisplayNameVal = c
return nil
}(); err != nil {
return err
}
s.DisplayName.SetTo(sDotDisplayNameVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"DisplayName\"")
}
case "Creator":
if err := func() error {
var sDotCreatorVal string
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToString(val)
if err != nil {
return err
}
sDotCreatorVal = c
return nil
}(); err != nil {
return err
}
s.Creator.SetTo(sDotCreatorVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Creator\"")
}
case "GameID":
if err := func() error {
var sDotGameIDVal int32
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt32(val)
if err != nil {
return err
}
sDotGameIDVal = c
return nil
}(); err != nil {
return err
}
s.GameID.SetTo(sDotGameIDVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"GameID\"")
}
case "Date":
if err := func() error {
var sDotDateVal int64
if err := func() error {
val, err := d.DecodeValue()
if err != nil {
return err
}
c, err := conv.ToInt64(val)
if err != nil {
return err
}
sDotDateVal = c
return nil
}(); err != nil {
return err
}
s.Date.SetTo(sDotDateVal)
return nil
}(); err != nil {
return errors.Wrap(err, "decode field \"Date\"")
}
default:
return nil
}
return nil
}); err != nil {
return errors.Wrap(err, "decode SubmissionFilter")
}
return nil
}

View File

@@ -1,61 +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 *Pagination) Validate() error {
if s == nil {
return validate.ErrNilPointer
}
var failures []validate.FieldError
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 1,
MaxSet: false,
Max: 0,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Page)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Page",
Error: err,
})
}
if err := func() error {
if err := (validate.Int{
MinSet: true,
Min: 1,
MaxSet: true,
Max: 100,
MinExclusive: false,
MaxExclusive: false,
MultipleOfSet: false,
MultipleOf: 0,
}).Validate(int64(s.Limit)); err != nil {
return errors.Wrap(err, "int")
}
return nil
}(); err != nil {
failures = append(failures, validate.FieldError{
Name: "Limit",
Error: err,
})
}
if len(failures) > 0 {
return &validate.Error{Fields: failures}
}
return nil
}

View File

@@ -0,0 +1,34 @@
package main
import (
"git.itzana.me/strafesnet/maps-service/pkg/cmds"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"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{})
log.SetReportCaller(true)
app := cmds.NewApp()
app.Commands = []*cli.Command{
cmds.NewServeCommand(),
cmds.NewApiCommand(),
}
if err := app.Run(os.Args); err != nil {
log.WithError(err).Fatal("Failed to run app")
}
}

131
compose.yaml Normal file
View File

@@ -0,0 +1,131 @@
version: '3.9'
networks:
maps-service-network:
driver: bridge
services:
nats:
image: docker.io/nats:latest
container_name: nats
command: ["-js"] #"-DVV"
networks:
- maps-service-network
submissions:
image:
maptest-api
container_name: submissions
command: [
# debug
"--debug","serve",
# http service port
"--port","8082",
# internal http endpoints
"--port-internal","8083",
# postgres
"--pg-host","10.0.0.29",
"--pg-port","5432",
"--pg-db","maps",
"--pg-user","quat",
"--pg-password","happypostgresuser",
# other hosts
"--nats-host","nats:4222",
"--auth-rpc-host","authrpc:8081",
"--data-rpc-host","dataservice:9000",
]
env_file:
- /home/quat/auth-compose/strafesnet_staging.env
depends_on:
- authrpc
- nats
networks:
- maps-service-network
ports:
- "8082:8082"
web:
image:
maptest-frontend
networks:
- maps-service-network
ports:
- "3000:3000"
environment:
- API_HOST=http://submissions:8082/v1
- AUTH_HOST=http://localhost:8080/
validation:
image:
maptest-validator
container_name: validation
env_file:
- /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
# the validation will panic if the nats stream is not created
- submissions
- dataservice
networks:
- maps-service-network
dataservice:
image: registry.itzana.me/strafesnet/data-service:master
container_name: dataservice
environment:
- DEBUG=true
- PG_HOST=10.0.0.29
- PG_PORT=5432
- PG_USER=quat
- PG_DB=data
- PG_PASS=happypostgresuser
networks:
- maps-service-network
authredis:
image: docker.io/redis:latest
container_name: authredis
volumes:
- redis-data:/data
command: ["redis-server", "--appendonly", "yes"]
networks:
- maps-service-network
authrpc:
image: registry.itzana.me/strafesnet/auth-service:staging
container_name: authrpc
command: ["serve", "rpc"]
environment:
- REDIS_ADDR=authredis:6379
- RBX_GROUP_ID=17032139
env_file:
- /home/quat/auth-compose/auth-service.env
depends_on:
- authredis
networks:
- maps-service-network
logging:
driver: "none"
auth-web:
image: registry.itzana.me/strafesnet/auth-service:staging
command: ["serve", "web"]
environment:
- REDIS_ADDR=authredis:6379
env_file:
- /home/quat/auth-compose/auth-service.env
depends_on:
- authredis
networks:
- maps-service-network
ports:
- "8080:8080"
volumes:
redis-data:

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,3 +1,4 @@
package main
//go:generate go run github.com/ogen-go/ogen/cmd/ogen@latest --target api --clean openapi.yaml
//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

109
go.mod
View File

@@ -1,42 +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-20240302215338-8ebbc7cffb0a
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/ogen-go/ogen v1.2.1
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/metric v1.32.0
go.opentelemetry.io/otel/trace v1.32.0
google.golang.org/grpc v1.64.0
github.com/go-faster/jx v1.2.0
github.com/nats-io/nats.go v1.37.0
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/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.6.0
gorm.io/gorm v1.25.12
)
require google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect
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-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/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
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.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
github.com/segmentio/asm v1.2.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
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
// google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.34.1 // 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
)

388
go.sum
View File

@@ -1,81 +1,415 @@
git.itzana.me/strafesnet/go-grpc v0.0.0-20240302215338-8ebbc7cffb0a h1:679jxkSaW3ZEj0XW6v+sr3Wr3LcmHRbbDLmo80xty5s=
git.itzana.me/strafesnet/go-grpc v0.0.0-20240302215338-8ebbc7cffb0a/go.mod h1:X7XTRUScRkBWq8q8bplbeso105RPDlnY7J6Wy1IwBMs=
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/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=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
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=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
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=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
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.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=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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-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/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/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.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/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
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.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=
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/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=
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=
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.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/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
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.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.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/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
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.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=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
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.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=
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.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.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,33 +0,0 @@
package controller
import (
"context"
"git.itzana.me/strafesnet/maps-service/internal/datastore"
"git.itzana.me/strafesnet/maps-service/api"
)
type Submissions struct {
Store datastore.Datastore
}
func (m Submissions) Get(ctx context.Context, params *api.GetSubmissionParams) (*api.Submission, error) {
item, err := m.Store.Submissions().Get(ctx, params.SubmissionID)
if err != nil {
return nil, err
}
return &api.Submission{
ID: api.NewOptInt64(item.ID),
DisplayName: api.NewOptString(item.DisplayName),
Creator: api.NewOptString(item.Creator),
GameID: api.NewOptInt32(item.GameID),
Date: api.NewOptInt64(item.Date.Unix()),
Submitter: api.NewOptInt64(item.Submitter),
AssetID: api.NewOptInt64(item.AssetID),
AssetVersion: api.NewOptInt64(item.AssetVersion),
Completed: api.NewOptBool(item.Completed),
SubmissionType: api.NewOptInt32(item.SubmissionType),
TargetAssetID: api.NewOptInt64(item.TargetAssetID),
StatusID: api.NewOptInt32(item.StatusID),
}, nil
}

View File

@@ -1,9 +0,0 @@
package controller
import (
"git.itzana.me/strafesnet/maps-service/internal/datastore"
)
type Users struct {
Store datastore.Datastore
}

View File

@@ -1,36 +0,0 @@
package datastore
import (
"context"
"errors"
"git.itzana.me/strafesnet/maps-service/internal/model"
)
var (
ErrNotExist = errors.New("resource does not exist")
)
type Datastore interface {
Users() Users
Submissions() Submissions
}
type Users interface {
Get(ctx context.Context, id int64) (model.User, error)
GetList(ctx context.Context, id []int64) ([]model.User, error)
Create(ctx context.Context, user model.User) (model.User, 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.User, error)
}
type Submissions interface {
Get(ctx context.Context, id int64) (model.Submission, error)
GetList(ctx context.Context, id []int64) ([]model.Submission, error)
Create(ctx context.Context, time model.Submission) (model.Submission, 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.Submission, error)
}

View File

@@ -1,48 +0,0 @@
package gormstore
import (
"fmt"
"os"
"time"
"git.itzana.me/strafesnet/maps-service/internal/datastore"
"git.itzana.me/strafesnet/maps-service/internal/model"
"git.itzana.me/strafesnet/utils/logger"
"github.com/eko/gocache/lib/v4/cache"
gocache_store "github.com/eko/gocache/store/go_cache/v4"
gocache "github.com/patrickmn/go-cache"
log "github.com/sirupsen/logrus"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func New(migrate bool) (datastore.Datastore, error) {
db, err := gorm.Open(postgres.Open(fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s", os.Getenv("PG_HOST"), os.Getenv("PG_USER"), os.Getenv("PG_PASS"), os.Getenv("PG_DB"), os.Getenv("PG_PORT"))), &gorm.Config{
Logger: logger.New()})
if err != nil {
log.WithFields(log.Fields{
"PG_USER": os.Getenv("PG_USER"),
"PG_HOST": os.Getenv("PG_HOST"),
"PG_PORT": os.Getenv("PG_PORT"),
"PG_DB": os.Getenv("PG_DB"),
"error": err,
}).Errorln("failed to connect to database")
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(25)
if migrate {
if err := db.AutoMigrate(&model.User{}, &model.Submission{}); err != nil {
log.WithField("error", err).Errorln("database migration failed")
return nil, err
}
}
return &Gormstore{db, cache.New[[]byte](gocache_store.NewGoCache(gocache.New(5*time.Minute, 10*time.Minute)))}, nil
}

View File

@@ -1,20 +0,0 @@
package gormstore
import (
"git.itzana.me/strafesnet/maps-service/internal/datastore"
"github.com/eko/gocache/lib/v4/cache"
"gorm.io/gorm"
)
type Gormstore struct {
db *gorm.DB
cache *cache.Cache[[]byte]
}
func (g Gormstore) Users() datastore.Users {
return &Users{db: g.db}
}
func (g Gormstore) Submissions() datastore.Submissions {
return &Submissions{db: g.db}
}

View File

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

View File

@@ -1,72 +0,0 @@
package gormstore
import (
"context"
"git.itzana.me/strafesnet/maps-service/internal/datastore"
"git.itzana.me/strafesnet/maps-service/internal/model"
"gorm.io/gorm"
)
type Users struct {
db *gorm.DB
}
func (u Users) Get(ctx context.Context, id int64) (model.User, error) {
var user model.User
if err := u.db.WithContext(ctx).First(&user, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return user, datastore.ErrNotExist
}
return user, err
}
return user, nil
}
func (u Users) GetList(ctx context.Context, id []int64) ([]model.User, error) {
var user []model.User
if err := u.db.WithContext(ctx).Find(&user, "id IN ?", id).Error; err != nil {
return user, err
}
return user, nil
}
func (u Users) Create(ctx context.Context, user model.User) (model.User, error) {
if err := u.db.WithContext(ctx).Create(&user).Error; err != nil {
return user, err
}
return user, nil
}
func (u Users) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := u.db.WithContext(ctx).Model(&model.User{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (u Users) Delete(ctx context.Context, id int64) error {
if err := u.db.WithContext(ctx).Delete(&model.User{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (u Users) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.User, error) {
var users []model.User
if err := u.db.WithContext(ctx).Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&users).Error; err != nil {
return nil, err
}
return users, nil
}

View File

@@ -1,18 +0,0 @@
package model
import "time"
type Submission struct {
ID int64
DisplayName string
Creator string
GameID int32
Date time.Time
Submitter int64 // UserID
AssetID int64
AssetVersion int64
Completed bool
SubmissionType int32 // 1=New 2=Fix
TargetAssetID int64 // where to upload map fix
StatusID int32
}

View File

@@ -1,7 +0,0 @@
package model
type User struct {
ID int64
Username string `gorm:"not null"`
StateID int32 `gorm:"not null;default:0"`
}

File diff suppressed because it is too large Load Diff

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) {

8404
pkg/api/oas_client_gen.go Normal file

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

12072
pkg/api/oas_handlers_gen.go Normal file

File diff suppressed because it is too large Load Diff

4836
pkg/api/oas_json_gen.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
// Code generated by ogen, DO NOT EDIT.
package api
// OperationName is the ogen operation name
type OperationName = string
const (
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"
UpdateMapfixDescriptionOperation OperationName = "UpdateMapfixDescription"
UpdateMapfixModelOperation OperationName = "UpdateMapfixModel"
UpdateScriptOperation OperationName = "UpdateScript"
UpdateScriptPolicyOperation OperationName = "UpdateScriptPolicy"
UpdateSubmissionModelOperation OperationName = "UpdateSubmissionModel"
)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
// 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 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,
) 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 encodeCreateMapfixAuditCommentRequest(
req CreateMapfixAuditCommentReq,
r *http.Request,
) error {
const contentType = "text/plain"
body := req
ht.SetBody(r, body, contentType)
return nil
}
func encodeCreateScriptRequest(
req *ScriptCreate,
r *http.Request,
) 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 *SubmissionTriggerCreate,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeCreateSubmissionAdminRequest(
req *SubmissionTriggerCreate,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeCreateSubmissionAuditCommentRequest(
req CreateSubmissionAuditCommentReq,
r *http.Request,
) error {
const contentType = "text/plain"
body := req
ht.SetBody(r, body, contentType)
return nil
}
func encodeReleaseSubmissionsRequest(
req []ReleaseInfo,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
e.ArrStart()
for _, elem := range req {
elem.Encode(e)
}
e.ArrEnd()
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeUpdateMapfixDescriptionRequest(
req UpdateMapfixDescriptionReq,
r *http.Request,
) error {
const contentType = "text/plain"
body := req
ht.SetBody(r, body, contentType)
return nil
}
func encodeUpdateScriptRequest(
req *ScriptUpdate,
r *http.Request,
) error {
const contentType = "application/json"
e := new(jx.Encoder)
{
req.Encode(e)
}
encoded := e.Bytes()
ht.SetBody(r, bytes.NewReader(encoded), contentType)
return nil
}
func encodeUpdateScriptPolicyRequest(
req *ScriptPolicyUpdate,
r *http.Request,
) 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

@@ -0,0 +1,740 @@
// Code generated by ogen, DO NOT EDIT.
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"
)
func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent, 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))
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 encodeActionMapfixResetSubmittingResponse(response *ActionMapfixResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixRetryValidateResponse(response *ActionMapfixRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionMapfixRevokeResponse(response *ActionMapfixRevokeNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
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))
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))
return nil
}
func encodeActionMapfixTriggerValidateResponse(response *ActionMapfixTriggerValidateNoContent, 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 encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNoContent, 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))
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 encodeActionSubmissionResetSubmittingResponse(response *ActionSubmissionResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionRetryValidateResponse(response *ActionSubmissionRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionRevokeResponse(response *ActionSubmissionRevokeNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeActionSubmissionTriggerSubmitResponse(response *ActionSubmissionTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
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))
return nil
}
func encodeActionSubmissionTriggerValidateResponse(response *ActionSubmissionTriggerValidateNoContent, 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 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)
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 encodeCreateMapfixAuditCommentResponse(response *CreateMapfixAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeCreateScriptResponse(response *ScriptID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
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 *OperationID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
span.SetStatus(codes.Ok, http.StatusText(201))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeCreateSubmissionAdminResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
span.SetStatus(codes.Ok, http.StatusText(201))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeCreateSubmissionAuditCommentResponse(response *CreateSubmissionAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeDeleteScriptResponse(response *DeleteScriptNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeDeleteScriptPolicyResponse(response *DeleteScriptPolicyNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func 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)
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 encodeGetMapfixResponse(response *Mapfix, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeGetOperationResponse(response *Operation, 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 encodeGetScriptResponse(response *Script, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeGetScriptPolicyResponse(response *ScriptPolicy, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func 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)
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 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)
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 encodeListMapfixesResponse(response *Mapfixes, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeListMapsResponse(response []Map, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
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 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 encodeListSubmissionAuditEventsResponse(response []AuditEvent, 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 encodeListSubmissionsResponse(response *Submissions, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(200)
span.SetStatus(codes.Ok, http.StatusText(200))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeReleaseSubmissionsResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(201)
span.SetStatus(codes.Ok, http.StatusText(201))
e := new(jx.Encoder)
response.Encode(e)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeSessionRolesResponse(response *Roles, 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 encodeSessionUserResponse(response *User, 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 encodeSessionValidateResponse(response bool, 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.Bool(response)
if _, err := e.WriteTo(w); err != nil {
return errors.Wrap(err, "write")
}
return nil
}
func encodeSetMapfixCompletedResponse(response *SetMapfixCompletedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeSetSubmissionCompletedResponse(response *SetSubmissionCompletedNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateMapfixDescriptionResponse(response *UpdateMapfixDescriptionNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateMapfixModelResponse(response *UpdateMapfixModelNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateScriptResponse(response *UpdateScriptNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateScriptPolicyResponse(response *UpdateScriptPolicyNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
func encodeUpdateSubmissionModelResponse(response *UpdateSubmissionModelNoContent, w http.ResponseWriter, span trace.Span) error {
w.WriteHeader(204)
span.SetStatus(codes.Ok, http.StatusText(204))
return nil
}
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
}

3565
pkg/api/oas_router_gen.go Normal file

File diff suppressed because it is too large Load Diff

2375
pkg/api/oas_schemas_gen.go Normal file

File diff suppressed because it is too large Load Diff

123
pkg/api/oas_security_gen.go Normal file
View File

@@ -0,0 +1,123 @@
// Code generated by ogen, DO NOT EDIT.
package api
import (
"context"
"net/http"
"strings"
"github.com/go-faster/errors"
"github.com/ogen-go/ogen/ogenerrors"
)
// SecurityHandler is handler for security parameters.
type SecurityHandler interface {
// HandleCookieAuth handles cookieAuth security.
HandleCookieAuth(ctx context.Context, operationName OperationName, t CookieAuth) (context.Context, error)
}
func findAuthorization(h http.Header, prefix string) (string, bool) {
v, ok := h["Authorization"]
if !ok {
return "", false
}
for _, vv := range v {
scheme, value, ok := strings.Cut(vv, " ")
if !ok || !strings.EqualFold(scheme, prefix) {
continue
}
return value, true
}
return "", false
}
var operationRolesCookieAuth = map[string][]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{},
UpdateMapfixDescriptionOperation: []string{},
UpdateMapfixModelOperation: []string{},
UpdateScriptOperation: []string{},
UpdateScriptPolicyOperation: []string{},
UpdateSubmissionModelOperation: []string{},
}
func (s *Server) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) (context.Context, bool, error) {
var t CookieAuth
const parameterName = "session_id"
var value string
switch cookie, err := req.Cookie(parameterName); {
case err == nil: // if NO error
value = cookie.Value
case errors.Is(err, http.ErrNoCookie):
return ctx, false, nil
default:
return nil, false, errors.Wrap(err, "get cookie value")
}
t.APIKey = value
t.Roles = operationRolesCookieAuth[operationName]
rctx, err := s.sec.HandleCookieAuth(ctx, operationName, t)
if errors.Is(err, ogenerrors.ErrSkipServerSecurity) {
return nil, false, nil
} else if err != nil {
return nil, false, err
}
return rctx, true, err
}
// SecuritySource is provider of security values (tokens, passwords, etc.).
type SecuritySource interface {
// CookieAuth provides cookieAuth security value.
CookieAuth(ctx context.Context, operationName OperationName) (CookieAuth, error)
}
func (s *Client) securityCookieAuth(ctx context.Context, operationName OperationName, req *http.Request) error {
t, err := s.sec.CookieAuth(ctx, operationName)
if err != nil {
return errors.Wrap(err, "security source \"CookieAuth\"")
}
req.AddCookie(&http.Cookie{
Name: "session_id",
Value: t.APIKey,
})
return nil
}

423
pkg/api/oas_server_gen.go Normal file
View File

@@ -0,0 +1,423 @@
// 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.
//
// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/reset-validating
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
// ActionMapfixReject implements actionMapfixReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
//
// POST /mapfixes/{MapfixID}/status/reject
ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/request-changes
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/reset-submitting
ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
//
// POST /mapfixes/{MapfixID}/status/retry-validate
ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error
// ActionMapfixRevoke implements actionMapfixRevoke operation.
//
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
//
// 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 MapfixUpload changes status from Validated -> Uploading.
//
// POST /mapfixes/{MapfixID}/status/trigger-upload
ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error
// ActionMapfixTriggerValidate implements actionMapfixTriggerValidate operation.
//
// Role Reviewer triggers validation and changes status from Submitted -> Validating.
//
// 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 MapfixUpload manually resets uploading softlock and changes status from Uploading -> Validated.
//
// POST /mapfixes/{MapfixID}/status/reset-uploading
ActionMapfixValidated(ctx context.Context, params ActionMapfixValidatedParams) error
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
//
// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
//
// POST /submissions/{SubmissionID}/status/reset-validating
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
// ActionSubmissionReject implements actionSubmissionReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
//
// POST /submissions/{SubmissionID}/status/reject
ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
//
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/request-changes
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/reset-submitting
ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
//
// POST /submissions/{SubmissionID}/status/retry-validate
ActionSubmissionRetryValidate(ctx context.Context, params ActionSubmissionRetryValidateParams) error
// ActionSubmissionRevoke implements actionSubmissionRevoke operation.
//
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/revoke
ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
//
// 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 SubmissionUpload changes status from Validated -> Uploading.
//
// POST /submissions/{SubmissionID}/status/trigger-upload
ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error
// ActionSubmissionTriggerValidate implements actionSubmissionTriggerValidate operation.
//
// Role Reviewer triggers validation and changes status from Submitted -> Validating.
//
// POST /submissions/{SubmissionID}/status/trigger-validate
ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// 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.
//
// POST /mapfixes
CreateMapfix(ctx context.Context, req *MapfixTriggerCreate) (*OperationID, error)
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /mapfixes/{MapfixID}/comment
CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error
// CreateScript implements createScript operation.
//
// Create a new script.
//
// 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.
//
// Trigger the validator to create a new submission.
//
// POST /submissions
CreateSubmission(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
//
// Trigger the validator to create a new submission.
//
// POST /submissions-admin
CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /submissions/{SubmissionID}/comment
CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
//
// DELETE /scripts/{ScriptID}
DeleteScript(ctx context.Context, params DeleteScriptParams) error
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// 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.
//
// GET /maps/{MapID}
GetMap(ctx context.Context, params GetMapParams) (*Map, error)
// GetMapfix implements getMapfix operation.
//
// Retrieve map with ID.
//
// GET /mapfixes/{MapfixID}
GetMapfix(ctx context.Context, params GetMapfixParams) (*Mapfix, error)
// GetOperation implements getOperation operation.
//
// Retrieve operation with ID.
//
// GET /operations/{OperationID}
GetOperation(ctx context.Context, params GetOperationParams) (*Operation, error)
// GetScript implements getScript operation.
//
// Get the specified script by ID.
//
// GET /scripts/{ScriptID}
GetScript(ctx context.Context, params GetScriptParams) (*Script, error)
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/{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.
//
// GET /mapfixes/{MapfixID}/audit-events
ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) ([]AuditEvent, error)
// ListMapfixes implements listMapfixes operation.
//
// Get list of mapfixes.
//
// GET /mapfixes
ListMapfixes(ctx context.Context, params ListMapfixesParams) (*Mapfixes, error)
// ListMaps implements listMaps operation.
//
// Get list of maps.
//
// GET /maps
ListMaps(ctx context.Context, params ListMapsParams) ([]Map, 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)
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) ([]AuditEvent, error)
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error)
// ReleaseSubmissions implements releaseSubmissions operation.
//
// Release a set of uploaded maps. Role SubmissionRelease.
//
// POST /release-submissions
ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) (*OperationID, error)
// SessionRoles implements sessionRoles operation.
//
// Get list of roles for the current session.
//
// GET /session/roles
SessionRoles(ctx context.Context) (*Roles, error)
// SessionUser implements sessionUser operation.
//
// Get information about the currently logged in user.
//
// GET /session/user
SessionUser(ctx context.Context) (*User, error)
// SessionValidate implements sessionValidate operation.
//
// Ask if the current session is valid.
//
// GET /session/validate
SessionValidate(ctx context.Context) (bool, error)
// SetMapfixCompleted implements setMapfixCompleted operation.
//
// Called by maptest when a player completes the map.
//
// POST /mapfixes/{MapfixID}/completed
SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error
// SetSubmissionCompleted implements setSubmissionCompleted operation.
//
// Called by maptest when a player completes the map.
//
// POST /submissions/{SubmissionID}/completed
SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error
// UpdateMapfixDescription implements updateMapfixDescription operation.
//
// Update description (submitter only).
//
// PATCH /mapfixes/{MapfixID}/description
UpdateMapfixDescription(ctx context.Context, req UpdateMapfixDescriptionReq, params UpdateMapfixDescriptionParams) error
// UpdateMapfixModel implements updateMapfixModel operation.
//
// Update model following role restrictions.
//
// POST /mapfixes/{MapfixID}/model
UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error
// UpdateScript implements updateScript operation.
//
// Update the specified script by ID.
//
// POST /scripts/{ScriptID}
UpdateScript(ctx context.Context, req *ScriptUpdate, params UpdateScriptParams) error
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// POST /script-policy/{ScriptPolicyID}
UpdateScriptPolicy(ctx context.Context, req *ScriptPolicyUpdate, params UpdateScriptPolicyParams) error
// UpdateSubmissionModel implements updateSubmissionModel operation.
//
// Update model following role restrictions.
//
// POST /submissions/{SubmissionID}/model
UpdateSubmissionModel(ctx context.Context, params UpdateSubmissionModelParams) 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
sec SecurityHandler
baseServer
}
// NewServer creates new Server.
func NewServer(h Handler, sec SecurityHandler, opts ...ServerOption) (*Server, error) {
s, err := newServerConfig(opts...).baseServer()
if err != nil {
return nil, err
}
return &Server{
h: h,
sec: sec,
baseServer: s,
}, nil
}

View File

@@ -0,0 +1,601 @@
// 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.
//
// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
//
// POST /mapfixes/{MapfixID}/status/reset-validating
func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixReject implements actionMapfixReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
//
// POST /mapfixes/{MapfixID}/status/reject
func (UnimplementedHandler) ActionMapfixReject(ctx context.Context, params ActionMapfixRejectParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
//
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
//
// POST /mapfixes/{MapfixID}/status/request-changes
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/reset-submitting
func (UnimplementedHandler) ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
//
// POST /mapfixes/{MapfixID}/status/retry-validate
func (UnimplementedHandler) ActionMapfixRetryValidate(ctx context.Context, params ActionMapfixRetryValidateParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixRevoke implements actionMapfixRevoke operation.
//
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
//
// POST /mapfixes/{MapfixID}/status/revoke
func (UnimplementedHandler) ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error {
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.
//
// POST /mapfixes/{MapfixID}/status/trigger-submit
func (UnimplementedHandler) ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error {
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 MapfixUpload changes status from Validated -> Uploading.
//
// POST /mapfixes/{MapfixID}/status/trigger-upload
func (UnimplementedHandler) ActionMapfixTriggerUpload(ctx context.Context, params ActionMapfixTriggerUploadParams) error {
return ht.ErrNotImplemented
}
// ActionMapfixTriggerValidate implements actionMapfixTriggerValidate operation.
//
// Role Reviewer triggers validation and changes status from Submitted -> Validating.
//
// POST /mapfixes/{MapfixID}/status/trigger-validate
func (UnimplementedHandler) ActionMapfixTriggerValidate(ctx context.Context, params ActionMapfixTriggerValidateParams) error {
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 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 {
return ht.ErrNotImplemented
}
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
//
// Role Reviewer manually resets validating softlock and changes status from Validating -> Accepted.
//
// POST /submissions/{SubmissionID}/status/reset-validating
func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionReject implements actionSubmissionReject operation.
//
// Role Reviewer changes status from Submitted -> Rejected.
//
// POST /submissions/{SubmissionID}/status/reject
func (UnimplementedHandler) ActionSubmissionReject(ctx context.Context, params ActionSubmissionRejectParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
//
// Role Reviewer changes status from Validated|Accepted|Submitted -> ChangesRequested.
//
// POST /submissions/{SubmissionID}/status/request-changes
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
//
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
// UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/reset-submitting
func (UnimplementedHandler) ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
//
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
//
// POST /submissions/{SubmissionID}/status/retry-validate
func (UnimplementedHandler) ActionSubmissionRetryValidate(ctx context.Context, params ActionSubmissionRetryValidateParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionRevoke implements actionSubmissionRevoke operation.
//
// Role Submitter changes status from Submitted|ChangesRequested -> UnderConstruction.
//
// POST /submissions/{SubmissionID}/status/revoke
func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
//
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
//
// POST /submissions/{SubmissionID}/status/trigger-submit
func (UnimplementedHandler) ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error {
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 SubmissionUpload changes status from Validated -> Uploading.
//
// POST /submissions/{SubmissionID}/status/trigger-upload
func (UnimplementedHandler) ActionSubmissionTriggerUpload(ctx context.Context, params ActionSubmissionTriggerUploadParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionTriggerValidate implements actionSubmissionTriggerValidate operation.
//
// Role Reviewer triggers validation and changes status from Submitted -> Validating.
//
// POST /submissions/{SubmissionID}/status/trigger-validate
func (UnimplementedHandler) ActionSubmissionTriggerValidate(ctx context.Context, params ActionSubmissionTriggerValidateParams) error {
return ht.ErrNotImplemented
}
// ActionSubmissionValidated implements actionSubmissionValidated operation.
//
// 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.
//
// POST /mapfixes
func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixTriggerCreate) (r *OperationID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /mapfixes/{MapfixID}/comment
func (UnimplementedHandler) CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error {
return ht.ErrNotImplemented
}
// CreateScript implements createScript operation.
//
// Create a new script.
//
// 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.
//
// Trigger the validator to create a new submission.
//
// POST /submissions
func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *SubmissionTriggerCreate) (r *OperationID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
//
// Trigger the validator to create a new submission.
//
// POST /submissions-admin
func (UnimplementedHandler) CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (r *OperationID, _ error) {
return r, ht.ErrNotImplemented
}
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
//
// Post a comment to the audit log.
//
// POST /submissions/{SubmissionID}/comment
func (UnimplementedHandler) CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error {
return ht.ErrNotImplemented
}
// DeleteScript implements deleteScript operation.
//
// Delete the specified script by ID.
//
// DELETE /scripts/{ScriptID}
func (UnimplementedHandler) DeleteScript(ctx context.Context, params DeleteScriptParams) error {
return ht.ErrNotImplemented
}
// DeleteScriptPolicy implements deleteScriptPolicy operation.
//
// Delete the specified script policy by ID.
//
// DELETE /script-policy/{ScriptPolicyID}
func (UnimplementedHandler) DeleteScriptPolicy(ctx context.Context, params DeleteScriptPolicyParams) error {
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.
//
// GET /maps/{MapID}
func (UnimplementedHandler) GetMap(ctx context.Context, params GetMapParams) (r *Map, _ error) {
return r, ht.ErrNotImplemented
}
// GetMapfix implements getMapfix operation.
//
// Retrieve map with ID.
//
// GET /mapfixes/{MapfixID}
func (UnimplementedHandler) GetMapfix(ctx context.Context, params GetMapfixParams) (r *Mapfix, _ error) {
return r, ht.ErrNotImplemented
}
// GetOperation implements getOperation operation.
//
// Retrieve operation with ID.
//
// GET /operations/{OperationID}
func (UnimplementedHandler) GetOperation(ctx context.Context, params GetOperationParams) (r *Operation, _ 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
}
// GetScriptPolicy implements getScriptPolicy operation.
//
// Get the specified script policy by ID.
//
// GET /script-policy/{ScriptPolicyID}
func (UnimplementedHandler) GetScriptPolicy(ctx context.Context, params GetScriptPolicyParams) (r *ScriptPolicy, _ error) {
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.
//
// GET /submissions/{SubmissionID}
func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmissionParams) (r *Submission, _ error) {
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.
//
// GET /mapfixes/{MapfixID}/audit-events
func (UnimplementedHandler) ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) (r []AuditEvent, _ error) {
return r, ht.ErrNotImplemented
}
// ListMapfixes implements listMapfixes operation.
//
// Get list of mapfixes.
//
// GET /mapfixes
func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r *Mapfixes, _ error) {
return r, ht.ErrNotImplemented
}
// ListMaps implements listMaps operation.
//
// Get list of maps.
//
// GET /maps
func (UnimplementedHandler) ListMaps(ctx context.Context, params ListMapsParams) (r []Map, _ 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
}
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
//
// Retrieve a list of audit events.
//
// GET /submissions/{SubmissionID}/audit-events
func (UnimplementedHandler) ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) (r []AuditEvent, _ error) {
return r, ht.ErrNotImplemented
}
// ListSubmissions implements listSubmissions operation.
//
// Get list of submissions.
//
// GET /submissions
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r *Submissions, _ error) {
return r, ht.ErrNotImplemented
}
// ReleaseSubmissions implements releaseSubmissions operation.
//
// Release a set of uploaded maps. Role SubmissionRelease.
//
// POST /release-submissions
func (UnimplementedHandler) ReleaseSubmissions(ctx context.Context, req []ReleaseInfo) (r *OperationID, _ error) {
return r, ht.ErrNotImplemented
}
// SessionRoles implements sessionRoles operation.
//
// Get list of roles for the current session.
//
// GET /session/roles
func (UnimplementedHandler) SessionRoles(ctx context.Context) (r *Roles, _ error) {
return r, ht.ErrNotImplemented
}
// SessionUser implements sessionUser operation.
//
// Get information about the currently logged in user.
//
// GET /session/user
func (UnimplementedHandler) SessionUser(ctx context.Context) (r *User, _ error) {
return r, ht.ErrNotImplemented
}
// SessionValidate implements sessionValidate operation.
//
// Ask if the current session is valid.
//
// GET /session/validate
func (UnimplementedHandler) SessionValidate(ctx context.Context) (r bool, _ error) {
return r, ht.ErrNotImplemented
}
// SetMapfixCompleted implements setMapfixCompleted operation.
//
// Called by maptest when a player completes the map.
//
// POST /mapfixes/{MapfixID}/completed
func (UnimplementedHandler) SetMapfixCompleted(ctx context.Context, params SetMapfixCompletedParams) error {
return ht.ErrNotImplemented
}
// SetSubmissionCompleted implements setSubmissionCompleted operation.
//
// Called by maptest when a player completes the map.
//
// POST /submissions/{SubmissionID}/completed
func (UnimplementedHandler) SetSubmissionCompleted(ctx context.Context, params SetSubmissionCompletedParams) error {
return ht.ErrNotImplemented
}
// UpdateMapfixDescription implements updateMapfixDescription operation.
//
// Update description (submitter only).
//
// PATCH /mapfixes/{MapfixID}/description
func (UnimplementedHandler) UpdateMapfixDescription(ctx context.Context, req UpdateMapfixDescriptionReq, params UpdateMapfixDescriptionParams) error {
return ht.ErrNotImplemented
}
// UpdateMapfixModel implements updateMapfixModel operation.
//
// Update model following role restrictions.
//
// POST /mapfixes/{MapfixID}/model
func (UnimplementedHandler) UpdateMapfixModel(ctx context.Context, params UpdateMapfixModelParams) error {
return ht.ErrNotImplemented
}
// UpdateScript implements updateScript operation.
//
// Update the specified script by ID.
//
// POST /scripts/{ScriptID}
func (UnimplementedHandler) UpdateScript(ctx context.Context, req *ScriptUpdate, params UpdateScriptParams) error {
return ht.ErrNotImplemented
}
// UpdateScriptPolicy implements updateScriptPolicy operation.
//
// Update the specified script policy by ID.
//
// POST /script-policy/{ScriptPolicyID}
func (UnimplementedHandler) UpdateScriptPolicy(ctx context.Context, req *ScriptPolicyUpdate, params UpdateScriptPolicyParams) error {
return ht.ErrNotImplemented
}
// UpdateSubmissionModel implements updateSubmissionModel operation.
//
// Update model following role restrictions.
//
// POST /submissions/{SubmissionID}/model
func (UnimplementedHandler) UpdateSubmissionModel(ctx context.Context, params UpdateSubmissionModelParams) 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
}

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

37
pkg/cmds/root.go Normal file
View File

@@ -0,0 +1,37 @@
package cmds
import (
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"os"
"path/filepath"
)
var (
appName = filepath.Base(os.Args[0])
commonFlag = []cli.Flag{
&cli.BoolFlag{
Name: "debug",
Usage: "Enable debug logging",
Value: false,
Action: func(ctx *cli.Context, debug bool) error {
log.Println("ran")
if debug {
log.SetLevel(log.DebugLevel)
log.SetFormatter(&log.TextFormatter{})
log.SetReportCaller(false)
}
return nil
},
},
}
)
func NewApp() *cli.App {
app := cli.NewApp()
app.Name = appName
app.Usage = "Maps API Service"
app.Flags = commonFlag
return app
}

250
pkg/cmds/serve.go Normal file
View File

@@ -0,0 +1,250 @@
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"
"git.itzana.me/strafesnet/maps-service/pkg/roblox"
"git.itzana.me/strafesnet/maps-service/pkg/service"
"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"
"google.golang.org/grpc/credentials/insecure"
)
func NewServeCommand() *cli.Command {
return &cli.Command{
Name: "serve",
Usage: "Run maps service",
Action: serve,
Flags: []cli.Flag{
&cli.StringFlag{
Name: "pg-host",
Usage: "Host of postgres database",
EnvVars: []string{"PG_HOST"},
Required: true,
},
&cli.IntFlag{
Name: "pg-port",
Usage: "Port of postgres database",
EnvVars: []string{"PG_PORT"},
Required: true,
},
&cli.StringFlag{
Name: "pg-db",
Usage: "Name of database to connect to",
EnvVars: []string{"PG_DB"},
Required: true,
},
&cli.StringFlag{
Name: "pg-user",
Usage: "User to connect with",
EnvVars: []string{"PG_USER"},
Required: true,
},
&cli.StringFlag{
Name: "pg-password",
Usage: "Password to connect with",
EnvVars: []string{"PG_PASSWORD"},
Required: true,
},
&cli.BoolFlag{
Name: "migrate",
Usage: "Run database migrations",
Value: true,
EnvVars: []string{"MIGRATE"},
},
&cli.IntFlag{
Name: "port",
Usage: "Port to listen on",
Value: 8080,
EnvVars: []string{"PORT"},
},
&cli.IntFlag{
Name: "port-internal",
Usage: "Port to listen on for internal api",
Value: 8081,
EnvVars: []string{"PORT_INTERNAL"},
},
&cli.StringFlag{
Name: "auth-rpc-host",
Usage: "Host of auth rpc",
EnvVars: []string{"AUTH_RPC_HOST"},
Value: "auth-service:8090",
},
&cli.StringFlag{
Name: "data-rpc-host",
Usage: "Host of data rpc",
EnvVars: []string{"DATA_RPC_HOST"},
Value: "data-service:9000",
},
&cli.StringFlag{
Name: "nats-host",
Usage: "Host of nats",
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,
},
},
}
}
func serve(ctx *cli.Context) error {
db, err := gormstore.New(ctx)
if err != nil {
log.WithError(err).Fatal("failed to connect database")
}
nc, err := nats.Connect(ctx.String("nats-host"))
if err != nil {
log.WithError(err).Fatal("failed to connect nats")
}
js, err := nc.JetStream()
if err != nil {
log.WithError(err).Fatal("failed to start jetstream")
}
_, err = js.AddStream(&nats.StreamConfig{
Name: "maptest",
Subjects: []string{"maptest.>"},
Retention: nats.WorkQueuePolicy,
})
if err != nil {
log.WithError(err).Fatal("failed to add stream")
}
// 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_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 := web_api.SecurityHandler{
Client: auth.NewAuthServiceClient(conn),
}
srv_external, err := api.NewServer(&svc_external, sec, api.WithPathPrefix("/v1"))
if err != nil {
log.WithError(err).Fatal("failed to initialize api server")
}
grpcServer := grpc.NewServer()
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.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 <- grpcServer.Serve(lis)
}(errChan)
// Second server
go func(errChan chan error) {
errChan <- http.ListenAndServe(fmt.Sprintf(":%d", ctx.Int("port")), srv_external)
}(errChan)
// Wait for the first error or completion of both tasks
for i := 0; i < 2; i++ {
err := <-errChan
if err != nil {
fmt.Println("Exiting due to:", err)
return err
}
}
log.Println("Both servers have stopped.")
return nil
}

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
}

101
pkg/datastore/datastore.go Normal file
View File

@@ -0,0 +1,101 @@
package datastore
import (
"context"
"errors"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
var (
ErrNotExist = errors.New("resource does not exist")
ErroNoRowsAffected = errors.New("query did not affect any rows")
ErrInvalidListSort = errors.New("invalid list sort parameter [1,2,3,4]")
)
type ListSort uint32
const (
ListSortDisabled ListSort = 0
ListSortDisplayNameAscending ListSort = 1
ListSortDisplayNameDescending ListSort = 2
ListSortDateAscending ListSort = 3
ListSortDateDescending ListSort = 4
)
type Datastore interface {
AuditEvents() AuditEvents
Maps() Maps
Mapfixes() Mapfixes
Operations() Operations
Submissions() Submissions
Scripts() Scripts
ScriptPolicy() ScriptPolicy
}
type AuditEvents interface {
Get(ctx context.Context, id int64) (model.AuditEvent, error)
Create(ctx context.Context, smap model.AuditEvent) (model.AuditEvent, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.AuditEvent, error)
}
type 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)
Create(ctx context.Context, smap model.Mapfix) (model.Mapfix, error)
Update(ctx context.Context, id int64, values OptionalMap) error
IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) error
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) (model.Mapfix, error)
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Mapfix, error)
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Mapfix, error)
}
type Operations interface {
Get(ctx context.Context, id int32) (model.Operation, error)
Create(ctx context.Context, smap model.Operation) (model.Operation, error)
Update(ctx context.Context, id int32, values OptionalMap) error
Delete(ctx context.Context, id int32) error
CountSince(ctx context.Context, owner int64, since time.Time) (int64, error)
}
type Submissions interface {
Get(ctx context.Context, id int64) (model.Submission, error)
GetList(ctx context.Context, id []int64) ([]model.Submission, error)
Create(ctx context.Context, smap model.Submission) (model.Submission, error)
Update(ctx context.Context, id int64, values OptionalMap) error
IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) error
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) (model.Submission, error)
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Submission, error)
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Submission, error)
}
type Scripts interface {
Get(ctx context.Context, id int64) (model.Script, error)
Create(ctx context.Context, smap model.Script) (model.Script, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.Script, error)
}
type ScriptPolicy interface {
Get(ctx context.Context, id int64) (model.ScriptPolicy, error)
GetFromHash(ctx context.Context, hash uint64) (model.ScriptPolicy, error)
Create(ctx context.Context, smap model.ScriptPolicy) (model.ScriptPolicy, error)
Update(ctx context.Context, id int64, values OptionalMap) error
Delete(ctx context.Context, id int64) error
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.ScriptPolicy, error)
}

View File

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

View File

@@ -0,0 +1,48 @@
package gormstore
import (
"fmt"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"git.itzana.me/strafesnet/utils/logger"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
func New(ctx *cli.Context) (datastore.Datastore, error) {
db, err := gorm.Open(
postgres.Open(
fmt.Sprintf(
"host=%s user=%s password=%s dbname=%s port=%d",
ctx.String("pg-host"),
ctx.String("pg-user"),
ctx.String("pg-password"),
ctx.String("pg-db"),
ctx.Int("pg-port")),
), &gorm.Config{
Logger: logger.New(),
})
if err != nil {
log.WithError(err).Errorln("failed to connect to database")
return nil, err
}
if ctx.Bool("migrate") {
if err := db.AutoMigrate(
&model.AuditEvent{},
&model.Map{},
&model.Mapfix{},
&model.Operation{},
&model.Submission{},
&model.Script{},
&model.ScriptPolicy{},
); err != nil {
log.WithError(err).Errorln("database migration failed")
return nil, err
}
}
return &Gormstore{db}, nil
}

View File

@@ -0,0 +1,38 @@
package gormstore
import (
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"gorm.io/gorm"
)
type Gormstore struct {
db *gorm.DB
}
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}
}
func (g Gormstore) Operations() datastore.Operations {
return &Operations{db: g.db}
}
func (g Gormstore) Submissions() datastore.Submissions {
return &Submissions{db: g.db}
}
func (g Gormstore) Scripts() datastore.Scripts {
return &Scripts{db: g.db}
}
func (g Gormstore) ScriptPolicy() datastore.ScriptPolicy {
return &ScriptPolicy{db: g.db}
}

View File

@@ -0,0 +1,153 @@
package gormstore
import (
"context"
"errors"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Mapfixes struct {
db *gorm.DB
}
func (env *Mapfixes) Get(ctx context.Context, id int64) (model.Mapfix, error) {
var mapfix model.Mapfix
if err := env.db.First(&mapfix, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mapfix, datastore.ErrNotExist
}
return mapfix, err
}
return mapfix, nil
}
func (env *Mapfixes) GetList(ctx context.Context, id []int64) ([]model.Mapfix, error) {
var mapList []model.Mapfix
if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
return mapList, err
}
return mapList, nil
}
func (env *Mapfixes) Create(ctx context.Context, smap model.Mapfix) (model.Mapfix, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Mapfixes) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Mapfix{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
// the update can only occur if the status matches one of the provided values.
func (env *Mapfixes) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.MapfixStatus, values datastore.OptionalMap) error {
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 result.Error
}
if result.RowsAffected == 0 {
return datastore.ErroNoRowsAffected
}
return nil
}
// the update can only occur if the status matches one of the provided values.
// returns the updated value
func (env *Mapfixes) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values datastore.OptionalMap) (model.Mapfix, error) {
var mapfix model.Mapfix
result := env.db.Model(&mapfix).
Clauses(clause.Returning{}).
Where("id = ?", id).
Where("status_id IN ?", statuses).
Updates(values.Map())
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return mapfix, datastore.ErrNotExist
}
return mapfix, result.Error
}
if result.RowsAffected == 0 {
return mapfix, datastore.ErroNoRowsAffected
}
return mapfix, nil
}
func (env *Mapfixes) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Mapfix{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Mapfixes) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) ([]model.Mapfix, error) {
var maps []model.Mapfix
db := env.db
switch sort {
case datastore.ListSortDisabled:
// No sort
break
case datastore.ListSortDisplayNameAscending:
db=db.Order("display_name ASC")
break
case datastore.ListSortDisplayNameDescending:
db=db.Order("display_name DESC")
break
case datastore.ListSortDateAscending:
db=db.Order("created_at ASC")
break
case datastore.ListSortDateDescending:
db=db.Order("created_at DESC")
break
default:
return nil, datastore.ErrInvalidListSort
}
if err := db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
return nil, err
}
return maps, nil
}
func (env *Mapfixes) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Mapfix, error) {
// grab page items
maps, err := env.List(ctx, filters, page, sort)
if err != nil{
return 0, nil, err
}
// count total with filters
var total int64
if err := env.db.Model(&model.Mapfix{}).Where(filters.Map()).Count(&total).Error; err != nil {
return 0, nil, err
}
return total, maps, 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

@@ -0,0 +1,65 @@
package gormstore
import (
"context"
"errors"
"time"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm"
)
type Operations struct {
db *gorm.DB
}
func (env *Operations) Get(ctx context.Context, id int32) (model.Operation, error) {
var operation model.Operation
if err := env.db.First(&operation, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return operation, datastore.ErrNotExist
}
return operation, err
}
return operation, nil
}
func (env *Operations) Create(ctx context.Context, smap model.Operation) (model.Operation, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Operations) Update(ctx context.Context, id int32, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Operation{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Operations) Delete(ctx context.Context, id int32) error {
if err := env.db.Delete(&model.Operation{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Operations) CountSince(ctx context.Context, owner int64, since time.Time) (int64, error) {
var count int64
if err := env.db.Model(&model.Operation{}).Where("owner = ? AND created_at > ?",owner,since).Count(&count).Error; err != nil {
return count, err
}
return count, nil
}

View File

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

View File

@@ -0,0 +1,85 @@
package gormstore
import (
"context"
"errors"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm"
)
type Scripts struct {
db *gorm.DB
}
func (env *Scripts) Get(ctx context.Context, id int64) (model.Script, error) {
var mdl model.Script
if err := env.db.First(&mdl, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return mdl, datastore.ErrNotExist
}
return mdl, err
}
return mdl, nil
}
func (env *Scripts) GetList(ctx context.Context, id []int64) ([]model.Script, error) {
var mapList []model.Script
if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
return mapList, err
}
return mapList, nil
}
func (env *Scripts) Create(ctx context.Context, smap model.Script) (model.Script, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Scripts) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Script{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
// the update can only occur if the status matches one of the provided values.
func (env *Scripts) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Script{}).Where("id = ?", id).Where("status IN ?", statuses).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Scripts) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Script{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Scripts) List(ctx context.Context, filters datastore.OptionalMap, page model.Page) ([]model.Script, error) {
var maps []model.Script
if err := env.db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
return nil, err
}
return maps, nil
}

View File

@@ -0,0 +1,153 @@
package gormstore
import (
"context"
"errors"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type Submissions struct {
db *gorm.DB
}
func (env *Submissions) Get(ctx context.Context, id int64) (model.Submission, error) {
var submission model.Submission
if err := env.db.First(&submission, id).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return submission, datastore.ErrNotExist
}
return submission, err
}
return submission, nil
}
func (env *Submissions) GetList(ctx context.Context, id []int64) ([]model.Submission, error) {
var mapList []model.Submission
if err := env.db.Find(&mapList, "id IN ?", id).Error; err != nil {
return mapList, err
}
return mapList, nil
}
func (env *Submissions) Create(ctx context.Context, smap model.Submission) (model.Submission, error) {
if err := env.db.Create(&smap).Error; err != nil {
return smap, err
}
return smap, nil
}
func (env *Submissions) Update(ctx context.Context, id int64, values datastore.OptionalMap) error {
if err := env.db.Model(&model.Submission{}).Where("id = ?", id).Updates(values.Map()).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
// the update can only occur if the status matches one of the provided values.
func (env *Submissions) IfStatusThenUpdate(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) error {
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 result.Error
}
if result.RowsAffected == 0 {
return datastore.ErroNoRowsAffected
}
return nil
}
// the update can only occur if the status matches one of the provided values.
// returns the updated value
func (env *Submissions) IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values datastore.OptionalMap) (model.Submission, error) {
var submission model.Submission
result := env.db.Model(&submission).
Clauses(clause.Returning{}).
Where("id = ?", id).
Where("status_id IN ?", statuses).
Updates(values.Map())
if result.Error != nil {
if result.Error == gorm.ErrRecordNotFound {
return submission, datastore.ErrNotExist
}
return submission, result.Error
}
if result.RowsAffected == 0 {
return submission, datastore.ErroNoRowsAffected
}
return submission, nil
}
func (env *Submissions) Delete(ctx context.Context, id int64) error {
if err := env.db.Delete(&model.Submission{}, id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return datastore.ErrNotExist
}
return err
}
return nil
}
func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) ([]model.Submission, error) {
var maps []model.Submission
db := env.db
switch sort {
case datastore.ListSortDisabled:
// No sort
break
case datastore.ListSortDisplayNameAscending:
db=db.Order("display_name ASC")
break
case datastore.ListSortDisplayNameDescending:
db=db.Order("display_name DESC")
break
case datastore.ListSortDateAscending:
db=db.Order("created_at ASC")
break
case datastore.ListSortDateDescending:
db=db.Order("created_at DESC")
break
default:
return nil, datastore.ErrInvalidListSort
}
if err := db.Where(filters.Map()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&maps).Error; err != nil {
return nil, err
}
return maps, nil
}
func (env *Submissions) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Submission, error) {
// grab page items
maps, err := env.List(ctx, filters, page, sort)
if err != nil{
return 0, nil, err
}
// count total with filters
var total int64
if err := env.db.Model(&model.Submission{}).Where(filters.Map()).Count(&total).Error; err != nil {
return 0, nil, err
}
return total, maps, nil
}

75
pkg/model/audit_event.go Normal file
View File

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

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

45
pkg/model/mapfix.go Normal file
View File

@@ -0,0 +1,45 @@
package model
import "time"
type MapfixStatus int32
const (
// Phase: Creation
MapfixStatusUnderConstruction MapfixStatus = 0
MapfixStatusChangesRequested MapfixStatus = 1
// Phase: Review
MapfixStatusSubmitting MapfixStatus = 2
MapfixStatusSubmitted MapfixStatus = 3
// Phase: Testing
MapfixStatusAcceptedUnvalidated MapfixStatus = 4 // pending script review, can re-trigger validation
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
MapfixStatusRejected MapfixStatus = 9
MapfixStatusReleased MapfixStatus = 10
)
type Mapfix struct {
ID int64 `gorm:"primaryKey"`
DisplayName string
Creator string
GameID uint32
CreatedAt time.Time
UpdatedAt time.Time
Submitter uint64 // UserID
AssetID uint64
AssetVersion uint64
ValidatedAssetID uint64
ValidatedAssetVersion uint64
Completed bool // Has this version of the map been completed at least once on maptest
TargetAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
StatusID MapfixStatus
Description string // mapfix description
}

93
pkg/model/nats.go Normal file
View File

@@ -0,0 +1,93 @@
package model
// These represent the information needed in the nats message
// to perform the operation, they are encoded to json
// Requests are sent from maps-service to validator
type CreateSubmissionRequest struct {
// operation_id is passed back in the response message
OperationID int32
ModelID uint64
DisplayName string
Creator string
GameID uint32
Status uint32
Roles uint32
}
type CreateMapfixRequest struct {
OperationID int32
ModelID uint64
TargetAssetID uint64
Description string
}
type CheckSubmissionRequest struct{
SubmissionID int64
ModelID uint64
SkipChecks bool
}
type CheckMapfixRequest struct{
MapfixID int64
ModelID uint64
SkipChecks bool
}
type ValidateSubmissionRequest struct {
// submission_id is passed back in the response message
SubmissionID int64
ModelID uint64
ModelVersion uint64
ValidatedModelID *uint64 // optional value
}
type ValidateMapfixRequest struct {
MapfixID int64
ModelID uint64
ModelVersion uint64
ValidatedModelID *uint64 // optional value
}
// Create a new map
type UploadSubmissionRequest struct {
SubmissionID int64
ModelID uint64
ModelVersion uint64
ModelName string
}
type UploadMapfixRequest struct {
MapfixID int64
ModelID uint64
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
}

19
pkg/model/operation.go Normal file
View File

@@ -0,0 +1,19 @@
package model
import "time"
type OperationStatus int32
const (
OperationStatusCreated OperationStatus = 0
OperationStatusCompleted OperationStatus = 1
OperationStatusFailed OperationStatus = 2
)
type Operation struct {
ID int32 `gorm:"primaryKey"`
CreatedAt time.Time
Owner uint64 // UserID
StatusID OperationStatus
StatusMessage string
Path string // redirect to view completed operation e.g. "/mapfixes/4"
}

28
pkg/model/policy.go Normal file
View File

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

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
)

35
pkg/model/script.go Normal file
View File

@@ -0,0 +1,35 @@
package model
import (
"fmt"
"strconv"
"time"
"github.com/dchest/siphash"
)
// compute the hash of a source code string
func HashSource(source string) uint64{
return siphash.Hash(0, 0, []byte(source))
}
// format a hash value as a hexidecimal string
func HashFormat(hash uint64) string{
return fmt.Sprintf("%016x", hash)
}
// parse a hexidecimal hash string
func HashParse(hash string) (uint64, error){
return strconv.ParseUint(hash, 16, 64)
}
type Script struct {
ID int64 `gorm:"primaryKey"`
Name string
Hash int64 `gorm:"uniqueIndex"` // postgres does not support unsigned integers, so we have to pretend
Source string
ResourceType ResourceType // is this a submission or is it a mapfix
ResourceID int64 // which submission / mapfix did this script first appear in
CreatedAt time.Time
UpdatedAt time.Time
}

43
pkg/model/submission.go Normal file
View File

@@ -0,0 +1,43 @@
package model
import "time"
type SubmissionStatus int32
const (
// Phase: Creation
SubmissionStatusUnderConstruction SubmissionStatus = 0
SubmissionStatusChangesRequested SubmissionStatus = 1
// Phase: Review
SubmissionStatusSubmitting SubmissionStatus = 2
SubmissionStatusSubmitted SubmissionStatus = 3
// Phase: Testing
SubmissionStatusAcceptedUnvalidated SubmissionStatus = 4 // pending script review, can re-trigger validation
SubmissionStatusValidating SubmissionStatus = 5
SubmissionStatusValidated SubmissionStatus = 6
SubmissionStatusUploading SubmissionStatus = 7
SubmissionStatusUploaded SubmissionStatus = 8 // uploaded to the group, but pending release
// Phase: Final SubmissionStatus
SubmissionStatusRejected SubmissionStatus = 9
SubmissionStatusReleased SubmissionStatus = 10
)
type Submission struct {
ID int64 `gorm:"primaryKey"`
DisplayName string
Creator string
GameID uint32
CreatedAt time.Time
UpdatedAt time.Time
Submitter uint64 // UserID
AssetID uint64
AssetVersion uint64
ValidatedAssetID uint64
ValidatedAssetVersion uint64
Completed bool // Has this version of the map been completed at least once on maptest
UploadedAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
StatusID SubmissionStatus
}

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
}

238
pkg/service/audit_events.go Normal file
View File

@@ -0,0 +1,238 @@
package service
import (
"context"
"encoding/json"
"git.itzana.me/strafesnet/go-grpc/users"
"git.itzana.me/strafesnet/maps-service/pkg/api"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
func (svc *Service) ListAuditEvents(ctx context.Context, resource model.Resource, page model.Page) ([]api.AuditEvent, error){
filter := datastore.Optional()
filter.Add("resource_type", resource.Type)
filter.Add("resource_id", resource.ID)
items, err := svc.db.AuditEvents().List(ctx, filter, page)
if err != nil {
return nil, err
}
idMap := make(map[int64]bool)
for _, item := range items {
idMap[int64(item.User)] = true
}
var idList users.IdList
idList.ID = make([]int64,len(idMap))
for userId := range idMap {
idList.ID = append(idList.ID, userId)
}
userList, err := svc.users.GetList(ctx, &idList)
if err != nil {
return nil, err
}
userMap := make(map[int64]*users.UserResponse)
for _,user := range userList.Users {
userMap[user.ID] = user
}
var resp []api.AuditEvent
for _, item := range items {
EventData := api.AuditEventEventData{}
err = EventData.UnmarshalJSON(item.EventData)
if err != nil {
return nil, err
}
username := ""
if userMap[int64(item.User)] != nil {
username = userMap[int64(item.User)].Username
}
resp = append(resp, api.AuditEvent{
ID: item.ID,
Date: item.CreatedAt.Unix(),
User: int64(item.User),
Username: username,
ResourceType: int32(item.ResourceType),
ResourceID: item.ResourceID,
EventType: int32(item.EventType),
EventData: EventData,
})
}
return resp, nil
}
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{
ID: 0,
User: userId,
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,
})
if err != nil {
return err
}
return nil
}
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
}
_, 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 err
}
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
}

116
pkg/service/mapfixes.go Normal file
View File

@@ -0,0 +1,116 @@
package service
import (
"context"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
type MapfixUpdate datastore.OptionalMap
func NewMapfixUpdate() MapfixUpdate {
update := datastore.Optional()
return MapfixUpdate(update)
}
func (update MapfixUpdate) SetDisplayName(display_name string) {
datastore.OptionalMap(update).Add("display_name", display_name)
}
func (update MapfixUpdate) SetCreator(creator string) {
datastore.OptionalMap(update).Add("creator", creator)
}
func (update MapfixUpdate) SetGameID(game_id uint32) {
datastore.OptionalMap(update).Add("game_id", game_id)
}
func (update MapfixUpdate) SetSubmitter(submitter uint64) {
datastore.OptionalMap(update).Add("submitter", submitter)
}
func (update MapfixUpdate) SetAssetID(asset_id uint64) {
datastore.OptionalMap(update).Add("asset_id", asset_id)
}
func (update MapfixUpdate) SetAssetVersion(asset_version uint64) {
datastore.OptionalMap(update).Add("asset_version", asset_version)
}
func (update MapfixUpdate) SetValidatedAssetID(validated_asset_id uint64) {
datastore.OptionalMap(update).Add("validated_asset_id", validated_asset_id)
}
func (update MapfixUpdate) SetValidatedAssetVersion(validated_asset_version uint64) {
datastore.OptionalMap(update).Add("validated_asset_version", validated_asset_version)
}
func (update MapfixUpdate) SetCompleted(completed bool) {
datastore.OptionalMap(update).Add("completed", completed)
}
func (update MapfixUpdate) SetTargetAssetID(target_asset_id uint64) {
datastore.OptionalMap(update).Add("target_asset_id", target_asset_id)
}
func (update MapfixUpdate) SetStatusID(status_id model.MapfixStatus) {
datastore.OptionalMap(update).Add("status_id", status_id)
}
func (update MapfixUpdate) SetDescription(description string) {
datastore.OptionalMap(update).Add("description", description)
}
type MapfixFilter datastore.OptionalMap
func NewMapfixFilter(
) MapfixFilter {
filter := datastore.Optional()
return MapfixFilter(filter)
}
func (update MapfixFilter) SetDisplayName(display_name string) {
datastore.OptionalMap(update).Add("display_name", display_name)
}
func (update MapfixFilter) SetCreator(creator string) {
datastore.OptionalMap(update).Add("creator", creator)
}
func (update MapfixFilter) SetGameID(game_id uint32) {
datastore.OptionalMap(update).Add("game_id", game_id)
}
func (update MapfixFilter) SetSubmitter(submitter uint64) {
datastore.OptionalMap(update).Add("submitter", submitter)
}
func (update MapfixFilter) SetAssetID(asset_id uint64) {
datastore.OptionalMap(update).Add("asset_id", asset_id)
}
func (update MapfixFilter) SetAssetVersion(asset_version uint64) {
datastore.OptionalMap(update).Add("asset_version", asset_version)
}
func (update MapfixFilter) SetTargetAssetID(target_asset_id uint64) {
datastore.OptionalMap(update).Add("target_asset_id", target_asset_id)
}
func (update MapfixFilter) SetStatuses(statuses []model.MapfixStatus) {
datastore.OptionalMap(update).Add("status_id", statuses)
}
func (svc *Service) CreateMapfix(ctx context.Context, script model.Mapfix) (model.Mapfix, error) {
return svc.db.Mapfixes().Create(ctx, script)
}
func (svc *Service) ListMapfixes(ctx context.Context, filter MapfixFilter, page model.Page, sort datastore.ListSort) ([]model.Mapfix, error) {
return svc.db.Mapfixes().List(ctx, datastore.OptionalMap(filter), page, sort)
}
func (svc *Service) ListMapfixesWithTotal(ctx context.Context, filter MapfixFilter, page model.Page, sort datastore.ListSort) (int64, []model.Mapfix, error) {
return svc.db.Mapfixes().ListWithTotal(ctx, datastore.OptionalMap(filter), page, sort)
}
func (svc *Service) DeleteMapfix(ctx context.Context, id int64) error {
return svc.db.Mapfixes().Delete(ctx, id)
}
func (svc *Service) GetMapfix(ctx context.Context, id int64) (model.Mapfix, error) {
return svc.db.Mapfixes().Get(ctx, id)
}
func (svc *Service) UpdateMapfix(ctx context.Context, id int64, pmap MapfixUpdate) error {
return svc.db.Mapfixes().Update(ctx, id, datastore.OptionalMap(pmap))
}
func (svc *Service) UpdateMapfixIfStatus(ctx context.Context, id int64, statuses []model.MapfixStatus, pmap MapfixUpdate) error {
return svc.db.Mapfixes().IfStatusThenUpdate(ctx, id, statuses, datastore.OptionalMap(pmap))
}
func (svc *Service) UpdateAndGetMapfixIfStatus(ctx context.Context, id int64, statuses []model.MapfixStatus, pmap MapfixUpdate) (model.Mapfix, error) {
return svc.db.Mapfixes().IfStatusThenUpdateAndGet(ctx, id, statuses, datastore.OptionalMap(pmap))
}

150
pkg/service/maps.go Normal file
View File

@@ -0,0 +1,150 @@
package service
import (
"context"
"time"
"git.itzana.me/strafesnet/go-grpc/maps"
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
"git.itzana.me/strafesnet/maps-service/pkg/model"
)
// Optional map used to update an object
type MapUpdate datastore.OptionalMap
func NewMapUpdate() MapUpdate {
update := datastore.Optional()
return MapUpdate(update)
}
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 0, err
}
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
}

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