Compare commits
163 Commits
restricted
...
hide-reset
| Author | SHA1 | Date | |
|---|---|---|---|
|
c3f497be48
|
|||
|
a95e6b7a9a
|
|||
|
|
4c1aef9113 | ||
|
|
c98d170423 | ||
|
6d14047f57
|
|||
|
41663624d3
|
|||
|
49b9b41085
|
|||
|
3614018794
|
|||
|
872b98aa74
|
|||
|
d5c8477869
|
|||
|
b600ca582b
|
|||
|
adbcbed9ac
|
|||
|
8f8d685f71
|
|||
|
a669de3c0b
|
|||
|
649b941d5f
|
|||
|
1b4456f30a
|
|||
|
d34a5c7091
|
|||
|
2f36877cb6
|
|||
|
3a124b8190
|
|||
|
6cc6da4879
|
|||
|
123b0c9a81
|
|||
|
54b0abbbf3
|
|||
|
1b0384da11
|
|||
|
e0cebfd80e
|
|||
|
5ba52ecb57
|
|||
|
9e42050a65
|
|||
|
c817bfc8c8
|
|||
|
8f97ca6690
|
|||
|
f220cb62bc
|
|||
|
f090fd7d68
|
|||
|
404e1281ff
|
|||
|
e4f710c83f
|
|||
|
a942c81ea8
|
|||
|
109b24061a
|
|||
|
ddef30984f
|
|||
|
9331f37d70
|
|||
|
c4f910c1f0
|
|||
|
343a4011dd
|
|||
|
c63997d161
|
|||
|
ea58fcedc9
|
|||
|
50e3fb283c
|
|||
|
aa513a7973
|
|||
|
eff9097456
|
|||
|
668c5fef51
|
|||
|
57db5f738e
|
|||
|
3789755a19
|
|||
|
ee6c37ab9d
|
|||
|
12bfbfb0a0
|
|||
|
c57a53692d
|
|||
|
ccf07c5931
|
|||
|
6efab4f411
|
|||
|
34d1db02a5
|
|||
|
d86ed0cdf5
|
|||
|
d19763349e
|
|||
|
5846e92924
|
|||
|
34b8d7475d
|
|||
|
a5daa2df4a
|
|||
|
1b73af9fe2
|
|||
|
8433030562
|
|||
|
8372665fd3
|
|||
|
d24b342738
|
|||
|
796f31aadf
|
|||
|
44f8736838
|
|||
|
b7e5d82c13
|
|||
|
169007f16e
|
|||
|
2519c9faa1
|
|||
|
1ff6bdbd4c
|
|||
|
d1ca9bdab9
|
|||
| c76ff3b687 | |||
| a42501d254 | |||
| f915c51ba4 | |||
| ff9da333eb | |||
| 1dabd216aa | |||
| cc7e890580 | |||
| 99d1b38535 | |||
| 12ca1b7dab | |||
|
fa1b44f172
|
|||
|
03519e9337
|
|||
|
60b6d30379
|
|||
|
19b8f7b7a2
|
|||
|
4f586c6176
|
|||
|
d1a70509b7
|
|||
|
95bfb87c6e
|
|||
|
de0cf37918
|
|||
|
f1fd826c62
|
|||
|
1380a00872
|
|||
|
174a210f81
|
|||
|
67a03f394f
|
|||
|
6eebe404d5
|
|||
|
1d409218a5
|
|||
|
e2c72c90c7
|
|||
|
7334e88b55
|
|||
|
b93c813dec
|
|||
|
926a90329b
|
|||
|
18abbd92ce
|
|||
|
c923a8a076
|
|||
|
d6da6f003e
|
|||
|
0dc7aec395
|
|||
|
c85cb63639
|
|||
|
6c865e8841
|
|||
|
99a082afb5
|
|||
|
434cd295f5
|
|||
|
bfc2a2cbca
|
|||
|
c24db2c3a0
|
|||
|
68f2311658
|
|||
|
163412a253
|
|||
|
044033cabf
|
|||
|
219a15f656
|
|||
|
383bc783a4
|
|||
|
24a5baae77
|
|||
|
4ba3b5cd01
|
|||
|
f610fc1c0f
|
|||
|
e67d679901
|
|||
|
3c3d09c4a7
|
|||
|
d02e3776f3
|
|||
|
77222c84db
|
|||
|
412f34817c
|
|||
|
cac288d73b
|
|||
|
29e414d6e7
|
|||
|
c9ba2e3e6e
|
|||
|
0666685a49
|
|||
|
ff9237e453
|
|||
|
9b5f7e0b0c
|
|||
|
e28c7e8149
|
|||
|
220ea84e22
|
|||
|
7648f407c5
|
|||
|
e0266c5d24
|
|||
|
9ab2e23fa9
|
|||
|
6b2f5e29e7
|
|||
|
d42e89fcb4
|
|||
|
7e881e6ac5
|
|||
|
2d57b945f2
|
|||
|
005e99424e
|
|||
|
a330b1c43b
|
|||
|
d2662eb833
|
|||
|
3ba599114d
|
|||
| d53f61fb5b | |||
|
5d259e20f2
|
|||
|
21b6903943
|
|||
|
14c7979310
|
|||
|
e376e02dc1
|
|||
|
4e7ee9dc5a
|
|||
|
ceaec14242
|
|||
|
9372caa157
|
|||
|
f73c274367
|
|||
|
c50a28443e
|
|||
|
c7150f1e23
|
|||
|
f16a817da2
|
|||
|
e858d252ab
|
|||
|
66e0d22ccd
|
|||
|
986ecfc7ad
|
|||
|
66890ccd44
|
|||
| ec15c1f2e5 | |||
|
8be9475ee5
|
|||
|
0cb2bec6e0
|
|||
| cf1906acaa | |||
|
7e93807298
|
|||
|
ee5b3331b4
|
|||
|
29c0acf3b2
|
|||
|
a844c4e90a
|
|||
|
5ed15a6847
|
|||
|
1ff1cae709
|
|||
|
|
c6ebe5a360 |
154
Cargo.lock
generated
154
Cargo.lock
generated
@@ -148,9 +148,9 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.7.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7"
|
||||
checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
@@ -191,9 +191,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.17"
|
||||
version = "1.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
@@ -320,9 +320,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.4.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cfac68e08048ae1883171632c2aef3ebc555621ae56fbccce1cbf22dd7f058"
|
||||
checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
|
||||
dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
@@ -388,9 +388,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
version = "0.3.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -410,9 +410,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -601,6 +601,12 @@ version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
@@ -696,9 +702,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hyper-util"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||
checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
@@ -706,6 +712,7 @@ dependencies = [
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"libc",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
@@ -715,9 +722,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.62"
|
||||
version = "0.1.63"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127"
|
||||
checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -878,9 +885,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -908,6 +915,29 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex"
|
||||
version = "3.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60c7310b93682b36b98fa7ea4de998d3463ccbebd94d935d6b48ba5b6ffa7126"
|
||||
dependencies = [
|
||||
"lazy-regex-proc_macros",
|
||||
"once_cell",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy-regex-proc_macros"
|
||||
version = "3.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ba01db5ef81e17eb10a5e0f2109d1b3a3e29bac3070fdbd7d156bf7dbd206a1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.5.0"
|
||||
@@ -922,9 +952,9 @@ checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.3"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litemap"
|
||||
@@ -963,6 +993,8 @@ version = "0.1.1"
|
||||
dependencies = [
|
||||
"async-nats",
|
||||
"futures",
|
||||
"heck",
|
||||
"lazy-regex",
|
||||
"rbx_asset",
|
||||
"rbx_binary",
|
||||
"rbx_dom_weak",
|
||||
@@ -999,9 +1031,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.5"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
|
||||
checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
|
||||
dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
@@ -1090,9 +1122,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.71"
|
||||
version = "0.10.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
|
||||
checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"cfg-if",
|
||||
@@ -1122,9 +1154,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.106"
|
||||
version = "0.9.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
|
||||
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -1297,10 +1329,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rbx_asset"
|
||||
version = "0.3.3"
|
||||
version = "0.4.4-pre2"
|
||||
source = "sparse+https://git.itzana.me/api/packages/strafesnet/cargo/"
|
||||
checksum = "91722b37549ded270f39556194ca03d03e08bd70674d239ec845765ed9e42b7d"
|
||||
checksum = "a32b98d3f303002faae783b5c1087e35c36a260b56470fd14a0606f35169ab35"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"chrono",
|
||||
"flate2",
|
||||
"reqwest",
|
||||
@@ -1513,9 +1546,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.3"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e56a18552996ac8d29ecc3b190b4fdbb2d91ca4ec396de7bbffaf43f3d637e96"
|
||||
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"errno",
|
||||
@@ -1526,9 +1559,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.25"
|
||||
version = "0.23.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c"
|
||||
checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"ring",
|
||||
@@ -1766,15 +1799,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.8"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
|
||||
checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
@@ -1798,7 +1831,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "submissions-api"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
dependencies = [
|
||||
"reqwest",
|
||||
"serde",
|
||||
@@ -1941,9 +1974,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.44.1"
|
||||
version = "1.44.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
|
||||
checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -2271,11 +2304,37 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-link",
|
||||
"windows-result",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2291,7 +2350,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
@@ -2313,6 +2372,15 @@ dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
@@ -2482,9 +2550,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.25"
|
||||
version = "0.8.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c5b940ebc25896e71dd073bad2dbaa2abfe97b0a391415e22ad1326d9c54e3c4"
|
||||
checksum = "a62ce76d9b56901b19a74f19431b0d8b3bc7ca4ad685a746dfd78ca8f4fc6bda"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Stage 1: Build
|
||||
FROM docker.io/golang:1.23 AS builder
|
||||
FROM registry.itzana.me/docker-proxy/golang:1.24 AS builder
|
||||
|
||||
# Set the working directory in the container
|
||||
WORKDIR /app
|
||||
@@ -14,7 +14,7 @@ COPY . .
|
||||
RUN CGO_ENABLED=0 GOOS=linux go build -o service ./cmd/maps-service/service.go
|
||||
|
||||
# Stage 2: Run
|
||||
FROM alpine
|
||||
FROM registry.itzana.me/docker-proxy/alpine:3.21
|
||||
|
||||
# Set up a non-root user for security
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
|
||||
@@ -26,10 +26,11 @@ Prerequisite: golang installed
|
||||
|
||||
Prerequisite: bun installed
|
||||
|
||||
The environment variable `API_HOST` will need to be set for the middleware.
|
||||
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/v1/"
|
||||
AUTH_HOST="http://localhost:8083/"
|
||||
```
|
||||
|
||||
1. `cd web`
|
||||
|
||||
@@ -50,6 +50,7 @@ services:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- API_HOST=http://submissions:8082/v1
|
||||
- AUTH_HOST=http://localhost:8080/
|
||||
|
||||
validation:
|
||||
image:
|
||||
|
||||
@@ -48,12 +48,81 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: ValidatedModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/validator-submitted:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
|
||||
operationId: actionMapfixSubmitted
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: DisplayName
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: Creator
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: GameID
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/validator-request-changes:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
|
||||
operationId: actionMapfixRequestChanges
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 0
|
||||
maxLength: 4096
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@@ -88,7 +157,7 @@ paths:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- name: StatusMessage
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
@@ -184,12 +253,81 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: ValidatedModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/validator-submitted:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted
|
||||
operationId: actionSubmissionSubmitted
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: DisplayName
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: Creator
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 128
|
||||
- name: GameID
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/validator-request-changes:
|
||||
post:
|
||||
summary: (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested
|
||||
operationId: actionSubmissionRequestChanges
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 0
|
||||
maxLength: 4096
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@@ -224,7 +362,7 @@ paths:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- name: StatusMessage
|
||||
- name: ErrorMessage
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
@@ -254,6 +392,7 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@@ -283,11 +422,13 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: Policy
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@@ -357,11 +498,13 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
- name: ResourceID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@@ -432,6 +575,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
OperationID:
|
||||
name: OperationID
|
||||
in: path
|
||||
@@ -440,6 +584,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
name: SubmissionID
|
||||
in: path
|
||||
@@ -448,6 +593,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
name: ScriptID
|
||||
in: path
|
||||
@@ -456,6 +602,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Page:
|
||||
name: Page
|
||||
in: query
|
||||
@@ -482,6 +629,7 @@ components:
|
||||
MapfixID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
required:
|
||||
- SubmissionID
|
||||
@@ -490,6 +638,7 @@ components:
|
||||
SubmissionID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
required:
|
||||
- ScriptID
|
||||
@@ -498,6 +647,7 @@ components:
|
||||
ScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
required:
|
||||
- ScriptPolicyID
|
||||
@@ -506,6 +656,7 @@ components:
|
||||
ScriptPolicyID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
MapfixCreate:
|
||||
required:
|
||||
- OperationID
|
||||
@@ -516,14 +667,17 @@ components:
|
||||
- AssetID
|
||||
- AssetVersion
|
||||
- TargetAssetID
|
||||
- Description
|
||||
type: object
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
AssetOwner:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -533,15 +687,22 @@ components:
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Description:
|
||||
type: string
|
||||
maxLength: 256
|
||||
SubmissionCreate:
|
||||
required:
|
||||
- OperationID
|
||||
@@ -551,14 +712,18 @@ components:
|
||||
- GameID
|
||||
- AssetID
|
||||
- AssetVersion
|
||||
- Status
|
||||
- Roles
|
||||
type: object
|
||||
properties:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
AssetOwner:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -568,12 +733,23 @@ components:
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Status:
|
||||
type: integer
|
||||
format: uint32
|
||||
minimum: 0
|
||||
maximum: 9
|
||||
Roles:
|
||||
type: integer
|
||||
format: uint32
|
||||
Script:
|
||||
required:
|
||||
- ID
|
||||
@@ -587,6 +763,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -600,9 +777,11 @@ components:
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptCreate:
|
||||
required:
|
||||
- Name
|
||||
@@ -620,9 +799,11 @@ components:
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptPolicy:
|
||||
required:
|
||||
- ID
|
||||
@@ -634,6 +815,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
FromScriptHash:
|
||||
type: string
|
||||
minLength: 16
|
||||
@@ -641,9 +823,11 @@ components:
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ScriptPolicyCreate:
|
||||
required:
|
||||
- FromScriptID
|
||||
@@ -654,12 +838,15 @@ components:
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
Error:
|
||||
description: Represents error object
|
||||
type: object
|
||||
@@ -667,6 +854,7 @@ components:
|
||||
code:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
message:
|
||||
type: string
|
||||
required:
|
||||
|
||||
407
openapi.yaml
407
openapi.yaml
@@ -105,11 +105,15 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@@ -172,20 +176,47 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
- name: Submitter
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: AssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: TargetAssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: StatusID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
maximum: 9
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Mapfix"
|
||||
$ref: "#/components/schemas/Mapfixes"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
@@ -238,6 +269,56 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/audit-events:
|
||||
get:
|
||||
summary: Retrieve a list of audit events
|
||||
operationId: listMapfixAuditEvents
|
||||
tags:
|
||||
- Mapfixes
|
||||
security: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/AuditEvent"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/comment:
|
||||
post:
|
||||
summary: Post a comment to the audit log
|
||||
operationId: createMapfixAuditComment
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 1024
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/model:
|
||||
post:
|
||||
summary: Update model following role restrictions
|
||||
@@ -252,12 +333,14 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: VersionID
|
||||
minimum: 0
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@@ -284,10 +367,27 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/submit:
|
||||
/mapfixes/{MapfixID}/status/trigger-submit:
|
||||
post:
|
||||
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
|
||||
operationId: actionMapfixSubmit
|
||||
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting
|
||||
operationId: actionMapfixTriggerSubmit
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/MapfixID'
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/mapfixes/{MapfixID}/status/reset-submitting:
|
||||
post:
|
||||
summary: Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction
|
||||
operationId: actionMapfixResetSubmitting
|
||||
tags:
|
||||
- Mapfixes
|
||||
parameters:
|
||||
@@ -483,20 +583,47 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
- name: Sort
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
maximum: 4
|
||||
- name: Submitter
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: AssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: UploadedAssetID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: StatusID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
maximum: 10
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Submission"
|
||||
$ref: "#/components/schemas/Submissions"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
@@ -527,6 +654,31 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions-admin:
|
||||
post:
|
||||
summary: Trigger the validator to create a new submission
|
||||
operationId: createSubmissionAdmin
|
||||
tags:
|
||||
- Submissions
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SubmissionTriggerCreate'
|
||||
responses:
|
||||
"201":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/OperationID"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}:
|
||||
get:
|
||||
summary: Retrieve map with ID
|
||||
@@ -549,6 +701,56 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/audit-events:
|
||||
get:
|
||||
summary: Retrieve a list of audit events
|
||||
operationId: listSubmissionAuditEvents
|
||||
tags:
|
||||
- Submissions
|
||||
security: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
- $ref: "#/components/parameters/Page"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/AuditEvent"
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/comment:
|
||||
post:
|
||||
summary: Post a comment to the audit log
|
||||
operationId: createSubmissionAuditComment
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
maxLength: 1024
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/model:
|
||||
post:
|
||||
summary: Update model following role restrictions
|
||||
@@ -563,12 +765,14 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
- name: VersionID
|
||||
minimum: 0
|
||||
- name: ModelVersion
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
@@ -595,10 +799,27 @@ paths:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/submit:
|
||||
/submissions/{SubmissionID}/status/trigger-submit:
|
||||
post:
|
||||
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted
|
||||
operationId: actionSubmissionSubmit
|
||||
summary: Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting
|
||||
operationId: actionSubmissionTriggerSubmit
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/SubmissionID'
|
||||
responses:
|
||||
"204":
|
||||
description: Successful response
|
||||
default:
|
||||
description: General Error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
/submissions/{SubmissionID}/status/reset-submitting:
|
||||
post:
|
||||
summary: Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction
|
||||
operationId: actionSubmissionResetSubmitting
|
||||
tags:
|
||||
- Submissions
|
||||
parameters:
|
||||
@@ -794,11 +1015,13 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
- name: Policy
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@@ -929,11 +1152,13 @@ paths:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
- name: ResourceID
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
responses:
|
||||
"200":
|
||||
description: Successful response
|
||||
@@ -1048,6 +1273,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
MapfixID:
|
||||
name: MapfixID
|
||||
in: path
|
||||
@@ -1056,6 +1282,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
OperationID:
|
||||
name: OperationID
|
||||
in: path
|
||||
@@ -1064,6 +1291,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
SubmissionID:
|
||||
name: SubmissionID
|
||||
in: path
|
||||
@@ -1072,6 +1300,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
name: ScriptID
|
||||
in: path
|
||||
@@ -1080,6 +1309,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
name: ScriptPolicyID
|
||||
in: path
|
||||
@@ -1088,6 +1318,7 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Page:
|
||||
name: Page
|
||||
in: query
|
||||
@@ -1103,9 +1334,47 @@ components:
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
schemas:
|
||||
AuditEvent:
|
||||
type: object
|
||||
required:
|
||||
- ID
|
||||
- Date
|
||||
- User
|
||||
- Username
|
||||
- ResourceType
|
||||
- ResourceID
|
||||
- EventType
|
||||
- EventData
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
Date:
|
||||
type: integer
|
||||
format: int64
|
||||
User:
|
||||
type: integer
|
||||
format: int64
|
||||
Username:
|
||||
type: string
|
||||
maxLength: 64
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
description: Is this a submission or is it a mapfix
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
EventType:
|
||||
type: integer
|
||||
format: int32
|
||||
EventData:
|
||||
type: object
|
||||
description: Arbitrary event data
|
||||
additionalProperties: true
|
||||
OperationID:
|
||||
required:
|
||||
- OperationID
|
||||
@@ -1114,6 +1383,7 @@ components:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ScriptID:
|
||||
required:
|
||||
- ScriptID
|
||||
@@ -1122,6 +1392,7 @@ components:
|
||||
ScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptPolicyID:
|
||||
required:
|
||||
- ScriptPolicyID
|
||||
@@ -1130,6 +1401,7 @@ components:
|
||||
ScriptPolicyID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Roles:
|
||||
required:
|
||||
- Roles
|
||||
@@ -1138,6 +1410,7 @@ components:
|
||||
Roles:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
User:
|
||||
required:
|
||||
- UserID
|
||||
@@ -1148,6 +1421,7 @@ components:
|
||||
UserID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Username:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1166,6 +1440,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1175,9 +1450,11 @@ components:
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
Date:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Mapfix:
|
||||
required:
|
||||
- ID
|
||||
@@ -1192,12 +1469,13 @@ components:
|
||||
- Completed
|
||||
- TargetAssetID
|
||||
- StatusID
|
||||
- StatusMessage
|
||||
- Description
|
||||
type: object
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1207,44 +1485,72 @@ components:
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
CreatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
UpdatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Submitter:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Completed:
|
||||
type: boolean
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
StatusID:
|
||||
type: integer
|
||||
format: int32
|
||||
StatusMessage:
|
||||
minimum: 0
|
||||
Description:
|
||||
type: string
|
||||
maxLength: 256
|
||||
Mapfixes:
|
||||
type: object
|
||||
required:
|
||||
- Total
|
||||
- Mapfixes
|
||||
properties:
|
||||
Total:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Mapfixes:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Mapfix"
|
||||
MapfixTriggerCreate:
|
||||
required:
|
||||
- AssetID
|
||||
- TargetAssetID
|
||||
- Description
|
||||
type: object
|
||||
properties:
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
TargetAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Description:
|
||||
type: string
|
||||
maxLength: 256
|
||||
Operation:
|
||||
required:
|
||||
- OperationID
|
||||
@@ -1258,15 +1564,19 @@ components:
|
||||
OperationID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
Date:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Owner:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Status:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
StatusMessage:
|
||||
type: string
|
||||
maxLength: 256
|
||||
@@ -1289,12 +1599,12 @@ components:
|
||||
- Completed
|
||||
# - UploadedAssetID
|
||||
- StatusID
|
||||
- StatusMessage
|
||||
type: object
|
||||
properties:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1304,46 +1614,81 @@ components:
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
CreatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
UpdatedAt:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Submitter:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
AssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ValidatedAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ValidatedAssetVersion:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Completed:
|
||||
type: boolean
|
||||
UploadedAssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
StatusID:
|
||||
type: integer
|
||||
format: int32
|
||||
StatusMessage:
|
||||
type: string
|
||||
maxLength: 256
|
||||
minimum: 0
|
||||
Submissions:
|
||||
required:
|
||||
- Total
|
||||
- Submissions
|
||||
type: object
|
||||
properties:
|
||||
Total:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Submissions:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Submission"
|
||||
SubmissionTriggerCreate:
|
||||
required:
|
||||
- AssetID
|
||||
- DisplayName
|
||||
- Creator
|
||||
- GameID
|
||||
type: object
|
||||
properties:
|
||||
AssetID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
DisplayName:
|
||||
type: string
|
||||
maxLength: 128
|
||||
Creator:
|
||||
type: string
|
||||
maxLength: 128
|
||||
GameID:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ReleaseInfo:
|
||||
required:
|
||||
- SubmissionID
|
||||
@@ -1353,6 +1698,7 @@ components:
|
||||
SubmissionID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Date:
|
||||
type: string
|
||||
format: date-time
|
||||
@@ -1369,6 +1715,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1382,9 +1729,11 @@ components:
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptCreate:
|
||||
required:
|
||||
- Name
|
||||
@@ -1402,9 +1751,11 @@ components:
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptUpdate:
|
||||
required:
|
||||
- ID
|
||||
@@ -1413,6 +1764,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Name:
|
||||
type: string
|
||||
maxLength: 128
|
||||
@@ -1422,9 +1774,11 @@ components:
|
||||
ResourceType:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ResourceID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ScriptPolicy:
|
||||
required:
|
||||
- ID
|
||||
@@ -1436,6 +1790,7 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
FromScriptHash:
|
||||
type: string
|
||||
minLength: 16
|
||||
@@ -1443,9 +1798,11 @@ components:
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ScriptPolicyCreate:
|
||||
required:
|
||||
- FromScriptID
|
||||
@@ -1456,12 +1813,15 @@ components:
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
ScriptPolicyUpdate:
|
||||
required:
|
||||
- ID
|
||||
@@ -1470,15 +1830,19 @@ components:
|
||||
ID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
FromScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
ToScriptID:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
Policy:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 0
|
||||
Error:
|
||||
description: Represents error object
|
||||
type: object
|
||||
@@ -1486,6 +1850,7 @@ components:
|
||||
code:
|
||||
type: integer
|
||||
format: int64
|
||||
minimum: 0
|
||||
message:
|
||||
type: string
|
||||
required:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -13,6 +13,277 @@ import (
|
||||
"github.com/ogen-go/ogen/validate"
|
||||
)
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *AuditEvent) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
s.encodeFields(e)
|
||||
e.ObjEnd()
|
||||
}
|
||||
|
||||
// encodeFields encodes fields.
|
||||
func (s *AuditEvent) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("ID")
|
||||
e.Int64(s.ID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Date")
|
||||
e.Int64(s.Date)
|
||||
}
|
||||
{
|
||||
e.FieldStart("User")
|
||||
e.Int64(s.User)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Username")
|
||||
e.Str(s.Username)
|
||||
}
|
||||
{
|
||||
e.FieldStart("ResourceType")
|
||||
e.Int32(s.ResourceType)
|
||||
}
|
||||
{
|
||||
e.FieldStart("ResourceID")
|
||||
e.Int64(s.ResourceID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("EventType")
|
||||
e.Int32(s.EventType)
|
||||
}
|
||||
{
|
||||
e.FieldStart("EventData")
|
||||
s.EventData.Encode(e)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfAuditEvent = [8]string{
|
||||
0: "ID",
|
||||
1: "Date",
|
||||
2: "User",
|
||||
3: "Username",
|
||||
4: "ResourceType",
|
||||
5: "ResourceID",
|
||||
6: "EventType",
|
||||
7: "EventData",
|
||||
}
|
||||
|
||||
// Decode decodes AuditEvent from json.
|
||||
func (s *AuditEvent) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode AuditEvent to nil")
|
||||
}
|
||||
var requiredBitSet [1]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "ID":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ID = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"ID\"")
|
||||
}
|
||||
case "Date":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.Date = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Date\"")
|
||||
}
|
||||
case "User":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.User = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"User\"")
|
||||
}
|
||||
case "Username":
|
||||
requiredBitSet[0] |= 1 << 3
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Username = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Username\"")
|
||||
}
|
||||
case "ResourceType":
|
||||
requiredBitSet[0] |= 1 << 4
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.ResourceType = int32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"ResourceType\"")
|
||||
}
|
||||
case "ResourceID":
|
||||
requiredBitSet[0] |= 1 << 5
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.ResourceID = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"ResourceID\"")
|
||||
}
|
||||
case "EventType":
|
||||
requiredBitSet[0] |= 1 << 6
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.EventType = int32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"EventType\"")
|
||||
}
|
||||
case "EventData":
|
||||
requiredBitSet[0] |= 1 << 7
|
||||
if err := func() error {
|
||||
if err := s.EventData.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"EventData\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode AuditEvent")
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b11111111,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
//
|
||||
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
|
||||
// Bits of fields which would be set are actually bits of missed fields.
|
||||
missed := bits.OnesCount8(result)
|
||||
for bitN := 0; bitN < missed; bitN++ {
|
||||
bitIdx := bits.TrailingZeros8(result)
|
||||
fieldIdx := i*8 + bitIdx
|
||||
var name string
|
||||
if fieldIdx < len(jsonFieldsNameOfAuditEvent) {
|
||||
name = jsonFieldsNameOfAuditEvent[fieldIdx]
|
||||
} else {
|
||||
name = strconv.Itoa(fieldIdx)
|
||||
}
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: name,
|
||||
Error: validate.ErrFieldRequired,
|
||||
})
|
||||
// Reset bit.
|
||||
result &^= 1 << bitIdx
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s *AuditEvent) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *AuditEvent) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s AuditEventEventData) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
s.encodeFields(e)
|
||||
e.ObjEnd()
|
||||
}
|
||||
|
||||
// encodeFields implements json.Marshaler.
|
||||
func (s AuditEventEventData) encodeFields(e *jx.Encoder) {
|
||||
for k, elem := range s {
|
||||
e.FieldStart(k)
|
||||
|
||||
if len(elem) != 0 {
|
||||
e.Raw(elem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode decodes AuditEventEventData from json.
|
||||
func (s *AuditEventEventData) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode AuditEventEventData to nil")
|
||||
}
|
||||
m := s.init()
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
var elem jx.Raw
|
||||
if err := func() error {
|
||||
v, err := d.RawAppend(nil)
|
||||
elem = jx.Raw(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrapf(err, "decode field %q", k)
|
||||
}
|
||||
m[string(k)] = elem
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode AuditEventEventData")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s AuditEventEventData) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *AuditEventEventData) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *Error) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
@@ -348,8 +619,8 @@ func (s *Mapfix) encodeFields(e *jx.Encoder) {
|
||||
e.Int32(s.StatusID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("StatusMessage")
|
||||
e.Str(s.StatusMessage)
|
||||
e.FieldStart("Description")
|
||||
e.Str(s.Description)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,7 +637,7 @@ var jsonFieldsNameOfMapfix = [13]string{
|
||||
9: "Completed",
|
||||
10: "TargetAssetID",
|
||||
11: "StatusID",
|
||||
12: "StatusMessage",
|
||||
12: "Description",
|
||||
}
|
||||
|
||||
// Decode decodes Mapfix from json.
|
||||
@@ -522,17 +793,17 @@ func (s *Mapfix) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"StatusID\"")
|
||||
}
|
||||
case "StatusMessage":
|
||||
case "Description":
|
||||
requiredBitSet[1] |= 1 << 4
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.StatusMessage = string(v)
|
||||
s.Description = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"StatusMessage\"")
|
||||
return errors.Wrap(err, "decode field \"Description\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
@@ -608,11 +879,16 @@ func (s *MapfixTriggerCreate) encodeFields(e *jx.Encoder) {
|
||||
e.FieldStart("TargetAssetID")
|
||||
e.Int64(s.TargetAssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Description")
|
||||
e.Str(s.Description)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfMapfixTriggerCreate = [2]string{
|
||||
var jsonFieldsNameOfMapfixTriggerCreate = [3]string{
|
||||
0: "AssetID",
|
||||
1: "TargetAssetID",
|
||||
2: "Description",
|
||||
}
|
||||
|
||||
// Decode decodes MapfixTriggerCreate from json.
|
||||
@@ -648,6 +924,18 @@ func (s *MapfixTriggerCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"TargetAssetID\"")
|
||||
}
|
||||
case "Description":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Description = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Description\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@@ -658,7 +946,7 @@ func (s *MapfixTriggerCreate) Decode(d *jx.Decoder) error {
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b00000011,
|
||||
0b00000111,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@@ -704,6 +992,129 @@ func (s *MapfixTriggerCreate) UnmarshalJSON(data []byte) error {
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *Mapfixes) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
s.encodeFields(e)
|
||||
e.ObjEnd()
|
||||
}
|
||||
|
||||
// encodeFields encodes fields.
|
||||
func (s *Mapfixes) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("Total")
|
||||
e.Int64(s.Total)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Mapfixes")
|
||||
e.ArrStart()
|
||||
for _, elem := range s.Mapfixes {
|
||||
elem.Encode(e)
|
||||
}
|
||||
e.ArrEnd()
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfMapfixes = [2]string{
|
||||
0: "Total",
|
||||
1: "Mapfixes",
|
||||
}
|
||||
|
||||
// Decode decodes Mapfixes from json.
|
||||
func (s *Mapfixes) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode Mapfixes to nil")
|
||||
}
|
||||
var requiredBitSet [1]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "Total":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.Total = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Total\"")
|
||||
}
|
||||
case "Mapfixes":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
s.Mapfixes = make([]Mapfix, 0)
|
||||
if err := d.Arr(func(d *jx.Decoder) error {
|
||||
var elem Mapfix
|
||||
if err := elem.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Mapfixes = append(s.Mapfixes, elem)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Mapfixes\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode Mapfixes")
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b00000011,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
//
|
||||
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
|
||||
// Bits of fields which would be set are actually bits of missed fields.
|
||||
missed := bits.OnesCount8(result)
|
||||
for bitN := 0; bitN < missed; bitN++ {
|
||||
bitIdx := bits.TrailingZeros8(result)
|
||||
fieldIdx := i*8 + bitIdx
|
||||
var name string
|
||||
if fieldIdx < len(jsonFieldsNameOfMapfixes) {
|
||||
name = jsonFieldsNameOfMapfixes[fieldIdx]
|
||||
} else {
|
||||
name = strconv.Itoa(fieldIdx)
|
||||
}
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: name,
|
||||
Error: validate.ErrFieldRequired,
|
||||
})
|
||||
// Reset bit.
|
||||
result &^= 1 << bitIdx
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s *Mapfixes) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *Mapfixes) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *Operation) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
@@ -2474,13 +2885,9 @@ func (s *Submission) encodeFields(e *jx.Encoder) {
|
||||
e.FieldStart("StatusID")
|
||||
e.Int32(s.StatusID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("StatusMessage")
|
||||
e.Str(s.StatusMessage)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfSubmission = [15]string{
|
||||
var jsonFieldsNameOfSubmission = [14]string{
|
||||
0: "ID",
|
||||
1: "DisplayName",
|
||||
2: "Creator",
|
||||
@@ -2495,7 +2902,6 @@ var jsonFieldsNameOfSubmission = [15]string{
|
||||
11: "Completed",
|
||||
12: "UploadedAssetID",
|
||||
13: "StatusID",
|
||||
14: "StatusMessage",
|
||||
}
|
||||
|
||||
// Decode decodes Submission from json.
|
||||
@@ -2669,18 +3075,6 @@ func (s *Submission) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"StatusID\"")
|
||||
}
|
||||
case "StatusMessage":
|
||||
requiredBitSet[1] |= 1 << 6
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.StatusMessage = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"StatusMessage\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@@ -2692,7 +3086,7 @@ func (s *Submission) Decode(d *jx.Decoder) error {
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [2]uint8{
|
||||
0b11111111,
|
||||
0b01101001,
|
||||
0b00101001,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@@ -2751,10 +3145,25 @@ func (s *SubmissionTriggerCreate) encodeFields(e *jx.Encoder) {
|
||||
e.FieldStart("AssetID")
|
||||
e.Int64(s.AssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("DisplayName")
|
||||
e.Str(s.DisplayName)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Creator")
|
||||
e.Str(s.Creator)
|
||||
}
|
||||
{
|
||||
e.FieldStart("GameID")
|
||||
e.Int32(s.GameID)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfSubmissionTriggerCreate = [1]string{
|
||||
var jsonFieldsNameOfSubmissionTriggerCreate = [4]string{
|
||||
0: "AssetID",
|
||||
1: "DisplayName",
|
||||
2: "Creator",
|
||||
3: "GameID",
|
||||
}
|
||||
|
||||
// Decode decodes SubmissionTriggerCreate from json.
|
||||
@@ -2778,6 +3187,42 @@ func (s *SubmissionTriggerCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"AssetID\"")
|
||||
}
|
||||
case "DisplayName":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.DisplayName = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"DisplayName\"")
|
||||
}
|
||||
case "Creator":
|
||||
requiredBitSet[0] |= 1 << 2
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Creator = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Creator\"")
|
||||
}
|
||||
case "GameID":
|
||||
requiredBitSet[0] |= 1 << 3
|
||||
if err := func() error {
|
||||
v, err := d.Int32()
|
||||
s.GameID = int32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"GameID\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@@ -2788,7 +3233,7 @@ func (s *SubmissionTriggerCreate) Decode(d *jx.Decoder) error {
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b00000001,
|
||||
0b00001111,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@@ -2834,6 +3279,129 @@ func (s *SubmissionTriggerCreate) UnmarshalJSON(data []byte) error {
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *Submissions) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
s.encodeFields(e)
|
||||
e.ObjEnd()
|
||||
}
|
||||
|
||||
// encodeFields encodes fields.
|
||||
func (s *Submissions) encodeFields(e *jx.Encoder) {
|
||||
{
|
||||
e.FieldStart("Total")
|
||||
e.Int64(s.Total)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Submissions")
|
||||
e.ArrStart()
|
||||
for _, elem := range s.Submissions {
|
||||
elem.Encode(e)
|
||||
}
|
||||
e.ArrEnd()
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfSubmissions = [2]string{
|
||||
0: "Total",
|
||||
1: "Submissions",
|
||||
}
|
||||
|
||||
// Decode decodes Submissions from json.
|
||||
func (s *Submissions) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode Submissions to nil")
|
||||
}
|
||||
var requiredBitSet [1]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
case "Total":
|
||||
requiredBitSet[0] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Int64()
|
||||
s.Total = int64(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Total\"")
|
||||
}
|
||||
case "Submissions":
|
||||
requiredBitSet[0] |= 1 << 1
|
||||
if err := func() error {
|
||||
s.Submissions = make([]Submission, 0)
|
||||
if err := d.Arr(func(d *jx.Decoder) error {
|
||||
var elem Submission
|
||||
if err := elem.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
s.Submissions = append(s.Submissions, elem)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Submissions\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode Submissions")
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b00000011,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
//
|
||||
// If XOR result is not zero, result is not equal to expected, so some fields are missed.
|
||||
// Bits of fields which would be set are actually bits of missed fields.
|
||||
missed := bits.OnesCount8(result)
|
||||
for bitN := 0; bitN < missed; bitN++ {
|
||||
bitIdx := bits.TrailingZeros8(result)
|
||||
fieldIdx := i*8 + bitIdx
|
||||
var name string
|
||||
if fieldIdx < len(jsonFieldsNameOfSubmissions) {
|
||||
name = jsonFieldsNameOfSubmissions[fieldIdx]
|
||||
} else {
|
||||
name = strconv.Itoa(fieldIdx)
|
||||
}
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: name,
|
||||
Error: validate.ErrFieldRequired,
|
||||
})
|
||||
// Reset bit.
|
||||
result &^= 1 << bitIdx
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements stdjson.Marshaler.
|
||||
func (s *Submissions) MarshalJSON() ([]byte, error) {
|
||||
e := jx.Encoder{}
|
||||
s.Encode(&e)
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements stdjson.Unmarshaler.
|
||||
func (s *Submissions) UnmarshalJSON(data []byte) error {
|
||||
d := jx.DecodeBytes(data)
|
||||
return s.Decode(d)
|
||||
}
|
||||
|
||||
// Encode implements json.Marshaler.
|
||||
func (s *User) Encode(e *jx.Encoder) {
|
||||
e.ObjStart()
|
||||
|
||||
@@ -9,25 +9,30 @@ const (
|
||||
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
|
||||
ActionMapfixRejectOperation OperationName = "ActionMapfixReject"
|
||||
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
|
||||
ActionMapfixResetSubmittingOperation OperationName = "ActionMapfixResetSubmitting"
|
||||
ActionMapfixRetryValidateOperation OperationName = "ActionMapfixRetryValidate"
|
||||
ActionMapfixRevokeOperation OperationName = "ActionMapfixRevoke"
|
||||
ActionMapfixSubmitOperation OperationName = "ActionMapfixSubmit"
|
||||
ActionMapfixTriggerSubmitOperation OperationName = "ActionMapfixTriggerSubmit"
|
||||
ActionMapfixTriggerUploadOperation OperationName = "ActionMapfixTriggerUpload"
|
||||
ActionMapfixTriggerValidateOperation OperationName = "ActionMapfixTriggerValidate"
|
||||
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
|
||||
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
|
||||
ActionSubmissionRejectOperation OperationName = "ActionSubmissionReject"
|
||||
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
|
||||
ActionSubmissionResetSubmittingOperation OperationName = "ActionSubmissionResetSubmitting"
|
||||
ActionSubmissionRetryValidateOperation OperationName = "ActionSubmissionRetryValidate"
|
||||
ActionSubmissionRevokeOperation OperationName = "ActionSubmissionRevoke"
|
||||
ActionSubmissionSubmitOperation OperationName = "ActionSubmissionSubmit"
|
||||
ActionSubmissionTriggerSubmitOperation OperationName = "ActionSubmissionTriggerSubmit"
|
||||
ActionSubmissionTriggerUploadOperation OperationName = "ActionSubmissionTriggerUpload"
|
||||
ActionSubmissionTriggerValidateOperation OperationName = "ActionSubmissionTriggerValidate"
|
||||
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
|
||||
CreateMapfixOperation OperationName = "CreateMapfix"
|
||||
CreateMapfixAuditCommentOperation OperationName = "CreateMapfixAuditComment"
|
||||
CreateScriptOperation OperationName = "CreateScript"
|
||||
CreateScriptPolicyOperation OperationName = "CreateScriptPolicy"
|
||||
CreateSubmissionOperation OperationName = "CreateSubmission"
|
||||
CreateSubmissionAdminOperation OperationName = "CreateSubmissionAdmin"
|
||||
CreateSubmissionAuditCommentOperation OperationName = "CreateSubmissionAuditComment"
|
||||
DeleteScriptOperation OperationName = "DeleteScript"
|
||||
DeleteScriptPolicyOperation OperationName = "DeleteScriptPolicy"
|
||||
GetMapOperation OperationName = "GetMap"
|
||||
@@ -36,10 +41,12 @@ const (
|
||||
GetScriptOperation OperationName = "GetScript"
|
||||
GetScriptPolicyOperation OperationName = "GetScriptPolicy"
|
||||
GetSubmissionOperation OperationName = "GetSubmission"
|
||||
ListMapfixAuditEventsOperation OperationName = "ListMapfixAuditEvents"
|
||||
ListMapfixesOperation OperationName = "ListMapfixes"
|
||||
ListMapsOperation OperationName = "ListMaps"
|
||||
ListScriptPolicyOperation OperationName = "ListScriptPolicy"
|
||||
ListScriptsOperation OperationName = "ListScripts"
|
||||
ListSubmissionAuditEventsOperation OperationName = "ListSubmissionAuditEvents"
|
||||
ListSubmissionsOperation OperationName = "ListSubmissions"
|
||||
ReleaseSubmissionsOperation OperationName = "ReleaseSubmissions"
|
||||
SessionRolesOperation OperationName = "SessionRoles"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
@@ -72,12 +73,54 @@ func (s *Server) decodeCreateMapfixRequest(r *http.Request) (
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeCreateMapfixAuditCommentRequest(r *http.Request) (
|
||||
req CreateMapfixAuditCommentReq,
|
||||
close func() error,
|
||||
rerr error,
|
||||
) {
|
||||
var closers []func() error
|
||||
close = func() error {
|
||||
var merr error
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return req, close, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "text/plain":
|
||||
reader := r.Body
|
||||
request := CreateMapfixAuditCommentReq{Data: reader}
|
||||
return request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeCreateScriptRequest(r *http.Request) (
|
||||
req *ScriptCreate,
|
||||
close func() error,
|
||||
@@ -206,6 +249,14 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
@@ -269,12 +320,125 @@ func (s *Server) decodeCreateSubmissionRequest(r *http.Request) (
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeCreateSubmissionAdminRequest(r *http.Request) (
|
||||
req *SubmissionTriggerCreate,
|
||||
close func() error,
|
||||
rerr error,
|
||||
) {
|
||||
var closers []func() error
|
||||
close = func() error {
|
||||
var merr error
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return req, close, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
if r.ContentLength == 0 {
|
||||
return req, close, validate.ErrBodyRequired
|
||||
}
|
||||
buf, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return req, close, err
|
||||
}
|
||||
|
||||
if len(buf) == 0 {
|
||||
return req, close, validate.ErrBodyRequired
|
||||
}
|
||||
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var request SubmissionTriggerCreate
|
||||
if err := func() error {
|
||||
if err := request.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != io.EOF {
|
||||
return errors.New("unexpected trailing data")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
err = &ogenerrors.DecodeBodyError{
|
||||
ContentType: ct,
|
||||
Body: buf,
|
||||
Err: err,
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeCreateSubmissionAuditCommentRequest(r *http.Request) (
|
||||
req CreateSubmissionAuditCommentReq,
|
||||
close func() error,
|
||||
rerr error,
|
||||
) {
|
||||
var closers []func() error
|
||||
close = func() error {
|
||||
var merr error
|
||||
// Close in reverse order, to match defer behavior.
|
||||
for i := len(closers) - 1; i >= 0; i-- {
|
||||
c := closers[i]
|
||||
merr = multierr.Append(merr, c())
|
||||
}
|
||||
return merr
|
||||
}
|
||||
defer func() {
|
||||
if rerr != nil {
|
||||
rerr = multierr.Append(rerr, close())
|
||||
}
|
||||
}()
|
||||
ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return req, close, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "text/plain":
|
||||
reader := r.Body
|
||||
request := CreateSubmissionAuditCommentReq{Data: reader}
|
||||
return request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
|
||||
req []ReleaseInfo,
|
||||
close func() error,
|
||||
@@ -352,6 +516,23 @@ func (s *Server) decodeReleaseSubmissionsRequest(r *http.Request) (
|
||||
}).ValidateLength(len(request)); err != nil {
|
||||
return errors.Wrap(err, "array")
|
||||
}
|
||||
var failures []validate.FieldError
|
||||
for i, elem := range request {
|
||||
if err := func() error {
|
||||
if err := elem.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: fmt.Sprintf("[%d]", i),
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
@@ -490,6 +671,14 @@ func (s *Server) decodeUpdateScriptPolicyRequest(r *http.Request) (
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
|
||||
@@ -25,6 +25,16 @@ func encodeCreateMapfixRequest(
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateMapfixAuditCommentRequest(
|
||||
req CreateMapfixAuditCommentReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "text/plain"
|
||||
body := req
|
||||
ht.SetBody(r, body, contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateScriptRequest(
|
||||
req *ScriptCreate,
|
||||
r *http.Request,
|
||||
@@ -67,6 +77,30 @@ func encodeCreateSubmissionRequest(
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAdminRequest(
|
||||
req *SubmissionTriggerCreate,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "application/json"
|
||||
e := new(jx.Encoder)
|
||||
{
|
||||
req.Encode(e)
|
||||
}
|
||||
encoded := e.Bytes()
|
||||
ht.SetBody(r, bytes.NewReader(encoded), contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAuditCommentRequest(
|
||||
req CreateSubmissionAuditCommentReq,
|
||||
r *http.Request,
|
||||
) error {
|
||||
const contentType = "text/plain"
|
||||
body := req
|
||||
ht.SetBody(r, body, contentType)
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeReleaseSubmissionsRequest(
|
||||
req []ReleaseInfo,
|
||||
r *http.Request,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,6 +34,13 @@ func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChang
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixResetSubmittingResponse(response *ActionMapfixResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixRetryValidateResponse(response *ActionMapfixRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@@ -48,7 +55,7 @@ func encodeActionMapfixRevokeResponse(response *ActionMapfixRevokeNoContent, w h
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixSubmitResponse(response *ActionMapfixSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
func encodeActionMapfixTriggerSubmitResponse(response *ActionMapfixTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
@@ -97,6 +104,13 @@ func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequ
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionResetSubmittingResponse(response *ActionSubmissionResetSubmittingNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionRetryValidateResponse(response *ActionSubmissionRetryValidateNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@@ -111,7 +125,7 @@ func encodeActionSubmissionRevokeResponse(response *ActionSubmissionRevokeNoCont
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionSubmitResponse(response *ActionSubmissionSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
func encodeActionSubmissionTriggerSubmitResponse(response *ActionSubmissionTriggerSubmitNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
@@ -153,6 +167,13 @@ func encodeCreateMapfixResponse(response *OperationID, w http.ResponseWriter, sp
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateMapfixAuditCommentResponse(response *CreateMapfixAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateScriptResponse(response *ScriptID, w http.ResponseWriter, span trace.Span) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(201)
|
||||
@@ -195,6 +216,27 @@ func encodeCreateSubmissionResponse(response *OperationID, w http.ResponseWriter
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAdminResponse(response *OperationID, w http.ResponseWriter, span trace.Span) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(201)
|
||||
span.SetStatus(codes.Ok, http.StatusText(201))
|
||||
|
||||
e := new(jx.Encoder)
|
||||
response.Encode(e)
|
||||
if _, err := e.WriteTo(w); err != nil {
|
||||
return errors.Wrap(err, "write")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeCreateSubmissionAuditCommentResponse(response *CreateSubmissionAuditCommentNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeDeleteScriptResponse(response *DeleteScriptNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@@ -293,7 +335,7 @@ func encodeGetSubmissionResponse(response *Submission, w http.ResponseWriter, sp
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeListMapfixesResponse(response []Mapfix, w http.ResponseWriter, span trace.Span) error {
|
||||
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))
|
||||
@@ -311,6 +353,20 @@ func encodeListMapfixesResponse(response []Mapfix, w http.ResponseWriter, span t
|
||||
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)
|
||||
@@ -365,7 +421,7 @@ func encodeListScriptsResponse(response []Script, w http.ResponseWriter, span tr
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter, span trace.Span) error {
|
||||
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))
|
||||
@@ -383,6 +439,20 @@ func encodeListSubmissionsResponse(response []Submission, w http.ResponseWriter,
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeListSubmissionsResponse(response *Submissions, w http.ResponseWriter, span trace.Span) error {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(200)
|
||||
span.SetStatus(codes.Ok, http.StatusText(200))
|
||||
|
||||
e := new(jx.Encoder)
|
||||
response.Encode(e)
|
||||
if _, err := e.WriteTo(w); err != nil {
|
||||
return errors.Wrap(err, "write")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeReleaseSubmissionsResponse(response *ReleaseSubmissionsCreated, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(201)
|
||||
span.SetStatus(codes.Ok, http.StatusText(201))
|
||||
|
||||
@@ -136,9 +136,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'c': // Prefix: "completed"
|
||||
case 'a': // Prefix: "audit-events"
|
||||
|
||||
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
|
||||
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
@@ -147,17 +147,75 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleSetMapfixCompletedRequest([1]string{
|
||||
case "GET":
|
||||
s.handleListMapfixAuditEventsRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
s.notAllowed(w, r, "GET")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'c': // Prefix: "com"
|
||||
|
||||
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'm': // Prefix: "ment"
|
||||
|
||||
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleCreateMapfixAuditCommentRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'p': // Prefix: "pleted"
|
||||
|
||||
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleSetMapfixCompletedRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case 'm': // Prefix: "model"
|
||||
|
||||
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
|
||||
@@ -260,6 +318,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submitting"
|
||||
|
||||
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixResetSubmittingRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploading"
|
||||
|
||||
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
|
||||
@@ -352,28 +432,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 't': // Prefix: "trigger-"
|
||||
|
||||
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
|
||||
@@ -386,6 +444,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixTriggerSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "upload"
|
||||
|
||||
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
|
||||
@@ -790,6 +870,26 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
switch elem[0] {
|
||||
case '-': // Prefix: "-admin"
|
||||
|
||||
if l := len("-admin"); len(elem) >= l && elem[0:l] == "-admin" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleCreateSubmissionAdminRequest([0]string{}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case '/': // Prefix: "/"
|
||||
|
||||
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
|
||||
@@ -832,9 +932,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'c': // Prefix: "completed"
|
||||
case 'a': // Prefix: "audit-events"
|
||||
|
||||
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
|
||||
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
@@ -843,17 +943,75 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleSetSubmissionCompletedRequest([1]string{
|
||||
case "GET":
|
||||
s.handleListSubmissionAuditEventsRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
s.notAllowed(w, r, "GET")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'c': // Prefix: "com"
|
||||
|
||||
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'm': // Prefix: "ment"
|
||||
|
||||
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleCreateSubmissionAuditCommentRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'p': // Prefix: "pleted"
|
||||
|
||||
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleSetSubmissionCompletedRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case 'm': // Prefix: "model"
|
||||
|
||||
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
|
||||
@@ -956,6 +1114,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submitting"
|
||||
|
||||
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionResetSubmittingRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploading"
|
||||
|
||||
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
|
||||
@@ -1048,28 +1228,6 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 't': // Prefix: "trigger-"
|
||||
|
||||
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
|
||||
@@ -1082,6 +1240,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionTriggerSubmitRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "upload"
|
||||
|
||||
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
|
||||
@@ -1319,9 +1499,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'c': // Prefix: "completed"
|
||||
case 'a': // Prefix: "audit-events"
|
||||
|
||||
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
|
||||
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
@@ -1330,11 +1510,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = SetMapfixCompletedOperation
|
||||
r.summary = "Called by maptest when a player completes the map"
|
||||
r.operationID = "setMapfixCompleted"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/completed"
|
||||
case "GET":
|
||||
r.name = ListMapfixAuditEventsOperation
|
||||
r.summary = "Retrieve a list of audit events"
|
||||
r.operationID = "listMapfixAuditEvents"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/audit-events"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
@@ -1343,6 +1523,68 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'c': // Prefix: "com"
|
||||
|
||||
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'm': // Prefix: "ment"
|
||||
|
||||
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = CreateMapfixAuditCommentOperation
|
||||
r.summary = "Post a comment to the audit log"
|
||||
r.operationID = "createMapfixAuditComment"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/comment"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'p': // Prefix: "pleted"
|
||||
|
||||
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = SetMapfixCompletedOperation
|
||||
r.summary = "Called by maptest when a player completes the map"
|
||||
r.operationID = "setMapfixCompleted"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/completed"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case 'm': // Prefix: "model"
|
||||
|
||||
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
|
||||
@@ -1451,6 +1693,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submitting"
|
||||
|
||||
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixResetSubmittingOperation
|
||||
r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction"
|
||||
r.operationID = "actionMapfixResetSubmitting"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/reset-submitting"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploading"
|
||||
|
||||
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
|
||||
@@ -1551,30 +1817,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixSubmitOperation
|
||||
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
|
||||
r.operationID = "actionMapfixSubmit"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 't': // Prefix: "trigger-"
|
||||
|
||||
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
|
||||
@@ -1587,6 +1829,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixTriggerSubmitOperation
|
||||
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting"
|
||||
r.operationID = "actionMapfixTriggerSubmit"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/trigger-submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "upload"
|
||||
|
||||
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
|
||||
@@ -2069,6 +2335,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
switch elem[0] {
|
||||
case '-': // Prefix: "-admin"
|
||||
|
||||
if l := len("-admin"); len(elem) >= l && elem[0:l] == "-admin" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = CreateSubmissionAdminOperation
|
||||
r.summary = "Trigger the validator to create a new submission"
|
||||
r.operationID = "createSubmissionAdmin"
|
||||
r.pathPattern = "/submissions-admin"
|
||||
r.args = args
|
||||
r.count = 0
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case '/': // Prefix: "/"
|
||||
|
||||
if l := len("/"); len(elem) >= l && elem[0:l] == "/" {
|
||||
@@ -2113,9 +2403,9 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'c': // Prefix: "completed"
|
||||
case 'a': // Prefix: "audit-events"
|
||||
|
||||
if l := len("completed"); len(elem) >= l && elem[0:l] == "completed" {
|
||||
if l := len("audit-events"); len(elem) >= l && elem[0:l] == "audit-events" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
@@ -2124,11 +2414,11 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = SetSubmissionCompletedOperation
|
||||
r.summary = "Called by maptest when a player completes the map"
|
||||
r.operationID = "setSubmissionCompleted"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/completed"
|
||||
case "GET":
|
||||
r.name = ListSubmissionAuditEventsOperation
|
||||
r.summary = "Retrieve a list of audit events"
|
||||
r.operationID = "listSubmissionAuditEvents"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/audit-events"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
@@ -2137,6 +2427,68 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'c': // Prefix: "com"
|
||||
|
||||
if l := len("com"); len(elem) >= l && elem[0:l] == "com" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 'm': // Prefix: "ment"
|
||||
|
||||
if l := len("ment"); len(elem) >= l && elem[0:l] == "ment" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = CreateSubmissionAuditCommentOperation
|
||||
r.summary = "Post a comment to the audit log"
|
||||
r.operationID = "createSubmissionAuditComment"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/comment"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'p': // Prefix: "pleted"
|
||||
|
||||
if l := len("pleted"); len(elem) >= l && elem[0:l] == "pleted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = SetSubmissionCompletedOperation
|
||||
r.summary = "Called by maptest when a player completes the map"
|
||||
r.operationID = "setSubmissionCompleted"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/completed"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case 'm': // Prefix: "model"
|
||||
|
||||
if l := len("model"); len(elem) >= l && elem[0:l] == "model" {
|
||||
@@ -2245,6 +2597,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submitting"
|
||||
|
||||
if l := len("submitting"); len(elem) >= l && elem[0:l] == "submitting" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionResetSubmittingOperation
|
||||
r.summary = "Role Submitter manually resets submitting softlock and changes status from Submitting -> UnderConstruction"
|
||||
r.operationID = "actionSubmissionResetSubmitting"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/reset-submitting"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploading"
|
||||
|
||||
if l := len("uploading"); len(elem) >= l && elem[0:l] == "uploading" {
|
||||
@@ -2345,30 +2721,6 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionSubmitOperation
|
||||
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted"
|
||||
r.operationID = "actionSubmissionSubmit"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 't': // Prefix: "trigger-"
|
||||
|
||||
if l := len("trigger-"); len(elem) >= l && elem[0:l] == "trigger-" {
|
||||
@@ -2381,6 +2733,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
break
|
||||
}
|
||||
switch elem[0] {
|
||||
case 's': // Prefix: "submit"
|
||||
|
||||
if l := len("submit"); len(elem) >= l && elem[0:l] == "submit" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionTriggerSubmitOperation
|
||||
r.summary = "Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting"
|
||||
r.operationID = "actionSubmissionTriggerSubmit"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/trigger-submit"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "upload"
|
||||
|
||||
if l := len("upload"); len(elem) >= l && elem[0:l] == "upload" {
|
||||
|
||||
@@ -4,7 +4,10 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/go-faster/jx"
|
||||
)
|
||||
|
||||
func (s *ErrorStatusCode) Error() string {
|
||||
@@ -20,14 +23,17 @@ type ActionMapfixRejectNoContent struct{}
|
||||
// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
|
||||
type ActionMapfixRequestChangesNoContent struct{}
|
||||
|
||||
// ActionMapfixResetSubmittingNoContent is response for ActionMapfixResetSubmitting operation.
|
||||
type ActionMapfixResetSubmittingNoContent struct{}
|
||||
|
||||
// ActionMapfixRetryValidateNoContent is response for ActionMapfixRetryValidate operation.
|
||||
type ActionMapfixRetryValidateNoContent struct{}
|
||||
|
||||
// ActionMapfixRevokeNoContent is response for ActionMapfixRevoke operation.
|
||||
type ActionMapfixRevokeNoContent struct{}
|
||||
|
||||
// ActionMapfixSubmitNoContent is response for ActionMapfixSubmit operation.
|
||||
type ActionMapfixSubmitNoContent struct{}
|
||||
// ActionMapfixTriggerSubmitNoContent is response for ActionMapfixTriggerSubmit operation.
|
||||
type ActionMapfixTriggerSubmitNoContent struct{}
|
||||
|
||||
// ActionMapfixTriggerUploadNoContent is response for ActionMapfixTriggerUpload operation.
|
||||
type ActionMapfixTriggerUploadNoContent struct{}
|
||||
@@ -47,14 +53,17 @@ type ActionSubmissionRejectNoContent struct{}
|
||||
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation.
|
||||
type ActionSubmissionRequestChangesNoContent struct{}
|
||||
|
||||
// ActionSubmissionResetSubmittingNoContent is response for ActionSubmissionResetSubmitting operation.
|
||||
type ActionSubmissionResetSubmittingNoContent struct{}
|
||||
|
||||
// ActionSubmissionRetryValidateNoContent is response for ActionSubmissionRetryValidate operation.
|
||||
type ActionSubmissionRetryValidateNoContent struct{}
|
||||
|
||||
// ActionSubmissionRevokeNoContent is response for ActionSubmissionRevoke operation.
|
||||
type ActionSubmissionRevokeNoContent struct{}
|
||||
|
||||
// ActionSubmissionSubmitNoContent is response for ActionSubmissionSubmit operation.
|
||||
type ActionSubmissionSubmitNoContent struct{}
|
||||
// ActionSubmissionTriggerSubmitNoContent is response for ActionSubmissionTriggerSubmit operation.
|
||||
type ActionSubmissionTriggerSubmitNoContent struct{}
|
||||
|
||||
// ActionSubmissionTriggerUploadNoContent is response for ActionSubmissionTriggerUpload operation.
|
||||
type ActionSubmissionTriggerUploadNoContent struct{}
|
||||
@@ -65,6 +74,112 @@ type ActionSubmissionTriggerValidateNoContent struct{}
|
||||
// ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation.
|
||||
type ActionSubmissionValidatedNoContent struct{}
|
||||
|
||||
// Ref: #/components/schemas/AuditEvent
|
||||
type AuditEvent struct {
|
||||
ID int64 `json:"ID"`
|
||||
Date int64 `json:"Date"`
|
||||
User int64 `json:"User"`
|
||||
Username string `json:"Username"`
|
||||
// Is this a submission or is it a mapfix.
|
||||
ResourceType int32 `json:"ResourceType"`
|
||||
ResourceID int64 `json:"ResourceID"`
|
||||
EventType int32 `json:"EventType"`
|
||||
// Arbitrary event data.
|
||||
EventData AuditEventEventData `json:"EventData"`
|
||||
}
|
||||
|
||||
// GetID returns the value of ID.
|
||||
func (s *AuditEvent) GetID() int64 {
|
||||
return s.ID
|
||||
}
|
||||
|
||||
// GetDate returns the value of Date.
|
||||
func (s *AuditEvent) GetDate() int64 {
|
||||
return s.Date
|
||||
}
|
||||
|
||||
// GetUser returns the value of User.
|
||||
func (s *AuditEvent) GetUser() int64 {
|
||||
return s.User
|
||||
}
|
||||
|
||||
// GetUsername returns the value of Username.
|
||||
func (s *AuditEvent) GetUsername() string {
|
||||
return s.Username
|
||||
}
|
||||
|
||||
// GetResourceType returns the value of ResourceType.
|
||||
func (s *AuditEvent) GetResourceType() int32 {
|
||||
return s.ResourceType
|
||||
}
|
||||
|
||||
// GetResourceID returns the value of ResourceID.
|
||||
func (s *AuditEvent) GetResourceID() int64 {
|
||||
return s.ResourceID
|
||||
}
|
||||
|
||||
// GetEventType returns the value of EventType.
|
||||
func (s *AuditEvent) GetEventType() int32 {
|
||||
return s.EventType
|
||||
}
|
||||
|
||||
// GetEventData returns the value of EventData.
|
||||
func (s *AuditEvent) GetEventData() AuditEventEventData {
|
||||
return s.EventData
|
||||
}
|
||||
|
||||
// SetID sets the value of ID.
|
||||
func (s *AuditEvent) SetID(val int64) {
|
||||
s.ID = val
|
||||
}
|
||||
|
||||
// SetDate sets the value of Date.
|
||||
func (s *AuditEvent) SetDate(val int64) {
|
||||
s.Date = val
|
||||
}
|
||||
|
||||
// SetUser sets the value of User.
|
||||
func (s *AuditEvent) SetUser(val int64) {
|
||||
s.User = val
|
||||
}
|
||||
|
||||
// SetUsername sets the value of Username.
|
||||
func (s *AuditEvent) SetUsername(val string) {
|
||||
s.Username = val
|
||||
}
|
||||
|
||||
// SetResourceType sets the value of ResourceType.
|
||||
func (s *AuditEvent) SetResourceType(val int32) {
|
||||
s.ResourceType = val
|
||||
}
|
||||
|
||||
// SetResourceID sets the value of ResourceID.
|
||||
func (s *AuditEvent) SetResourceID(val int64) {
|
||||
s.ResourceID = val
|
||||
}
|
||||
|
||||
// SetEventType sets the value of EventType.
|
||||
func (s *AuditEvent) SetEventType(val int32) {
|
||||
s.EventType = val
|
||||
}
|
||||
|
||||
// SetEventData sets the value of EventData.
|
||||
func (s *AuditEvent) SetEventData(val AuditEventEventData) {
|
||||
s.EventData = val
|
||||
}
|
||||
|
||||
// Arbitrary event data.
|
||||
type AuditEventEventData map[string]jx.Raw
|
||||
|
||||
func (s *AuditEventEventData) init() AuditEventEventData {
|
||||
m := *s
|
||||
if m == nil {
|
||||
m = map[string]jx.Raw{}
|
||||
*s = m
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type CookieAuth struct {
|
||||
APIKey string
|
||||
}
|
||||
@@ -79,6 +194,40 @@ func (s *CookieAuth) SetAPIKey(val string) {
|
||||
s.APIKey = val
|
||||
}
|
||||
|
||||
// CreateMapfixAuditCommentNoContent is response for CreateMapfixAuditComment operation.
|
||||
type CreateMapfixAuditCommentNoContent struct{}
|
||||
|
||||
type CreateMapfixAuditCommentReq struct {
|
||||
Data io.Reader
|
||||
}
|
||||
|
||||
// Read reads data from the Data reader.
|
||||
//
|
||||
// Kept to satisfy the io.Reader interface.
|
||||
func (s CreateMapfixAuditCommentReq) Read(p []byte) (n int, err error) {
|
||||
if s.Data == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return s.Data.Read(p)
|
||||
}
|
||||
|
||||
// CreateSubmissionAuditCommentNoContent is response for CreateSubmissionAuditComment operation.
|
||||
type CreateSubmissionAuditCommentNoContent struct{}
|
||||
|
||||
type CreateSubmissionAuditCommentReq struct {
|
||||
Data io.Reader
|
||||
}
|
||||
|
||||
// Read reads data from the Data reader.
|
||||
//
|
||||
// Kept to satisfy the io.Reader interface.
|
||||
func (s CreateSubmissionAuditCommentReq) Read(p []byte) (n int, err error) {
|
||||
if s.Data == nil {
|
||||
return 0, io.EOF
|
||||
}
|
||||
return s.Data.Read(p)
|
||||
}
|
||||
|
||||
// DeleteScriptNoContent is response for DeleteScript operation.
|
||||
type DeleteScriptNoContent struct{}
|
||||
|
||||
@@ -211,7 +360,7 @@ type Mapfix struct {
|
||||
Completed bool `json:"Completed"`
|
||||
TargetAssetID int64 `json:"TargetAssetID"`
|
||||
StatusID int32 `json:"StatusID"`
|
||||
StatusMessage string `json:"StatusMessage"`
|
||||
Description string `json:"Description"`
|
||||
}
|
||||
|
||||
// GetID returns the value of ID.
|
||||
@@ -274,9 +423,9 @@ func (s *Mapfix) GetStatusID() int32 {
|
||||
return s.StatusID
|
||||
}
|
||||
|
||||
// GetStatusMessage returns the value of StatusMessage.
|
||||
func (s *Mapfix) GetStatusMessage() string {
|
||||
return s.StatusMessage
|
||||
// GetDescription returns the value of Description.
|
||||
func (s *Mapfix) GetDescription() string {
|
||||
return s.Description
|
||||
}
|
||||
|
||||
// SetID sets the value of ID.
|
||||
@@ -339,15 +488,16 @@ func (s *Mapfix) SetStatusID(val int32) {
|
||||
s.StatusID = val
|
||||
}
|
||||
|
||||
// SetStatusMessage sets the value of StatusMessage.
|
||||
func (s *Mapfix) SetStatusMessage(val string) {
|
||||
s.StatusMessage = val
|
||||
// SetDescription sets the value of Description.
|
||||
func (s *Mapfix) SetDescription(val string) {
|
||||
s.Description = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/MapfixTriggerCreate
|
||||
type MapfixTriggerCreate struct {
|
||||
AssetID int64 `json:"AssetID"`
|
||||
TargetAssetID int64 `json:"TargetAssetID"`
|
||||
AssetID int64 `json:"AssetID"`
|
||||
TargetAssetID int64 `json:"TargetAssetID"`
|
||||
Description string `json:"Description"`
|
||||
}
|
||||
|
||||
// GetAssetID returns the value of AssetID.
|
||||
@@ -360,6 +510,11 @@ func (s *MapfixTriggerCreate) GetTargetAssetID() int64 {
|
||||
return s.TargetAssetID
|
||||
}
|
||||
|
||||
// GetDescription returns the value of Description.
|
||||
func (s *MapfixTriggerCreate) GetDescription() string {
|
||||
return s.Description
|
||||
}
|
||||
|
||||
// SetAssetID sets the value of AssetID.
|
||||
func (s *MapfixTriggerCreate) SetAssetID(val int64) {
|
||||
s.AssetID = val
|
||||
@@ -370,6 +525,37 @@ func (s *MapfixTriggerCreate) SetTargetAssetID(val int64) {
|
||||
s.TargetAssetID = val
|
||||
}
|
||||
|
||||
// SetDescription sets the value of Description.
|
||||
func (s *MapfixTriggerCreate) SetDescription(val string) {
|
||||
s.Description = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/Mapfixes
|
||||
type Mapfixes struct {
|
||||
Total int64 `json:"Total"`
|
||||
Mapfixes []Mapfix `json:"Mapfixes"`
|
||||
}
|
||||
|
||||
// GetTotal returns the value of Total.
|
||||
func (s *Mapfixes) GetTotal() int64 {
|
||||
return s.Total
|
||||
}
|
||||
|
||||
// GetMapfixes returns the value of Mapfixes.
|
||||
func (s *Mapfixes) GetMapfixes() []Mapfix {
|
||||
return s.Mapfixes
|
||||
}
|
||||
|
||||
// SetTotal sets the value of Total.
|
||||
func (s *Mapfixes) SetTotal(val int64) {
|
||||
s.Total = val
|
||||
}
|
||||
|
||||
// SetMapfixes sets the value of Mapfixes.
|
||||
func (s *Mapfixes) SetMapfixes(val []Mapfix) {
|
||||
s.Mapfixes = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/Operation
|
||||
type Operation struct {
|
||||
OperationID int32 `json:"OperationID"`
|
||||
@@ -999,7 +1185,6 @@ type Submission struct {
|
||||
Completed bool `json:"Completed"`
|
||||
UploadedAssetID OptInt64 `json:"UploadedAssetID"`
|
||||
StatusID int32 `json:"StatusID"`
|
||||
StatusMessage string `json:"StatusMessage"`
|
||||
}
|
||||
|
||||
// GetID returns the value of ID.
|
||||
@@ -1072,11 +1257,6 @@ func (s *Submission) GetStatusID() int32 {
|
||||
return s.StatusID
|
||||
}
|
||||
|
||||
// GetStatusMessage returns the value of StatusMessage.
|
||||
func (s *Submission) GetStatusMessage() string {
|
||||
return s.StatusMessage
|
||||
}
|
||||
|
||||
// SetID sets the value of ID.
|
||||
func (s *Submission) SetID(val int64) {
|
||||
s.ID = val
|
||||
@@ -1147,14 +1327,12 @@ func (s *Submission) SetStatusID(val int32) {
|
||||
s.StatusID = val
|
||||
}
|
||||
|
||||
// SetStatusMessage sets the value of StatusMessage.
|
||||
func (s *Submission) SetStatusMessage(val string) {
|
||||
s.StatusMessage = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/SubmissionTriggerCreate
|
||||
type SubmissionTriggerCreate struct {
|
||||
AssetID int64 `json:"AssetID"`
|
||||
AssetID int64 `json:"AssetID"`
|
||||
DisplayName string `json:"DisplayName"`
|
||||
Creator string `json:"Creator"`
|
||||
GameID int32 `json:"GameID"`
|
||||
}
|
||||
|
||||
// GetAssetID returns the value of AssetID.
|
||||
@@ -1162,11 +1340,67 @@ func (s *SubmissionTriggerCreate) GetAssetID() int64 {
|
||||
return s.AssetID
|
||||
}
|
||||
|
||||
// GetDisplayName returns the value of DisplayName.
|
||||
func (s *SubmissionTriggerCreate) GetDisplayName() string {
|
||||
return s.DisplayName
|
||||
}
|
||||
|
||||
// GetCreator returns the value of Creator.
|
||||
func (s *SubmissionTriggerCreate) GetCreator() string {
|
||||
return s.Creator
|
||||
}
|
||||
|
||||
// GetGameID returns the value of GameID.
|
||||
func (s *SubmissionTriggerCreate) GetGameID() int32 {
|
||||
return s.GameID
|
||||
}
|
||||
|
||||
// SetAssetID sets the value of AssetID.
|
||||
func (s *SubmissionTriggerCreate) SetAssetID(val int64) {
|
||||
s.AssetID = val
|
||||
}
|
||||
|
||||
// SetDisplayName sets the value of DisplayName.
|
||||
func (s *SubmissionTriggerCreate) SetDisplayName(val string) {
|
||||
s.DisplayName = val
|
||||
}
|
||||
|
||||
// SetCreator sets the value of Creator.
|
||||
func (s *SubmissionTriggerCreate) SetCreator(val string) {
|
||||
s.Creator = val
|
||||
}
|
||||
|
||||
// SetGameID sets the value of GameID.
|
||||
func (s *SubmissionTriggerCreate) SetGameID(val int32) {
|
||||
s.GameID = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/Submissions
|
||||
type Submissions struct {
|
||||
Total int64 `json:"Total"`
|
||||
Submissions []Submission `json:"Submissions"`
|
||||
}
|
||||
|
||||
// GetTotal returns the value of Total.
|
||||
func (s *Submissions) GetTotal() int64 {
|
||||
return s.Total
|
||||
}
|
||||
|
||||
// GetSubmissions returns the value of Submissions.
|
||||
func (s *Submissions) GetSubmissions() []Submission {
|
||||
return s.Submissions
|
||||
}
|
||||
|
||||
// SetTotal sets the value of Total.
|
||||
func (s *Submissions) SetTotal(val int64) {
|
||||
s.Total = val
|
||||
}
|
||||
|
||||
// SetSubmissions sets the value of Submissions.
|
||||
func (s *Submissions) SetSubmissions(val []Submission) {
|
||||
s.Submissions = val
|
||||
}
|
||||
|
||||
// UpdateMapfixModelNoContent is response for UpdateMapfixModel operation.
|
||||
type UpdateMapfixModelNoContent struct{}
|
||||
|
||||
|
||||
@@ -26,6 +26,13 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/request-changes
|
||||
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
|
||||
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
|
||||
//
|
||||
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
|
||||
// UnderConstruction.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/reset-submitting
|
||||
ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error
|
||||
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
|
||||
//
|
||||
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
|
||||
@@ -38,12 +45,12 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/revoke
|
||||
ActionMapfixRevoke(ctx context.Context, params ActionMapfixRevokeParams) error
|
||||
// ActionMapfixSubmit implements actionMapfixSubmit operation.
|
||||
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/submit
|
||||
ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error
|
||||
// POST /mapfixes/{MapfixID}/status/trigger-submit
|
||||
ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error
|
||||
// ActionMapfixTriggerUpload implements actionMapfixTriggerUpload operation.
|
||||
//
|
||||
// Role Admin changes status from Validated -> Uploading.
|
||||
@@ -80,6 +87,13 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/request-changes
|
||||
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
|
||||
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
|
||||
//
|
||||
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
|
||||
// UnderConstruction.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/reset-submitting
|
||||
ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error
|
||||
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
|
||||
//
|
||||
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
|
||||
@@ -92,12 +106,12 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/revoke
|
||||
ActionSubmissionRevoke(ctx context.Context, params ActionSubmissionRevokeParams) error
|
||||
// ActionSubmissionSubmit implements actionSubmissionSubmit operation.
|
||||
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/submit
|
||||
ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error
|
||||
// POST /submissions/{SubmissionID}/status/trigger-submit
|
||||
ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error
|
||||
// ActionSubmissionTriggerUpload implements actionSubmissionTriggerUpload operation.
|
||||
//
|
||||
// Role Admin changes status from Validated -> Uploading.
|
||||
@@ -122,6 +136,12 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes
|
||||
CreateMapfix(ctx context.Context, req *MapfixTriggerCreate) (*OperationID, error)
|
||||
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/comment
|
||||
CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error
|
||||
// CreateScript implements createScript operation.
|
||||
//
|
||||
// Create a new script.
|
||||
@@ -140,6 +160,18 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions
|
||||
CreateSubmission(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
|
||||
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
|
||||
//
|
||||
// Trigger the validator to create a new submission.
|
||||
//
|
||||
// POST /submissions-admin
|
||||
CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (*OperationID, error)
|
||||
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/comment
|
||||
CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error
|
||||
// DeleteScript implements deleteScript operation.
|
||||
//
|
||||
// Delete the specified script by ID.
|
||||
@@ -188,12 +220,18 @@ type Handler interface {
|
||||
//
|
||||
// GET /submissions/{SubmissionID}
|
||||
GetSubmission(ctx context.Context, params GetSubmissionParams) (*Submission, error)
|
||||
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /mapfixes/{MapfixID}/audit-events
|
||||
ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) ([]AuditEvent, error)
|
||||
// ListMapfixes implements listMapfixes operation.
|
||||
//
|
||||
// Get list of mapfixes.
|
||||
//
|
||||
// GET /mapfixes
|
||||
ListMapfixes(ctx context.Context, params ListMapfixesParams) ([]Mapfix, error)
|
||||
ListMapfixes(ctx context.Context, params ListMapfixesParams) (*Mapfixes, error)
|
||||
// ListMaps implements listMaps operation.
|
||||
//
|
||||
// Get list of maps.
|
||||
@@ -212,12 +250,18 @@ type Handler interface {
|
||||
//
|
||||
// GET /scripts
|
||||
ListScripts(ctx context.Context, params ListScriptsParams) ([]Script, error)
|
||||
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /submissions/{SubmissionID}/audit-events
|
||||
ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) ([]AuditEvent, error)
|
||||
// ListSubmissions implements listSubmissions operation.
|
||||
//
|
||||
// Get list of submissions.
|
||||
//
|
||||
// GET /submissions
|
||||
ListSubmissions(ctx context.Context, params ListSubmissionsParams) ([]Submission, error)
|
||||
ListSubmissions(ctx context.Context, params ListSubmissionsParams) (*Submissions, error)
|
||||
// ReleaseSubmissions implements releaseSubmissions operation.
|
||||
//
|
||||
// Release a set of uploaded maps.
|
||||
|
||||
@@ -40,6 +40,16 @@ func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, para
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
|
||||
//
|
||||
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
|
||||
// UnderConstruction.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/reset-submitting
|
||||
func (UnimplementedHandler) ActionMapfixResetSubmitting(ctx context.Context, params ActionMapfixResetSubmittingParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixRetryValidate implements actionMapfixRetryValidate operation.
|
||||
//
|
||||
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
|
||||
@@ -58,12 +68,12 @@ func (UnimplementedHandler) ActionMapfixRevoke(ctx context.Context, params Actio
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixSubmit implements actionMapfixSubmit operation.
|
||||
// ActionMapfixTriggerSubmit implements actionMapfixTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/submit
|
||||
func (UnimplementedHandler) ActionMapfixSubmit(ctx context.Context, params ActionMapfixSubmitParams) error {
|
||||
// POST /mapfixes/{MapfixID}/status/trigger-submit
|
||||
func (UnimplementedHandler) ActionMapfixTriggerSubmit(ctx context.Context, params ActionMapfixTriggerSubmitParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -121,6 +131,16 @@ func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context,
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
|
||||
//
|
||||
// Role Submitter manually resets submitting softlock and changes status from Submitting ->
|
||||
// UnderConstruction.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/reset-submitting
|
||||
func (UnimplementedHandler) ActionSubmissionResetSubmitting(ctx context.Context, params ActionSubmissionResetSubmittingParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionRetryValidate implements actionSubmissionRetryValidate operation.
|
||||
//
|
||||
// Role Reviewer re-runs validation and changes status from Accepted -> Validating.
|
||||
@@ -139,12 +159,12 @@ func (UnimplementedHandler) ActionSubmissionRevoke(ctx context.Context, params A
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmit implements actionSubmissionSubmit operation.
|
||||
// ActionSubmissionTriggerSubmit implements actionSubmissionTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/submit
|
||||
func (UnimplementedHandler) ActionSubmissionSubmit(ctx context.Context, params ActionSubmissionSubmitParams) error {
|
||||
// POST /submissions/{SubmissionID}/status/trigger-submit
|
||||
func (UnimplementedHandler) ActionSubmissionTriggerSubmit(ctx context.Context, params ActionSubmissionTriggerSubmitParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -184,6 +204,15 @@ func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixTrigger
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/comment
|
||||
func (UnimplementedHandler) CreateMapfixAuditComment(ctx context.Context, req CreateMapfixAuditCommentReq, params CreateMapfixAuditCommentParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateScript implements createScript operation.
|
||||
//
|
||||
// Create a new script.
|
||||
@@ -211,6 +240,24 @@ func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *Submissio
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateSubmissionAdmin implements createSubmissionAdmin operation.
|
||||
//
|
||||
// Trigger the validator to create a new submission.
|
||||
//
|
||||
// POST /submissions-admin
|
||||
func (UnimplementedHandler) CreateSubmissionAdmin(ctx context.Context, req *SubmissionTriggerCreate) (r *OperationID, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/comment
|
||||
func (UnimplementedHandler) CreateSubmissionAuditComment(ctx context.Context, req CreateSubmissionAuditCommentReq, params CreateSubmissionAuditCommentParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// DeleteScript implements deleteScript operation.
|
||||
//
|
||||
// Delete the specified script by ID.
|
||||
@@ -283,12 +330,21 @@ func (UnimplementedHandler) GetSubmission(ctx context.Context, params GetSubmiss
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ListMapfixAuditEvents implements listMapfixAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /mapfixes/{MapfixID}/audit-events
|
||||
func (UnimplementedHandler) ListMapfixAuditEvents(ctx context.Context, params ListMapfixAuditEventsParams) (r []AuditEvent, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ListMapfixes implements listMapfixes operation.
|
||||
//
|
||||
// Get list of mapfixes.
|
||||
//
|
||||
// GET /mapfixes
|
||||
func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r []Mapfix, _ error) {
|
||||
func (UnimplementedHandler) ListMapfixes(ctx context.Context, params ListMapfixesParams) (r *Mapfixes, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -319,12 +375,21 @@ func (UnimplementedHandler) ListScripts(ctx context.Context, params ListScriptsP
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ListSubmissionAuditEvents implements listSubmissionAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /submissions/{SubmissionID}/audit-events
|
||||
func (UnimplementedHandler) ListSubmissionAuditEvents(ctx context.Context, params ListSubmissionAuditEventsParams) (r []AuditEvent, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ListSubmissions implements listSubmissions operation.
|
||||
//
|
||||
// Get list of submissions.
|
||||
//
|
||||
// GET /submissions
|
||||
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r []Submission, _ error) {
|
||||
func (UnimplementedHandler) ListSubmissions(ctx context.Context, params ListSubmissionsParams) (r *Submissions, _ error) {
|
||||
return r, ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/auth"
|
||||
"git.itzana.me/strafesnet/go-grpc/maps"
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore/gormstore"
|
||||
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
@@ -125,7 +126,8 @@ func serve(ctx *cli.Context) error {
|
||||
svc := &service.Service{
|
||||
DB: db,
|
||||
Nats: js,
|
||||
Client: maps.NewMapsServiceClient(conn),
|
||||
Maps: maps.NewMapsServiceClient(conn),
|
||||
Users: users.NewUsersServiceClient(conn),
|
||||
}
|
||||
|
||||
conn, err = grpc.Dial(ctx.String("auth-rpc-host"), grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
|
||||
@@ -3,6 +3,8 @@ package datastore
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
)
|
||||
|
||||
@@ -22,6 +24,7 @@ const (
|
||||
)
|
||||
|
||||
type Datastore interface {
|
||||
AuditEvents() AuditEvents
|
||||
Mapfixes() Mapfixes
|
||||
Operations() Operations
|
||||
Submissions() Submissions
|
||||
@@ -29,6 +32,14 @@ type Datastore interface {
|
||||
ScriptPolicy() ScriptPolicy
|
||||
}
|
||||
|
||||
type AuditEvents interface {
|
||||
Get(ctx context.Context, id int64) (model.AuditEvent, error)
|
||||
Create(ctx context.Context, smap model.AuditEvent) (model.AuditEvent, error)
|
||||
Update(ctx context.Context, id int64, values OptionalMap) error
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, filters OptionalMap, page model.Page) ([]model.AuditEvent, error)
|
||||
}
|
||||
|
||||
type Mapfixes interface {
|
||||
Get(ctx context.Context, id int64) (model.Mapfix, error)
|
||||
GetList(ctx context.Context, id []int64) ([]model.Mapfix, error)
|
||||
@@ -38,6 +49,7 @@ type Mapfixes interface {
|
||||
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.MapfixStatus, values OptionalMap) (model.Mapfix, error)
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Mapfix, error)
|
||||
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Mapfix, error)
|
||||
}
|
||||
|
||||
type Operations interface {
|
||||
@@ -45,6 +57,7 @@ type Operations interface {
|
||||
Create(ctx context.Context, smap model.Operation) (model.Operation, error)
|
||||
Update(ctx context.Context, id int32, values OptionalMap) error
|
||||
Delete(ctx context.Context, id int32) error
|
||||
CountSince(ctx context.Context, owner int64, since time.Time) (int64, error)
|
||||
}
|
||||
|
||||
type Submissions interface {
|
||||
@@ -56,6 +69,7 @@ type Submissions interface {
|
||||
IfStatusThenUpdateAndGet(ctx context.Context, id int64, statuses []model.SubmissionStatus, values OptionalMap) (model.Submission, error)
|
||||
Delete(ctx context.Context, id int64) error
|
||||
List(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) ([]model.Submission, error)
|
||||
ListWithTotal(ctx context.Context, filters OptionalMap, page model.Page, sort ListSort) (int64, []model.Submission, error)
|
||||
}
|
||||
|
||||
type Scripts interface {
|
||||
|
||||
64
pkg/datastore/gormstore/audit_events.go
Normal file
64
pkg/datastore/gormstore/audit_events.go
Normal 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()).Offset(int((page.Number - 1) * page.Size)).Limit(int(page.Size)).Find(&events).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return events, nil
|
||||
}
|
||||
@@ -31,6 +31,7 @@ func New(ctx *cli.Context) (datastore.Datastore, error) {
|
||||
|
||||
if ctx.Bool("migrate") {
|
||||
if err := db.AutoMigrate(
|
||||
&model.AuditEvent{},
|
||||
&model.Mapfix{},
|
||||
&model.Operation{},
|
||||
&model.Submission{},
|
||||
|
||||
@@ -9,6 +9,10 @@ type Gormstore struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (g Gormstore) AuditEvents() datastore.AuditEvents {
|
||||
return &AuditEvents{db: g.db}
|
||||
}
|
||||
|
||||
func (g Gormstore) Mapfixes() datastore.Mapfixes {
|
||||
return &Mapfixes{db: g.db}
|
||||
}
|
||||
|
||||
@@ -130,3 +130,19 @@ func (env *Mapfixes) List(ctx context.Context, filters datastore.OptionalMap, pa
|
||||
|
||||
return maps, nil
|
||||
}
|
||||
|
||||
func (env *Mapfixes) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Mapfix, error) {
|
||||
// grab page items
|
||||
maps, err := env.List(ctx, filters, page, sort)
|
||||
if err != nil{
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package gormstore
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
@@ -53,3 +54,12 @@ func (env *Operations) Delete(ctx context.Context, id int32) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (env *Operations) CountSince(ctx context.Context, owner int64, since time.Time) (int64, error) {
|
||||
var count int64
|
||||
if err := env.db.Model(&model.Operation{}).Where("owner = ? AND created_at > ?",owner,since).Count(&count).Error; err != nil {
|
||||
return count, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
@@ -130,3 +130,19 @@ func (env *Submissions) List(ctx context.Context, filters datastore.OptionalMap,
|
||||
|
||||
return maps, nil
|
||||
}
|
||||
|
||||
func (env *Submissions) ListWithTotal(ctx context.Context, filters datastore.OptionalMap, page model.Page, sort datastore.ListSort) (int64, []model.Submission, error) {
|
||||
// grab page items
|
||||
maps, err := env.List(ctx, filters, page, sort)
|
||||
if err != nil{
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -34,6 +34,18 @@ type Invoker interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
|
||||
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error
|
||||
// ActionMapfixUploaded invokes actionMapfixUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -58,6 +70,18 @@ type Invoker interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-failed
|
||||
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
|
||||
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error
|
||||
// ActionSubmissionUploaded invokes actionSubmissionUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -245,15 +269,15 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "StatusMessage" parameter.
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "StatusMessage",
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.StatusMessage))
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@@ -282,6 +306,266 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (c *Client) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
|
||||
_, err := c.sendActionMapfixRequestChanges(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) (res *ActionMapfixRequestChangesNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
elapsedDuration := time.Since(startTime)
|
||||
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
|
||||
}()
|
||||
|
||||
// Increment request counter.
|
||||
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/mapfixes/"
|
||||
{
|
||||
// Encode "MapfixID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "MapfixID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-request-changes"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionMapfixRequestChangesResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
func (c *Client) ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error {
|
||||
_, err := c.sendActionMapfixSubmitted(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) (res *ActionMapfixSubmittedNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixSubmitted"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-submitted"),
|
||||
}
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
elapsedDuration := time.Since(startTime)
|
||||
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
|
||||
}()
|
||||
|
||||
// Increment request counter.
|
||||
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := c.cfg.Tracer.Start(ctx, ActionMapfixSubmittedOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/mapfixes/"
|
||||
{
|
||||
// Encode "MapfixID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "MapfixID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.MapfixID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-submitted"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ModelVersion" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ModelVersion",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "DisplayName" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "DisplayName",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.DisplayName))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "Creator" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "Creator",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.Creator))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "GameID" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "GameID",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.GameID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionMapfixSubmittedResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionMapfixUploaded invokes actionMapfixUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -645,15 +929,15 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "StatusMessage" parameter.
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "StatusMessage",
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.StatusMessage))
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
@@ -682,6 +966,266 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (c *Client) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
|
||||
_, err := c.sendActionSubmissionRequestChanges(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) (res *ActionSubmissionRequestChangesNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
elapsedDuration := time.Since(startTime)
|
||||
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
|
||||
}()
|
||||
|
||||
// Increment request counter.
|
||||
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := c.cfg.Tracer.Start(ctx, ActionSubmissionRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/submissions/"
|
||||
{
|
||||
// Encode "SubmissionID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "SubmissionID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-request-changes"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ErrorMessage" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ErrorMessage",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.ErrorMessage))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionSubmissionRequestChangesResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
func (c *Client) ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error {
|
||||
_, err := c.sendActionSubmissionSubmitted(ctx, params)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) sendActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) (res *ActionSubmissionSubmittedNoContent, err error) {
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionSubmitted"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-submitted"),
|
||||
}
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
elapsedDuration := time.Since(startTime)
|
||||
c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
|
||||
}()
|
||||
|
||||
// Increment request counter.
|
||||
c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := c.cfg.Tracer.Start(ctx, ActionSubmissionSubmittedOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
clientSpanKind,
|
||||
)
|
||||
// Track stage for error reporting.
|
||||
var stage string
|
||||
defer func() {
|
||||
if err != nil {
|
||||
span.RecordError(err)
|
||||
span.SetStatus(codes.Error, stage)
|
||||
c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
|
||||
}
|
||||
span.End()
|
||||
}()
|
||||
|
||||
stage = "BuildURL"
|
||||
u := uri.Clone(c.requestURL(ctx))
|
||||
var pathParts [3]string
|
||||
pathParts[0] = "/submissions/"
|
||||
{
|
||||
// Encode "SubmissionID" parameter.
|
||||
e := uri.NewPathEncoder(uri.PathEncoderConfig{
|
||||
Param: "SubmissionID",
|
||||
Style: uri.PathStyleSimple,
|
||||
Explode: false,
|
||||
})
|
||||
if err := func() error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.SubmissionID))
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
encoded, err := e.Result()
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "encode path")
|
||||
}
|
||||
pathParts[1] = encoded
|
||||
}
|
||||
pathParts[2] = "/status/validator-submitted"
|
||||
uri.AddPathParts(u, pathParts[:]...)
|
||||
|
||||
stage = "EncodeQueryParams"
|
||||
q := uri.NewQueryEncoder()
|
||||
{
|
||||
// Encode "ModelVersion" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "ModelVersion",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int64ToString(params.ModelVersion))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "DisplayName" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "DisplayName",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.DisplayName))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "Creator" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "Creator",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.StringToString(params.Creator))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
{
|
||||
// Encode "GameID" parameter.
|
||||
cfg := uri.QueryParameterEncodingConfig{
|
||||
Name: "GameID",
|
||||
Style: uri.QueryStyleForm,
|
||||
Explode: true,
|
||||
}
|
||||
|
||||
if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
|
||||
return e.EncodeValue(conv.Int32ToString(params.GameID))
|
||||
}); err != nil {
|
||||
return res, errors.Wrap(err, "encode query")
|
||||
}
|
||||
}
|
||||
u.RawQuery = q.Values().Encode()
|
||||
|
||||
stage = "EncodeRequest"
|
||||
r, err := ht.NewRequest(ctx, "POST", u)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "create request")
|
||||
}
|
||||
|
||||
stage = "SendRequest"
|
||||
resp, err := c.cfg.Client.Do(r)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "do request")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
stage = "DecodeResponse"
|
||||
result, err := decodeActionSubmissionSubmittedResponse(resp)
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "decode response")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ActionSubmissionUploaded invokes actionSubmissionUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
|
||||
@@ -129,9 +129,9 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "StatusMessage",
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.StatusMessage,
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
@@ -183,6 +183,324 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixRequestChangesRequest handles actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
serverSpanKind,
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// Add Labeler to context.
|
||||
labeler := &Labeler{attrs: otelAttrs}
|
||||
ctx = contextWithLabeler(ctx, labeler)
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
elapsedDuration := time.Since(startTime)
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
code := statusWriter.status
|
||||
if code != 0 {
|
||||
codeAttr := semconv.HTTPResponseStatusCode(code)
|
||||
attrs = append(attrs, codeAttr)
|
||||
span.SetAttributes(codeAttr)
|
||||
}
|
||||
attrOpt := metric.WithAttributes(attrs...)
|
||||
|
||||
// Increment request counter.
|
||||
s.requests.Add(ctx, 1, attrOpt)
|
||||
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
|
||||
}()
|
||||
|
||||
var (
|
||||
recordError = func(stage string, err error) {
|
||||
span.RecordError(err)
|
||||
|
||||
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
|
||||
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
|
||||
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
|
||||
// max redirects exceeded), in which case status MUST be set to Error.
|
||||
code := statusWriter.status
|
||||
if code >= 100 && code < 500 {
|
||||
span.SetStatus(codes.Error, stage)
|
||||
}
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
if code != 0 {
|
||||
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
|
||||
}
|
||||
|
||||
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
|
||||
}
|
||||
err error
|
||||
opErrContext = ogenerrors.OperationContext{
|
||||
Name: ActionMapfixRequestChangesOperation,
|
||||
ID: "actionMapfixRequestChanges",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionMapfixRequestChangesParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionMapfixRequestChangesNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionMapfixRequestChangesOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
|
||||
OperationID: "actionMapfixRequestChanges",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "MapfixID",
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionMapfixRequestChangesParams
|
||||
Response = *ActionMapfixRequestChangesNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionMapfixRequestChangesParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionMapfixRequestChanges(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionMapfixRequestChanges(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionMapfixRequestChangesResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixSubmittedRequest handles actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
func (s *Server) handleActionMapfixSubmittedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionMapfixSubmitted"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/status/validator-submitted"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionMapfixSubmittedOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
serverSpanKind,
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// Add Labeler to context.
|
||||
labeler := &Labeler{attrs: otelAttrs}
|
||||
ctx = contextWithLabeler(ctx, labeler)
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
elapsedDuration := time.Since(startTime)
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
code := statusWriter.status
|
||||
if code != 0 {
|
||||
codeAttr := semconv.HTTPResponseStatusCode(code)
|
||||
attrs = append(attrs, codeAttr)
|
||||
span.SetAttributes(codeAttr)
|
||||
}
|
||||
attrOpt := metric.WithAttributes(attrs...)
|
||||
|
||||
// Increment request counter.
|
||||
s.requests.Add(ctx, 1, attrOpt)
|
||||
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
|
||||
}()
|
||||
|
||||
var (
|
||||
recordError = func(stage string, err error) {
|
||||
span.RecordError(err)
|
||||
|
||||
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
|
||||
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
|
||||
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
|
||||
// max redirects exceeded), in which case status MUST be set to Error.
|
||||
code := statusWriter.status
|
||||
if code >= 100 && code < 500 {
|
||||
span.SetStatus(codes.Error, stage)
|
||||
}
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
if code != 0 {
|
||||
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
|
||||
}
|
||||
|
||||
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
|
||||
}
|
||||
err error
|
||||
opErrContext = ogenerrors.OperationContext{
|
||||
Name: ActionMapfixSubmittedOperation,
|
||||
ID: "actionMapfixSubmitted",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionMapfixSubmittedParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionMapfixSubmittedNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionMapfixSubmittedOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> Submitted",
|
||||
OperationID: "actionMapfixSubmitted",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "MapfixID",
|
||||
In: "path",
|
||||
}: params.MapfixID,
|
||||
{
|
||||
Name: "ModelVersion",
|
||||
In: "query",
|
||||
}: params.ModelVersion,
|
||||
{
|
||||
Name: "DisplayName",
|
||||
In: "query",
|
||||
}: params.DisplayName,
|
||||
{
|
||||
Name: "Creator",
|
||||
In: "query",
|
||||
}: params.Creator,
|
||||
{
|
||||
Name: "GameID",
|
||||
In: "query",
|
||||
}: params.GameID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionMapfixSubmittedParams
|
||||
Response = *ActionMapfixSubmittedNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionMapfixSubmittedParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionMapfixSubmitted(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionMapfixSubmitted(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionMapfixSubmittedResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionMapfixUploadedRequest handles actionMapfixUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -733,9 +1051,9 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "StatusMessage",
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.StatusMessage,
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
@@ -787,6 +1105,324 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionRequestChangesRequest handles actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionRequestChanges"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-request-changes"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionRequestChangesOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
serverSpanKind,
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// Add Labeler to context.
|
||||
labeler := &Labeler{attrs: otelAttrs}
|
||||
ctx = contextWithLabeler(ctx, labeler)
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
elapsedDuration := time.Since(startTime)
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
code := statusWriter.status
|
||||
if code != 0 {
|
||||
codeAttr := semconv.HTTPResponseStatusCode(code)
|
||||
attrs = append(attrs, codeAttr)
|
||||
span.SetAttributes(codeAttr)
|
||||
}
|
||||
attrOpt := metric.WithAttributes(attrs...)
|
||||
|
||||
// Increment request counter.
|
||||
s.requests.Add(ctx, 1, attrOpt)
|
||||
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
|
||||
}()
|
||||
|
||||
var (
|
||||
recordError = func(stage string, err error) {
|
||||
span.RecordError(err)
|
||||
|
||||
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
|
||||
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
|
||||
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
|
||||
// max redirects exceeded), in which case status MUST be set to Error.
|
||||
code := statusWriter.status
|
||||
if code >= 100 && code < 500 {
|
||||
span.SetStatus(codes.Error, stage)
|
||||
}
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
if code != 0 {
|
||||
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
|
||||
}
|
||||
|
||||
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
|
||||
}
|
||||
err error
|
||||
opErrContext = ogenerrors.OperationContext{
|
||||
Name: ActionSubmissionRequestChangesOperation,
|
||||
ID: "actionSubmissionRequestChanges",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionSubmissionRequestChangesParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionSubmissionRequestChangesNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionSubmissionRequestChangesOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested",
|
||||
OperationID: "actionSubmissionRequestChanges",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "SubmissionID",
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "ErrorMessage",
|
||||
In: "query",
|
||||
}: params.ErrorMessage,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionSubmissionRequestChangesParams
|
||||
Response = *ActionSubmissionRequestChangesNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionSubmissionRequestChangesParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionSubmissionRequestChanges(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionSubmissionRequestChanges(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionSubmissionRequestChangesResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionSubmittedRequest handles actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
func (s *Server) handleActionSubmissionSubmittedRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
|
||||
statusWriter := &codeRecorder{ResponseWriter: w}
|
||||
w = statusWriter
|
||||
otelAttrs := []attribute.KeyValue{
|
||||
otelogen.OperationID("actionSubmissionSubmitted"),
|
||||
semconv.HTTPRequestMethodKey.String("POST"),
|
||||
semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/status/validator-submitted"),
|
||||
}
|
||||
|
||||
// Start a span for this request.
|
||||
ctx, span := s.cfg.Tracer.Start(r.Context(), ActionSubmissionSubmittedOperation,
|
||||
trace.WithAttributes(otelAttrs...),
|
||||
serverSpanKind,
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
// Add Labeler to context.
|
||||
labeler := &Labeler{attrs: otelAttrs}
|
||||
ctx = contextWithLabeler(ctx, labeler)
|
||||
|
||||
// Run stopwatch.
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
elapsedDuration := time.Since(startTime)
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
code := statusWriter.status
|
||||
if code != 0 {
|
||||
codeAttr := semconv.HTTPResponseStatusCode(code)
|
||||
attrs = append(attrs, codeAttr)
|
||||
span.SetAttributes(codeAttr)
|
||||
}
|
||||
attrOpt := metric.WithAttributes(attrs...)
|
||||
|
||||
// Increment request counter.
|
||||
s.requests.Add(ctx, 1, attrOpt)
|
||||
|
||||
// Use floating point division here for higher precision (instead of Millisecond method).
|
||||
s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
|
||||
}()
|
||||
|
||||
var (
|
||||
recordError = func(stage string, err error) {
|
||||
span.RecordError(err)
|
||||
|
||||
// https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
|
||||
// Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
|
||||
// unless there was another error (e.g., network error receiving the response body; or 3xx codes with
|
||||
// max redirects exceeded), in which case status MUST be set to Error.
|
||||
code := statusWriter.status
|
||||
if code >= 100 && code < 500 {
|
||||
span.SetStatus(codes.Error, stage)
|
||||
}
|
||||
|
||||
attrSet := labeler.AttributeSet()
|
||||
attrs := attrSet.ToSlice()
|
||||
if code != 0 {
|
||||
attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
|
||||
}
|
||||
|
||||
s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
|
||||
}
|
||||
err error
|
||||
opErrContext = ogenerrors.OperationContext{
|
||||
Name: ActionSubmissionSubmittedOperation,
|
||||
ID: "actionSubmissionSubmitted",
|
||||
}
|
||||
)
|
||||
params, err := decodeActionSubmissionSubmittedParams(args, argsEscaped, r)
|
||||
if err != nil {
|
||||
err = &ogenerrors.DecodeParamsError{
|
||||
OperationContext: opErrContext,
|
||||
Err: err,
|
||||
}
|
||||
defer recordError("DecodeParams", err)
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
|
||||
var response *ActionSubmissionSubmittedNoContent
|
||||
if m := s.cfg.Middleware; m != nil {
|
||||
mreq := middleware.Request{
|
||||
Context: ctx,
|
||||
OperationName: ActionSubmissionSubmittedOperation,
|
||||
OperationSummary: "(Internal endpoint) Role Validator changes status from Submitting -> Submitted",
|
||||
OperationID: "actionSubmissionSubmitted",
|
||||
Body: nil,
|
||||
Params: middleware.Parameters{
|
||||
{
|
||||
Name: "SubmissionID",
|
||||
In: "path",
|
||||
}: params.SubmissionID,
|
||||
{
|
||||
Name: "ModelVersion",
|
||||
In: "query",
|
||||
}: params.ModelVersion,
|
||||
{
|
||||
Name: "DisplayName",
|
||||
In: "query",
|
||||
}: params.DisplayName,
|
||||
{
|
||||
Name: "Creator",
|
||||
In: "query",
|
||||
}: params.Creator,
|
||||
{
|
||||
Name: "GameID",
|
||||
In: "query",
|
||||
}: params.GameID,
|
||||
},
|
||||
Raw: r,
|
||||
}
|
||||
|
||||
type (
|
||||
Request = struct{}
|
||||
Params = ActionSubmissionSubmittedParams
|
||||
Response = *ActionSubmissionSubmittedNoContent
|
||||
)
|
||||
response, err = middleware.HookMiddleware[
|
||||
Request,
|
||||
Params,
|
||||
Response,
|
||||
](
|
||||
m,
|
||||
mreq,
|
||||
unpackActionSubmissionSubmittedParams,
|
||||
func(ctx context.Context, request Request, params Params) (response Response, err error) {
|
||||
err = s.h.ActionSubmissionSubmitted(ctx, params)
|
||||
return response, err
|
||||
},
|
||||
)
|
||||
} else {
|
||||
err = s.h.ActionSubmissionSubmitted(ctx, params)
|
||||
}
|
||||
if err != nil {
|
||||
if errRes, ok := errors.Into[*ErrorStatusCode](err); ok {
|
||||
if err := encodeErrorResponse(errRes, w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Is(err, ht.ErrNotImplemented) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
return
|
||||
}
|
||||
if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil {
|
||||
defer recordError("Internal", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := encodeActionSubmissionSubmittedResponse(response, w, span); err != nil {
|
||||
defer recordError("EncodeResponse", err)
|
||||
if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
|
||||
s.cfg.ErrorHandler(ctx, w, r, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// handleActionSubmissionUploadedRequest handles actionSubmissionUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
|
||||
@@ -166,9 +166,13 @@ func (s *MapfixCreate) encodeFields(e *jx.Encoder) {
|
||||
e.FieldStart("TargetAssetID")
|
||||
e.Int64(s.TargetAssetID)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Description")
|
||||
e.Str(s.Description)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfMapfixCreate = [8]string{
|
||||
var jsonFieldsNameOfMapfixCreate = [9]string{
|
||||
0: "OperationID",
|
||||
1: "AssetOwner",
|
||||
2: "DisplayName",
|
||||
@@ -177,6 +181,7 @@ var jsonFieldsNameOfMapfixCreate = [8]string{
|
||||
5: "AssetID",
|
||||
6: "AssetVersion",
|
||||
7: "TargetAssetID",
|
||||
8: "Description",
|
||||
}
|
||||
|
||||
// Decode decodes MapfixCreate from json.
|
||||
@@ -184,7 +189,7 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode MapfixCreate to nil")
|
||||
}
|
||||
var requiredBitSet [1]uint8
|
||||
var requiredBitSet [2]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
@@ -284,6 +289,18 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"TargetAssetID\"")
|
||||
}
|
||||
case "Description":
|
||||
requiredBitSet[1] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.Str()
|
||||
s.Description = string(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Description\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@@ -293,8 +310,9 @@ func (s *MapfixCreate) Decode(d *jx.Decoder) error {
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
for i, mask := range [2]uint8{
|
||||
0b11111111,
|
||||
0b00000001,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
@@ -1305,9 +1323,17 @@ func (s *SubmissionCreate) encodeFields(e *jx.Encoder) {
|
||||
e.FieldStart("AssetVersion")
|
||||
e.Int64(s.AssetVersion)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Status")
|
||||
e.UInt32(s.Status)
|
||||
}
|
||||
{
|
||||
e.FieldStart("Roles")
|
||||
e.UInt32(s.Roles)
|
||||
}
|
||||
}
|
||||
|
||||
var jsonFieldsNameOfSubmissionCreate = [7]string{
|
||||
var jsonFieldsNameOfSubmissionCreate = [9]string{
|
||||
0: "OperationID",
|
||||
1: "AssetOwner",
|
||||
2: "DisplayName",
|
||||
@@ -1315,6 +1341,8 @@ var jsonFieldsNameOfSubmissionCreate = [7]string{
|
||||
4: "GameID",
|
||||
5: "AssetID",
|
||||
6: "AssetVersion",
|
||||
7: "Status",
|
||||
8: "Roles",
|
||||
}
|
||||
|
||||
// Decode decodes SubmissionCreate from json.
|
||||
@@ -1322,7 +1350,7 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
if s == nil {
|
||||
return errors.New("invalid: unable to decode SubmissionCreate to nil")
|
||||
}
|
||||
var requiredBitSet [1]uint8
|
||||
var requiredBitSet [2]uint8
|
||||
|
||||
if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
|
||||
switch string(k) {
|
||||
@@ -1410,6 +1438,30 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"AssetVersion\"")
|
||||
}
|
||||
case "Status":
|
||||
requiredBitSet[0] |= 1 << 7
|
||||
if err := func() error {
|
||||
v, err := d.UInt32()
|
||||
s.Status = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Status\"")
|
||||
}
|
||||
case "Roles":
|
||||
requiredBitSet[1] |= 1 << 0
|
||||
if err := func() error {
|
||||
v, err := d.UInt32()
|
||||
s.Roles = uint32(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return errors.Wrap(err, "decode field \"Roles\"")
|
||||
}
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
@@ -1419,8 +1471,9 @@ func (s *SubmissionCreate) Decode(d *jx.Decoder) error {
|
||||
}
|
||||
// Validate required fields.
|
||||
var failures []validate.FieldError
|
||||
for i, mask := range [1]uint8{
|
||||
0b01111111,
|
||||
for i, mask := range [2]uint8{
|
||||
0b11111111,
|
||||
0b00000001,
|
||||
} {
|
||||
if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
|
||||
// Mask only required fields and check equality to mask using XOR.
|
||||
|
||||
@@ -7,10 +7,14 @@ type OperationName = string
|
||||
|
||||
const (
|
||||
ActionMapfixAcceptedOperation OperationName = "ActionMapfixAccepted"
|
||||
ActionMapfixRequestChangesOperation OperationName = "ActionMapfixRequestChanges"
|
||||
ActionMapfixSubmittedOperation OperationName = "ActionMapfixSubmitted"
|
||||
ActionMapfixUploadedOperation OperationName = "ActionMapfixUploaded"
|
||||
ActionMapfixValidatedOperation OperationName = "ActionMapfixValidated"
|
||||
ActionOperationFailedOperation OperationName = "ActionOperationFailed"
|
||||
ActionSubmissionAcceptedOperation OperationName = "ActionSubmissionAccepted"
|
||||
ActionSubmissionRequestChangesOperation OperationName = "ActionSubmissionRequestChanges"
|
||||
ActionSubmissionSubmittedOperation OperationName = "ActionSubmissionSubmitted"
|
||||
ActionSubmissionUploadedOperation OperationName = "ActionSubmissionUploaded"
|
||||
ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated"
|
||||
CreateMapfixOperation OperationName = "CreateMapfix"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -214,6 +214,14 @@ func (s *Server) decodeCreateScriptPolicyRequest(r *http.Request) (
|
||||
}
|
||||
return req, close, err
|
||||
}
|
||||
if err := func() error {
|
||||
if err := request.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return req, close, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &request, close, nil
|
||||
default:
|
||||
return req, close, validate.InvalidContentType(ct)
|
||||
|
||||
@@ -52,6 +52,135 @@ func decodeActionMapfixAcceptedResponse(resp *http.Response) (res *ActionMapfixA
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
}, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
|
||||
}
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionMapfixRequestChangesResponse(resp *http.Response) (res *ActionMapfixRequestChangesNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionMapfixRequestChangesNoContent{}, nil
|
||||
}
|
||||
// Convenient error response.
|
||||
defRes, err := func() (res *ErrorStatusCode, err error) {
|
||||
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var response Error
|
||||
if err := func() error {
|
||||
if err := response.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != io.EOF {
|
||||
return errors.New("unexpected trailing data")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
err = &ogenerrors.DecodeBodyError{
|
||||
ContentType: ct,
|
||||
Body: buf,
|
||||
Err: err,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
}, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
|
||||
}
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionMapfixSubmittedResponse(resp *http.Response) (res *ActionMapfixSubmittedNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionMapfixSubmittedNoContent{}, nil
|
||||
}
|
||||
// Convenient error response.
|
||||
defRes, err := func() (res *ErrorStatusCode, err error) {
|
||||
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var response Error
|
||||
if err := func() error {
|
||||
if err := response.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != io.EOF {
|
||||
return errors.New("unexpected trailing data")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
err = &ogenerrors.DecodeBodyError{
|
||||
ContentType: ct,
|
||||
Body: buf,
|
||||
Err: err,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -103,6 +232,15 @@ func decodeActionMapfixUploadedResponse(resp *http.Response) (res *ActionMapfixU
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -154,6 +292,15 @@ func decodeActionMapfixValidatedResponse(resp *http.Response) (res *ActionMapfix
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -205,6 +352,15 @@ func decodeActionOperationFailedResponse(resp *http.Response) (res *ActionOperat
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -256,6 +412,135 @@ func decodeActionSubmissionAcceptedResponse(resp *http.Response) (res *ActionSub
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
}, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
|
||||
}
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionSubmissionRequestChangesResponse(resp *http.Response) (res *ActionSubmissionRequestChangesNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionSubmissionRequestChangesNoContent{}, nil
|
||||
}
|
||||
// Convenient error response.
|
||||
defRes, err := func() (res *ErrorStatusCode, err error) {
|
||||
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var response Error
|
||||
if err := func() error {
|
||||
if err := response.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != io.EOF {
|
||||
return errors.New("unexpected trailing data")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
err = &ogenerrors.DecodeBodyError{
|
||||
ContentType: ct,
|
||||
Body: buf,
|
||||
Err: err,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
}, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode)
|
||||
}
|
||||
return res, errors.Wrap(defRes, "error")
|
||||
}
|
||||
|
||||
func decodeActionSubmissionSubmittedResponse(resp *http.Response) (res *ActionSubmissionSubmittedNoContent, _ error) {
|
||||
switch resp.StatusCode {
|
||||
case 204:
|
||||
// Code 204.
|
||||
return &ActionSubmissionSubmittedNoContent{}, nil
|
||||
}
|
||||
// Convenient error response.
|
||||
defRes, err := func() (res *ErrorStatusCode, err error) {
|
||||
ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
|
||||
if err != nil {
|
||||
return res, errors.Wrap(err, "parse media type")
|
||||
}
|
||||
switch {
|
||||
case ct == "application/json":
|
||||
buf, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
d := jx.DecodeBytes(buf)
|
||||
|
||||
var response Error
|
||||
if err := func() error {
|
||||
if err := response.Decode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := d.Skip(); err != io.EOF {
|
||||
return errors.New("unexpected trailing data")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
err = &ogenerrors.DecodeBodyError{
|
||||
ContentType: ct,
|
||||
Body: buf,
|
||||
Err: err,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -307,6 +592,15 @@ func decodeActionSubmissionUploadedResponse(resp *http.Response) (res *ActionSub
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -358,6 +652,15 @@ func decodeActionSubmissionValidatedResponse(resp *http.Response) (res *ActionSu
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -405,6 +708,15 @@ func decodeCreateMapfixResponse(resp *http.Response) (res *MapfixID, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &response, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
@@ -441,6 +753,15 @@ func decodeCreateMapfixResponse(resp *http.Response) (res *MapfixID, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -488,6 +809,15 @@ func decodeCreateScriptResponse(resp *http.Response) (res *ScriptID, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &response, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
@@ -524,6 +854,15 @@ func decodeCreateScriptResponse(resp *http.Response) (res *ScriptID, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -571,6 +910,15 @@ func decodeCreateScriptPolicyResponse(resp *http.Response) (res *ScriptPolicyID,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &response, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
@@ -607,6 +955,15 @@ func decodeCreateScriptPolicyResponse(resp *http.Response) (res *ScriptPolicyID,
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -654,6 +1011,15 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *SubmissionID, _ e
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &response, nil
|
||||
default:
|
||||
return res, validate.InvalidContentType(ct)
|
||||
@@ -690,6 +1056,15 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *SubmissionID, _ e
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -782,6 +1157,15 @@ func decodeGetScriptResponse(resp *http.Response) (res *Script, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -899,6 +1283,15 @@ func decodeListScriptPolicyResponse(resp *http.Response) (res []ScriptPolicy, _
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -1016,6 +1409,15 @@ func decodeListScriptsResponse(resp *http.Response) (res []Script, _ error) {
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -1067,6 +1469,15 @@ func decodeUpdateMapfixValidatedModelResponse(resp *http.Response) (res *UpdateM
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
@@ -1118,6 +1529,15 @@ func decodeUpdateSubmissionValidatedModelResponse(resp *http.Response) (res *Upd
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
// Validate response.
|
||||
if err := func() error {
|
||||
if err := response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return res, errors.Wrap(err, "validate")
|
||||
}
|
||||
return &ErrorStatusCode{
|
||||
StatusCode: resp.StatusCode,
|
||||
Response: response,
|
||||
|
||||
@@ -20,6 +20,20 @@ func encodeActionMapfixAcceptedResponse(response *ActionMapfixAcceptedNoContent,
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixRequestChangesResponse(response *ActionMapfixRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixSubmittedResponse(response *ActionMapfixSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionMapfixUploadedResponse(response *ActionMapfixUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
@@ -48,6 +62,20 @@ func encodeActionSubmissionAcceptedResponse(response *ActionSubmissionAcceptedNo
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionRequestChangesResponse(response *ActionSubmissionRequestChangesNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionSubmittedResponse(response *ActionSubmissionSubmittedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func encodeActionSubmissionUploadedResponse(response *ActionSubmissionUploadedNoContent, w http.ResponseWriter, span trace.Span) error {
|
||||
w.WriteHeader(204)
|
||||
span.SetStatus(codes.Ok, http.StatusText(204))
|
||||
|
||||
@@ -147,6 +147,50 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixRequestChangesRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionMapfixSubmittedRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploaded"
|
||||
|
||||
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
|
||||
@@ -454,6 +498,50 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionRequestChangesRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch r.Method {
|
||||
case "POST":
|
||||
s.handleActionSubmissionSubmittedRequest([1]string{
|
||||
args[0],
|
||||
}, elemIsEscaped, w, r)
|
||||
default:
|
||||
s.notAllowed(w, r, "POST")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploaded"
|
||||
|
||||
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
|
||||
@@ -716,6 +804,54 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixRequestChangesOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested"
|
||||
r.operationID = "actionMapfixRequestChanges"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/validator-request-changes"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionMapfixSubmittedOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> Submitted"
|
||||
r.operationID = "actionMapfixSubmitted"
|
||||
r.pathPattern = "/mapfixes/{MapfixID}/status/validator-submitted"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploaded"
|
||||
|
||||
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
|
||||
@@ -1059,6 +1195,54 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
|
||||
}
|
||||
}
|
||||
|
||||
case 'r': // Prefix: "request-changes"
|
||||
|
||||
if l := len("request-changes"); len(elem) >= l && elem[0:l] == "request-changes" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionRequestChangesOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested"
|
||||
r.operationID = "actionSubmissionRequestChanges"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/validator-request-changes"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 's': // Prefix: "submitted"
|
||||
|
||||
if l := len("submitted"); len(elem) >= l && elem[0:l] == "submitted" {
|
||||
elem = elem[l:]
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if len(elem) == 0 {
|
||||
// Leaf node.
|
||||
switch method {
|
||||
case "POST":
|
||||
r.name = ActionSubmissionSubmittedOperation
|
||||
r.summary = "(Internal endpoint) Role Validator changes status from Submitting -> Submitted"
|
||||
r.operationID = "actionSubmissionSubmitted"
|
||||
r.pathPattern = "/submissions/{SubmissionID}/status/validator-submitted"
|
||||
r.args = args
|
||||
r.count = 1
|
||||
return r, true
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
case 'u': // Prefix: "uploaded"
|
||||
|
||||
if l := len("uploaded"); len(elem) >= l && elem[0:l] == "uploaded" {
|
||||
|
||||
@@ -13,6 +13,12 @@ func (s *ErrorStatusCode) Error() string {
|
||||
// ActionMapfixAcceptedNoContent is response for ActionMapfixAccepted operation.
|
||||
type ActionMapfixAcceptedNoContent struct{}
|
||||
|
||||
// ActionMapfixRequestChangesNoContent is response for ActionMapfixRequestChanges operation.
|
||||
type ActionMapfixRequestChangesNoContent struct{}
|
||||
|
||||
// ActionMapfixSubmittedNoContent is response for ActionMapfixSubmitted operation.
|
||||
type ActionMapfixSubmittedNoContent struct{}
|
||||
|
||||
// ActionMapfixUploadedNoContent is response for ActionMapfixUploaded operation.
|
||||
type ActionMapfixUploadedNoContent struct{}
|
||||
|
||||
@@ -25,6 +31,12 @@ type ActionOperationFailedNoContent struct{}
|
||||
// ActionSubmissionAcceptedNoContent is response for ActionSubmissionAccepted operation.
|
||||
type ActionSubmissionAcceptedNoContent struct{}
|
||||
|
||||
// ActionSubmissionRequestChangesNoContent is response for ActionSubmissionRequestChanges operation.
|
||||
type ActionSubmissionRequestChangesNoContent struct{}
|
||||
|
||||
// ActionSubmissionSubmittedNoContent is response for ActionSubmissionSubmitted operation.
|
||||
type ActionSubmissionSubmittedNoContent struct{}
|
||||
|
||||
// ActionSubmissionUploadedNoContent is response for ActionSubmissionUploaded operation.
|
||||
type ActionSubmissionUploadedNoContent struct{}
|
||||
|
||||
@@ -94,6 +106,7 @@ type MapfixCreate struct {
|
||||
AssetID int64 `json:"AssetID"`
|
||||
AssetVersion int64 `json:"AssetVersion"`
|
||||
TargetAssetID int64 `json:"TargetAssetID"`
|
||||
Description string `json:"Description"`
|
||||
}
|
||||
|
||||
// GetOperationID returns the value of OperationID.
|
||||
@@ -136,6 +149,11 @@ func (s *MapfixCreate) GetTargetAssetID() int64 {
|
||||
return s.TargetAssetID
|
||||
}
|
||||
|
||||
// GetDescription returns the value of Description.
|
||||
func (s *MapfixCreate) GetDescription() string {
|
||||
return s.Description
|
||||
}
|
||||
|
||||
// SetOperationID sets the value of OperationID.
|
||||
func (s *MapfixCreate) SetOperationID(val int32) {
|
||||
s.OperationID = val
|
||||
@@ -176,6 +194,11 @@ func (s *MapfixCreate) SetTargetAssetID(val int64) {
|
||||
s.TargetAssetID = val
|
||||
}
|
||||
|
||||
// SetDescription sets the value of Description.
|
||||
func (s *MapfixCreate) SetDescription(val string) {
|
||||
s.Description = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/MapfixID
|
||||
type MapfixID struct {
|
||||
MapfixID int64 `json:"MapfixID"`
|
||||
@@ -571,6 +594,8 @@ type SubmissionCreate struct {
|
||||
GameID int32 `json:"GameID"`
|
||||
AssetID int64 `json:"AssetID"`
|
||||
AssetVersion int64 `json:"AssetVersion"`
|
||||
Status uint32 `json:"Status"`
|
||||
Roles uint32 `json:"Roles"`
|
||||
}
|
||||
|
||||
// GetOperationID returns the value of OperationID.
|
||||
@@ -608,6 +633,16 @@ func (s *SubmissionCreate) GetAssetVersion() int64 {
|
||||
return s.AssetVersion
|
||||
}
|
||||
|
||||
// GetStatus returns the value of Status.
|
||||
func (s *SubmissionCreate) GetStatus() uint32 {
|
||||
return s.Status
|
||||
}
|
||||
|
||||
// GetRoles returns the value of Roles.
|
||||
func (s *SubmissionCreate) GetRoles() uint32 {
|
||||
return s.Roles
|
||||
}
|
||||
|
||||
// SetOperationID sets the value of OperationID.
|
||||
func (s *SubmissionCreate) SetOperationID(val int32) {
|
||||
s.OperationID = val
|
||||
@@ -643,6 +678,16 @@ func (s *SubmissionCreate) SetAssetVersion(val int64) {
|
||||
s.AssetVersion = val
|
||||
}
|
||||
|
||||
// SetStatus sets the value of Status.
|
||||
func (s *SubmissionCreate) SetStatus(val uint32) {
|
||||
s.Status = val
|
||||
}
|
||||
|
||||
// SetRoles sets the value of Roles.
|
||||
func (s *SubmissionCreate) SetRoles(val uint32) {
|
||||
s.Roles = val
|
||||
}
|
||||
|
||||
// Ref: #/components/schemas/SubmissionID
|
||||
type SubmissionID struct {
|
||||
SubmissionID int64 `json:"SubmissionID"`
|
||||
|
||||
@@ -14,6 +14,18 @@ type Handler interface {
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||
ActionMapfixAccepted(ctx context.Context, params ActionMapfixAcceptedParams) error
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error
|
||||
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error
|
||||
// ActionMapfixUploaded implements actionMapfixUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -38,6 +50,18 @@ type Handler interface {
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-failed
|
||||
ActionSubmissionAccepted(ctx context.Context, params ActionSubmissionAcceptedParams) error
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error
|
||||
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error
|
||||
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
|
||||
@@ -22,6 +22,24 @@ func (UnimplementedHandler) ActionMapfixAccepted(ctx context.Context, params Act
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (UnimplementedHandler) ActionMapfixRequestChanges(ctx context.Context, params ActionMapfixRequestChangesParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted implements actionMapfixSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
func (UnimplementedHandler) ActionMapfixSubmitted(ctx context.Context, params ActionMapfixSubmittedParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionMapfixUploaded implements actionMapfixUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
@@ -58,6 +76,24 @@ func (UnimplementedHandler) ActionSubmissionAccepted(ctx context.Context, params
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> ChangesRequested.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (UnimplementedHandler) ActionSubmissionRequestChanges(ctx context.Context, params ActionSubmissionRequestChangesParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted implements actionSubmissionSubmitted operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
func (UnimplementedHandler) ActionSubmissionSubmitted(ctx context.Context, params ActionSubmissionSubmittedParams) error {
|
||||
return ht.ErrNotImplemented
|
||||
}
|
||||
|
||||
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Uploading -> Uploaded.
|
||||
|
||||
@@ -8,12 +8,107 @@ import (
|
||||
"github.com/ogen-go/ogen/validate"
|
||||
)
|
||||
|
||||
func (s *Error) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.Code)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "code",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ErrorStatusCode) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := s.Response.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Response",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MapfixCreate) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.OperationID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "OperationID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetOwner)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetOwner",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
@@ -52,6 +147,137 @@ func (s *MapfixCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.GameID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "GameID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetVersion)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetVersion",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.TargetAssetID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "TargetAssetID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
MinLengthSet: false,
|
||||
MaxLength: 256,
|
||||
MaxLengthSet: true,
|
||||
Email: false,
|
||||
Hostname: false,
|
||||
Regex: nil,
|
||||
}).Validate(string(s.Description)); err != nil {
|
||||
return errors.Wrap(err, "string")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Description",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *MapfixID) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.MapfixID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "MapfixID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@@ -64,6 +290,26 @@ func (s *Script) Validate() error {
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
@@ -121,6 +367,46 @@ func (s *Script) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ResourceType)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ResourceType",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ResourceID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ResourceID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@@ -171,6 +457,85 @@ func (s *ScriptCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ResourceType)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ResourceType",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if value, ok := s.ResourceID.Get(); ok {
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(value)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ResourceID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScriptID) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ScriptID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ScriptID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@@ -183,6 +548,26 @@ func (s *ScriptPolicy) Validate() error {
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 16,
|
||||
@@ -202,6 +587,150 @@ func (s *ScriptPolicy) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ToScriptID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ToScriptID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.Policy)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Policy",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScriptPolicyCreate) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.FromScriptID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "FromScriptID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ToScriptID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ToScriptID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.Policy)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Policy",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ScriptPolicyID) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.ScriptPolicyID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "ScriptPolicyID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
@@ -214,6 +743,46 @@ func (s *SubmissionCreate) Validate() error {
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.OperationID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "OperationID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetOwner)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetOwner",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.String{
|
||||
MinLength: 0,
|
||||
@@ -252,6 +821,118 @@ func (s *SubmissionCreate) Validate() error {
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.GameID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "GameID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.AssetVersion)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "AssetVersion",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: true,
|
||||
Max: 9,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.Status)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "Status",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SubmissionID) Validate() error {
|
||||
if s == nil {
|
||||
return validate.ErrNilPointer
|
||||
}
|
||||
|
||||
var failures []validate.FieldError
|
||||
if err := func() error {
|
||||
if err := (validate.Int{
|
||||
MinSet: true,
|
||||
Min: 0,
|
||||
MaxSet: false,
|
||||
Max: 0,
|
||||
MinExclusive: false,
|
||||
MaxExclusive: false,
|
||||
MultipleOfSet: false,
|
||||
MultipleOf: 0,
|
||||
}).Validate(int64(s.SubmissionID)); err != nil {
|
||||
return errors.Wrap(err, "int")
|
||||
}
|
||||
return nil
|
||||
}(); err != nil {
|
||||
failures = append(failures, validate.FieldError{
|
||||
Name: "SubmissionID",
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
if len(failures) > 0 {
|
||||
return &validate.Error{Fields: failures}
|
||||
}
|
||||
|
||||
59
pkg/model/audit_event.go
Normal file
59
pkg/model/audit_event.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type AuditEventType int32
|
||||
|
||||
// User clicked "Submit", "Accept" etc
|
||||
const AuditEventTypeAction AuditEventType = 0
|
||||
type AuditEventDataAction struct {
|
||||
TargetStatus uint32 `json:"target_status"`
|
||||
}
|
||||
|
||||
// User wrote a comment
|
||||
const AuditEventTypeComment AuditEventType = 1
|
||||
type AuditEventDataComment struct {
|
||||
Comment string `json:"comment"`
|
||||
}
|
||||
|
||||
// User changed Model
|
||||
const AuditEventTypeChangeModel AuditEventType = 2
|
||||
type AuditEventDataChangeModel struct {
|
||||
OldModelID uint64 `json:"old_model_id"`
|
||||
OldModelVersion uint64 `json:"old_model_version"`
|
||||
NewModelID uint64 `json:"new_model_id"`
|
||||
NewModelVersion uint64 `json:"new_model_version"`
|
||||
}
|
||||
// Validator validates model
|
||||
const AuditEventTypeChangeValidatedModel AuditEventType = 3
|
||||
type AuditEventDataChangeValidatedModel struct {
|
||||
ValidatedModelID uint64 `json:"validated_model_id"`
|
||||
ValidatedModelVersion uint64 `json:"validated_model_version"`
|
||||
}
|
||||
|
||||
// User changed DisplayName / Creator
|
||||
const AuditEventTypeChangeDisplayName AuditEventType = 4
|
||||
const AuditEventTypeChangeCreator AuditEventType = 5
|
||||
type AuditEventDataChangeName struct {
|
||||
OldName string `json:"old_name"`
|
||||
NewName string `json:"new_name"`
|
||||
}
|
||||
|
||||
// Validator had an error
|
||||
const AuditEventTypeError AuditEventType = 6
|
||||
type AuditEventDataError struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
type AuditEvent struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
User uint64
|
||||
ResourceType ResourceType // is this a submission or is it a mapfix
|
||||
ResourceID int64 // submission / mapfix / map ID
|
||||
EventType AuditEventType
|
||||
EventData json.RawMessage `gorm:"type:jsonb"`
|
||||
}
|
||||
@@ -5,36 +5,39 @@ import "time"
|
||||
type MapfixStatus int32
|
||||
|
||||
const (
|
||||
// Phase: Final MapfixStatus
|
||||
MapfixStatusRejected MapfixStatus = 8
|
||||
MapfixStatusUploaded MapfixStatus = 7 // uploaded to the group, final status for mapfixes
|
||||
// Phase: Creation
|
||||
MapfixStatusUnderConstruction MapfixStatus = 0
|
||||
MapfixStatusChangesRequested MapfixStatus = 1
|
||||
|
||||
// Phase: Review
|
||||
MapfixStatusSubmitting MapfixStatus = 2
|
||||
MapfixStatusSubmitted MapfixStatus = 3
|
||||
|
||||
// Phase: Testing
|
||||
MapfixStatusUploading MapfixStatus = 6
|
||||
MapfixStatusValidated MapfixStatus = 5
|
||||
MapfixStatusValidating MapfixStatus = 4
|
||||
MapfixStatusAccepted MapfixStatus = 3 // pending script review, can re-trigger validation
|
||||
MapfixStatusAcceptedUnvalidated MapfixStatus = 4 // pending script review, can re-trigger validation
|
||||
MapfixStatusValidating MapfixStatus = 5
|
||||
MapfixStatusValidated MapfixStatus = 6
|
||||
MapfixStatusUploading MapfixStatus = 7
|
||||
|
||||
// Phase: Creation
|
||||
MapfixStatusChangesRequested MapfixStatus = 2
|
||||
MapfixStatusSubmitted MapfixStatus = 1
|
||||
MapfixStatusUnderConstruction MapfixStatus = 0
|
||||
// Phase: Final MapfixStatus
|
||||
MapfixStatusUploaded MapfixStatus = 8 // uploaded to the group, but pending release
|
||||
MapfixStatusRejected MapfixStatus = 9
|
||||
)
|
||||
|
||||
type Mapfix struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID int32
|
||||
GameID uint32
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Submitter int64 // UserID
|
||||
AssetID int64
|
||||
AssetVersion int64
|
||||
ValidatedAssetID int64
|
||||
ValidatedAssetVersion int64
|
||||
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 int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
TargetAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
StatusID MapfixStatus
|
||||
StatusMessage string
|
||||
Description string // mapfix description
|
||||
}
|
||||
|
||||
@@ -7,42 +7,59 @@ package model
|
||||
|
||||
type CreateSubmissionRequest struct {
|
||||
// operation_id is passed back in the response message
|
||||
OperationID int32
|
||||
ModelID int64
|
||||
OperationID int32
|
||||
ModelID uint64
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID uint32
|
||||
Status uint32
|
||||
Roles uint32
|
||||
}
|
||||
|
||||
type CreateMapfixRequest struct {
|
||||
OperationID int32
|
||||
ModelID int64
|
||||
TargetAssetID int64
|
||||
OperationID int32
|
||||
ModelID uint64
|
||||
TargetAssetID uint64
|
||||
Description string
|
||||
}
|
||||
|
||||
|
||||
type CheckSubmissionRequest struct{
|
||||
SubmissionID int64
|
||||
ModelID uint64
|
||||
}
|
||||
|
||||
type CheckMapfixRequest struct{
|
||||
MapfixID int64
|
||||
ModelID uint64
|
||||
}
|
||||
|
||||
type ValidateSubmissionRequest struct {
|
||||
// submission_id is passed back in the response message
|
||||
SubmissionID int64
|
||||
ModelID int64
|
||||
ModelVersion int64
|
||||
ValidatedModelID *int64 // optional value
|
||||
SubmissionID int64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ValidatedModelID *uint64 // optional value
|
||||
}
|
||||
|
||||
type ValidateMapfixRequest struct {
|
||||
MapfixID int64
|
||||
ModelID int64
|
||||
ModelVersion int64
|
||||
ValidatedModelID *int64 // optional value
|
||||
MapfixID int64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ValidatedModelID *uint64 // optional value
|
||||
}
|
||||
|
||||
// Create a new map
|
||||
type UploadSubmissionRequest struct {
|
||||
SubmissionID int64
|
||||
ModelID int64
|
||||
ModelVersion int64
|
||||
SubmissionID int64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
ModelName string
|
||||
}
|
||||
|
||||
type UploadMapfixRequest struct {
|
||||
MapfixID int64
|
||||
ModelID int64
|
||||
ModelVersion int64
|
||||
TargetAssetID int64
|
||||
MapfixID int64
|
||||
ModelID uint64
|
||||
ModelVersion uint64
|
||||
TargetAssetID uint64
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ const (
|
||||
type Operation struct {
|
||||
ID int32 `gorm:"primaryKey"`
|
||||
CreatedAt time.Time
|
||||
Owner int64 // UserID
|
||||
Owner uint64 // UserID
|
||||
StatusID OperationStatus
|
||||
StatusMessage string
|
||||
Path string // redirect to view completed operation e.g. "/mapfixes/4"
|
||||
|
||||
@@ -5,37 +5,39 @@ import "time"
|
||||
type SubmissionStatus int32
|
||||
|
||||
const (
|
||||
// Phase: Final SubmissionStatus
|
||||
SubmissionStatusReleased SubmissionStatus = 9
|
||||
SubmissionStatusRejected SubmissionStatus = 8
|
||||
// Phase: Creation
|
||||
SubmissionStatusUnderConstruction SubmissionStatus = 0
|
||||
SubmissionStatusChangesRequested SubmissionStatus = 1
|
||||
|
||||
// Phase: Review
|
||||
SubmissionStatusSubmitting SubmissionStatus = 2
|
||||
SubmissionStatusSubmitted SubmissionStatus = 3
|
||||
|
||||
// Phase: Testing
|
||||
SubmissionStatusUploaded SubmissionStatus = 7 // uploaded to the group, but pending release
|
||||
SubmissionStatusUploading SubmissionStatus = 6
|
||||
SubmissionStatusValidated SubmissionStatus = 5
|
||||
SubmissionStatusValidating SubmissionStatus = 4
|
||||
SubmissionStatusAccepted SubmissionStatus = 3 // pending script review, can re-trigger validation
|
||||
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: Creation
|
||||
SubmissionStatusChangesRequested SubmissionStatus = 2
|
||||
SubmissionStatusSubmitted SubmissionStatus = 1
|
||||
SubmissionStatusUnderConstruction SubmissionStatus = 0
|
||||
// Phase: Final SubmissionStatus
|
||||
SubmissionStatusRejected SubmissionStatus = 9
|
||||
SubmissionStatusReleased SubmissionStatus = 10
|
||||
)
|
||||
|
||||
type Submission struct {
|
||||
ID int64 `gorm:"primaryKey"`
|
||||
DisplayName string
|
||||
Creator string
|
||||
GameID int32
|
||||
GameID uint32
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
Submitter int64 // UserID
|
||||
AssetID int64
|
||||
AssetVersion int64
|
||||
ValidatedAssetID int64
|
||||
ValidatedAssetVersion int64
|
||||
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 int64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
UploadedAssetID uint64 // where to upload map fix. if the TargetAssetID is 0, it's a new map.
|
||||
StatusID SubmissionStatus
|
||||
StatusMessage string
|
||||
}
|
||||
|
||||
253
pkg/service/audit_events.go
Normal file
253
pkg/service/audit_events.go
Normal file
@@ -0,0 +1,253 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
)
|
||||
|
||||
// CreateMapfixAuditComment implements createMapfixAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/comment
|
||||
func (svc *Service) CreateMapfixAuditComment(ctx context.Context, req api.CreateMapfixAuditCommentReq, params api.CreateMapfixAuditCommentParams) (error) {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
has_role, err := userInfo.HasRoleMapfixReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := []byte{}
|
||||
_, err = req.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Comment := string(data)
|
||||
|
||||
event_data := model.AuditEventDataComment{
|
||||
Comment: Comment,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeComment,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListMapfixAuditEvents invokes listMapfixAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /mapfixes/{MapfixID}/audit-events
|
||||
func (svc *Service) ListMapfixAuditEvents(ctx context.Context, params api.ListMapfixAuditEventsParams) ([]api.AuditEvent, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
filter.Add("resource_type", model.ResourceMapfix)
|
||||
filter.Add("resource_id", params.MapfixID)
|
||||
|
||||
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
Size: params.Limit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idMap := make(map[int64]bool)
|
||||
for _, item := range items {
|
||||
idMap[int64(item.User)] = true
|
||||
}
|
||||
|
||||
var idList users.IdList
|
||||
idList.ID = make([]int64,len(idMap))
|
||||
for userId := range idMap {
|
||||
idList.ID = append(idList.ID, userId)
|
||||
}
|
||||
|
||||
userList, err := svc.Users.GetList(ctx, &idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*users.UserResponse)
|
||||
for _,user := range userList.Users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
|
||||
var resp []api.AuditEvent
|
||||
for _, item := range items {
|
||||
EventData := api.AuditEventEventData{}
|
||||
err = EventData.UnmarshalJSON(item.EventData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
username := ""
|
||||
if userMap[int64(item.User)] != nil {
|
||||
username = userMap[int64(item.User)].Username
|
||||
}
|
||||
resp = append(resp, api.AuditEvent{
|
||||
ID: item.ID,
|
||||
Date: item.CreatedAt.Unix(),
|
||||
User: int64(item.User),
|
||||
Username: username,
|
||||
ResourceType: int32(item.ResourceType),
|
||||
ResourceID: item.ResourceID,
|
||||
EventType: int32(item.EventType),
|
||||
EventData: EventData,
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// CreateSubmissionAuditComment implements createSubmissionAuditComment operation.
|
||||
//
|
||||
// Post a comment to the audit log
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/comment
|
||||
func (svc *Service) CreateSubmissionAuditComment(ctx context.Context, req api.CreateSubmissionAuditCommentReq, params api.CreateSubmissionAuditCommentParams) (error) {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
has_role, err := userInfo.HasRoleSubmissionReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data := []byte{}
|
||||
_, err = req.Read(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
Comment := string(data)
|
||||
|
||||
event_data := model.AuditEventDataComment{
|
||||
Comment: Comment,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeComment,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListSubmissionAuditEvents invokes listSubmissionAuditEvents operation.
|
||||
//
|
||||
// Retrieve a list of audit events.
|
||||
//
|
||||
// GET /submissions/{SubmissionID}/audit-events
|
||||
func (svc *Service) ListSubmissionAuditEvents(ctx context.Context, params api.ListSubmissionAuditEventsParams) ([]api.AuditEvent, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
filter.Add("resource_type", model.ResourceSubmission)
|
||||
filter.Add("resource_id", params.SubmissionID)
|
||||
|
||||
items, err := svc.DB.AuditEvents().List(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
Size: params.Limit,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
idMap := make(map[int64]bool)
|
||||
for _, item := range items {
|
||||
idMap[int64(item.User)] = true
|
||||
}
|
||||
|
||||
var idList users.IdList
|
||||
idList.ID = make([]int64,len(idMap))
|
||||
for userId := range idMap {
|
||||
idList.ID = append(idList.ID, userId)
|
||||
}
|
||||
|
||||
userList, err := svc.Users.GetList(ctx, &idList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userMap := make(map[int64]*users.UserResponse)
|
||||
for _,user := range userList.Users {
|
||||
userMap[user.ID] = user
|
||||
}
|
||||
|
||||
var resp []api.AuditEvent
|
||||
for _, item := range items {
|
||||
EventData := api.AuditEventEventData{}
|
||||
err = EventData.UnmarshalJSON(item.EventData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
username := ""
|
||||
if userMap[int64(item.User)] != nil {
|
||||
username = userMap[int64(item.User)].Username
|
||||
}
|
||||
resp = append(resp, api.AuditEvent{
|
||||
ID: item.ID,
|
||||
Date: item.CreatedAt.Unix(),
|
||||
User: int64(item.User),
|
||||
Username: username,
|
||||
ResourceType: int32(item.ResourceType),
|
||||
ResourceID: item.ResourceID,
|
||||
EventType: int32(item.EventType),
|
||||
EventData: EventData,
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
@@ -25,18 +25,29 @@ var(
|
||||
model.MapfixStatusUploading,
|
||||
model.MapfixStatusValidated,
|
||||
model.MapfixStatusValidating,
|
||||
model.MapfixStatusAccepted,
|
||||
model.MapfixStatusAcceptedUnvalidated,
|
||||
}
|
||||
// Allow 5 mapfixes every 10 minutes
|
||||
CreateMapfixRateLimit int64 = 5
|
||||
CreateMapfixRecencyWindow = time.Second*600
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCreationPhaseMapfixesLimit = errors.New("Active mapfixes limited to 20")
|
||||
ErrActiveMapfixSameTargetAssetID = errors.New("There is an active mapfix with the same TargetAssetID")
|
||||
ErrAcceptOwnMapfix = fmt.Errorf("%w: You cannot accept your own mapfix as the submitter", ErrPermissionDenied)
|
||||
ErrCreateMapfixRateLimit = errors.New("You must not create more than 5 mapfixes every 10 minutes")
|
||||
)
|
||||
|
||||
// POST /mapfixes
|
||||
func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTriggerCreate) (*api.OperationID, error) {
|
||||
// sanitization
|
||||
if request.AssetID<0 || request.TargetAssetID<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var ModelID=uint64(request.AssetID);
|
||||
var TargetAssetID=uint64(request.TargetAssetID);
|
||||
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
@@ -67,7 +78,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
|
||||
// Check if TargetAssetID actually exists
|
||||
{
|
||||
_, err := svc.Client.Get(ctx, &maps.IdMessage{
|
||||
_, err := svc.Maps.Get(ctx, &maps.IdMessage{
|
||||
ID: request.TargetAssetID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -76,8 +87,23 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
}
|
||||
}
|
||||
|
||||
// Check if too many operations have been created recently
|
||||
{
|
||||
count, err := svc.DB.Operations().CountSince(ctx,
|
||||
int64(userId),
|
||||
time.Now().Add(-CreateMapfixRecencyWindow),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if CreateMapfixRateLimit < count {
|
||||
return nil, ErrCreateMapfixRateLimit
|
||||
}
|
||||
}
|
||||
|
||||
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
|
||||
Owner: int64(userId),
|
||||
Owner: userId,
|
||||
StatusID: model.OperationStatusCreated,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -86,8 +112,9 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
|
||||
create_request := model.CreateMapfixRequest{
|
||||
OperationID: operation.ID,
|
||||
ModelID: request.AssetID,
|
||||
TargetAssetID: request.TargetAssetID,
|
||||
ModelID: ModelID,
|
||||
TargetAssetID: TargetAssetID,
|
||||
Description: request.Description,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
@@ -95,7 +122,10 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *api.MapfixTrigger
|
||||
return nil, err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.mapfixes.create", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.create", []byte(j))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.OperationID{
|
||||
OperationID: operation.ID,
|
||||
@@ -116,7 +146,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
|
||||
ID: mapfix.ID,
|
||||
DisplayName: mapfix.DisplayName,
|
||||
Creator: mapfix.Creator,
|
||||
GameID: mapfix.GameID,
|
||||
GameID: int32(mapfix.GameID),
|
||||
CreatedAt: mapfix.CreatedAt.Unix(),
|
||||
UpdatedAt: mapfix.UpdatedAt.Unix(),
|
||||
Submitter: int64(mapfix.Submitter),
|
||||
@@ -125,7 +155,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
|
||||
Completed: mapfix.Completed,
|
||||
TargetAssetID: int64(mapfix.TargetAssetID),
|
||||
StatusID: int32(mapfix.StatusID),
|
||||
StatusMessage: mapfix.StatusMessage,
|
||||
Description: mapfix.Description,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -134,7 +164,7 @@ func (svc *Service) GetMapfix(ctx context.Context, params api.GetMapfixParams) (
|
||||
// Get list of mapfixes.
|
||||
//
|
||||
// GET /mapfixes
|
||||
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) ([]api.Mapfix, error) {
|
||||
func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesParams) (*api.Mapfixes, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
if params.DisplayName.IsSet(){
|
||||
@@ -146,10 +176,22 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
|
||||
if params.GameID.IsSet(){
|
||||
filter.Add("game_id", params.GameID.Value)
|
||||
}
|
||||
if params.Submitter.IsSet(){
|
||||
filter.Add("submitter", params.Submitter.Value)
|
||||
}
|
||||
if params.AssetID.IsSet(){
|
||||
filter.Add("asset_id", params.AssetID.Value)
|
||||
}
|
||||
if params.TargetAssetID.IsSet(){
|
||||
filter.Add("target_asset_id", params.TargetAssetID.Value)
|
||||
}
|
||||
if params.StatusID.IsSet(){
|
||||
filter.Add("status_id", params.StatusID.Value)
|
||||
}
|
||||
|
||||
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
|
||||
|
||||
items, err := svc.DB.Mapfixes().List(ctx, filter, model.Page{
|
||||
total, items, err := svc.DB.Mapfixes().ListWithTotal(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
Size: params.Limit,
|
||||
},sort)
|
||||
@@ -157,13 +199,14 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []api.Mapfix
|
||||
var resp api.Mapfixes
|
||||
resp.Total=total
|
||||
for _, item := range items {
|
||||
resp = append(resp, api.Mapfix{
|
||||
resp.Mapfixes = append(resp.Mapfixes, api.Mapfix{
|
||||
ID: item.ID,
|
||||
DisplayName: item.DisplayName,
|
||||
Creator: item.Creator,
|
||||
GameID: item.GameID,
|
||||
GameID: int32(item.GameID),
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
Submitter: int64(item.Submitter),
|
||||
@@ -172,10 +215,11 @@ func (svc *Service) ListMapfixes(ctx context.Context, params api.ListMapfixesPar
|
||||
Completed: item.Completed,
|
||||
TargetAssetID: int64(item.TargetAssetID),
|
||||
StatusID: int32(item.StatusID),
|
||||
Description: item.Description,
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// PatchMapfixCompleted implements patchMapfixCompleted operation.
|
||||
@@ -220,22 +264,58 @@ func (svc *Service) UpdateMapfixModel(ctx context.Context, params api.UpdateMapf
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == mapfix.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
OldModelID := mapfix.AssetID
|
||||
OldModelVersion := mapfix.AssetVersion
|
||||
NewModelID := uint64(params.ModelID)
|
||||
NewModelVersion := uint64(params.ModelVersion)
|
||||
|
||||
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||
pmap := datastore.Optional()
|
||||
pmap.AddNotNil("asset_id", params.ModelID)
|
||||
pmap.AddNotNil("asset_version", params.VersionID)
|
||||
pmap.Add("asset_id", NewModelID)
|
||||
pmap.Add("asset_version", NewModelVersion)
|
||||
//always reset completed when model changes
|
||||
pmap.Add("completed", false)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusChangesRequested, model.MapfixStatusSubmitted, model.MapfixStatusUnderConstruction}, pmap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataChangeModel{
|
||||
OldModelID: OldModelID,
|
||||
OldModelVersion: OldModelVersion,
|
||||
NewModelID: NewModelID,
|
||||
NewModelVersion: NewModelVersion,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeChangeModel,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixReject invokes actionMapfixReject operation.
|
||||
@@ -255,13 +335,45 @@ func (svc *Service) ActionMapfixReject(ctx context.Context, params api.ActionMap
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusRejected
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusRejected)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges invokes actionMapfixRequestChanges operation.
|
||||
@@ -281,13 +393,13 @@ func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params api.A
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
// transaction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusChangesRequested)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAccepted, model.MapfixStatusSubmitted}, smap)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated, model.MapfixStatusAcceptedUnvalidated, model.MapfixStatusSubmitted}, smap)
|
||||
}
|
||||
|
||||
// ActionMapfixRevoke invokes actionMapfixRevoke operation.
|
||||
@@ -307,27 +419,56 @@ func (svc *Service) ActionMapfixRevoke(ctx context.Context, params api.ActionMap
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == mapfix.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusUnderConstruction)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted, model.MapfixStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixSubmit invokes actionMapfixSubmit operation.
|
||||
// ActionMapfixTriggerSubmit invokes actionMapfixTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/submit
|
||||
func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMapfixSubmitParams) error {
|
||||
// POST /mapfixes/{MapfixID}/status/trigger-submit
|
||||
func (svc *Service) ActionMapfixTriggerSubmit(ctx context.Context, params api.ActionMapfixTriggerSubmitParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
@@ -339,19 +480,128 @@ func (svc *Service) ActionMapfixSubmit(ctx context.Context, params api.ActionMap
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == mapfix.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusSubmitting
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusSubmitted)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUnderConstruction, model.MapfixStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validate_request := model.CheckMapfixRequest{
|
||||
MapfixID: mapfix.ID,
|
||||
ModelID: mapfix.AssetID,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(validate_request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.check", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixResetSubmitting implements actionMapfixResetSubmitting operation.
|
||||
//
|
||||
// Role MapfixReview changes status from Submitting -> UnderConstruction.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/reset-submitting
|
||||
func (svc *Service) ActionMapfixResetSubmitting(ctx context.Context, params api.ActionMapfixResetSubmittingParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when mapfix was updated
|
||||
mapfix, err := svc.DB.Mapfixes().Get(ctx, params.MapfixID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if time.Now().Before(mapfix.UpdatedAt.Add(time.Second*10)) {
|
||||
// the last time the mapfix was updated must be longer than 10 seconds ago
|
||||
return ErrDelayReset
|
||||
}
|
||||
|
||||
// check if caller has required role
|
||||
has_role := userId == mapfix.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixTriggerUpload invokes actionMapfixTriggerUpload operation.
|
||||
@@ -371,12 +621,18 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapUpload
|
||||
return ErrPermissionDeniedNeedRoleMapfixUpload
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusUploading
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusUploading)
|
||||
smap.Add("status_id", target_status)
|
||||
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidated}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -395,7 +651,31 @@ func (svc *Service) ActionMapfixTriggerUpload(ctx context.Context, params api.Ac
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.mapfixes.uploadfix", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.upload", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -417,7 +697,12 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapUpload
|
||||
return ErrPermissionDeniedNeedRoleMapfixUpload
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when mapfix was updated
|
||||
@@ -431,9 +716,36 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params api.Action
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusValidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusValidated)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixTriggerValidate invokes actionMapfixTriggerValidate operation.
|
||||
@@ -453,7 +765,7 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
// read mapfix (this could be done with a transaction WHERE clause)
|
||||
@@ -462,11 +774,13 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err = userInfo.IsSubmitter(uint64(mapfix.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is NOT the submitter
|
||||
has_role = userId == mapfix.Submitter
|
||||
if has_role {
|
||||
return ErrAcceptOwnMapfix
|
||||
}
|
||||
@@ -489,8 +803,9 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusValidating
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusValidating)
|
||||
smap.Add("status_id", target_status)
|
||||
mapfix, err = svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -513,7 +828,31 @@ func (svc *Service) ActionMapfixTriggerValidate(ctx context.Context, params api.
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -535,13 +874,19 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusValidating
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusValidating)
|
||||
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAccepted}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
mapfix, err := svc.DB.Mapfixes().IfStatusThenUpdateAndGet(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusAcceptedUnvalidated}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -563,7 +908,31 @@ func (svc *Service) ActionMapfixRetryValidate(ctx context.Context, params api.Ac
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.mapfixes.validate", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -585,7 +954,12 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleMapfixReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when mapfix was updated
|
||||
@@ -599,8 +973,34 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params api.ActionM
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.MapfixStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusAccepted)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]
|
||||
filter.GameID = ¶ms.GameID.Value
|
||||
}
|
||||
|
||||
mapList, err := svc.Client.List(ctx, &maps.ListRequest{
|
||||
mapList, err := svc.Maps.List(ctx, &maps.ListRequest{
|
||||
Filter: &filter,
|
||||
Page: &maps.Pagination{
|
||||
Size: params.Limit,
|
||||
@@ -56,7 +56,7 @@ func (svc *Service) ListMaps(ctx context.Context, params api.ListMapsParams) ([]
|
||||
//
|
||||
// GET /maps/{MapID}
|
||||
func (svc *Service) GetMap(ctx context.Context, params api.GetMapParams) (*api.Map, error) {
|
||||
mapResponse, err := svc.Client.Get(ctx, &maps.IdMessage{
|
||||
mapResponse, err := svc.Maps.Get(ctx, &maps.IdMessage{
|
||||
ID: params.MapID,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -24,11 +24,13 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar
|
||||
return nil, err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(operation.Owner))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// check if caller is operation owner
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == operation.Owner
|
||||
if !has_role {
|
||||
return nil, ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
@@ -36,7 +38,7 @@ func (svc *Service) GetOperation(ctx context.Context, params api.GetOperationPar
|
||||
return &api.Operation{
|
||||
OperationID: operation.ID,
|
||||
Date: operation.CreatedAt.Unix(),
|
||||
Owner: operation.Owner,
|
||||
Owner: int64(operation.Owner),
|
||||
Status: int32(operation.StatusID),
|
||||
StatusMessage: operation.StatusMessage,
|
||||
Path: operation.Path,
|
||||
|
||||
@@ -63,13 +63,13 @@ func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptP
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.AddNotNil("from_script_hash", int64(hash)) // No type safety!
|
||||
filter.Add("from_script_hash", int64(hash)) // No type safety!
|
||||
}
|
||||
if params.ToScriptID.IsSet(){
|
||||
filter.AddNotNil("to_script_id", params.ToScriptID.Value)
|
||||
filter.Add("to_script_id", params.ToScriptID.Value)
|
||||
}
|
||||
if params.Policy.IsSet(){
|
||||
filter.AddNotNil("policy", params.Policy.Value)
|
||||
filter.Add("policy", params.Policy.Value)
|
||||
}
|
||||
|
||||
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{
|
||||
@@ -121,13 +121,6 @@ func (svc *Service) DeleteScriptPolicy(ctx context.Context, params api.DeleteScr
|
||||
//
|
||||
// GET /script-policy/{ScriptPolicyID}
|
||||
func (svc *Service) GetScriptPolicy(ctx context.Context, params api.GetScriptPolicyParams) (*api.ScriptPolicy, error) {
|
||||
_, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
}
|
||||
|
||||
// Read permission for script policy only requires you to be logged in
|
||||
|
||||
policy, err := svc.DB.ScriptPolicy().Get(ctx, params.ScriptPolicyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -57,19 +57,19 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.AddNotNil("hash", int64(hash)) // No type safety!
|
||||
filter.Add("hash", int64(hash)) // No type safety!
|
||||
}
|
||||
if params.Name.IsSet(){
|
||||
filter.AddNotNil("name", params.Name.Value)
|
||||
filter.Add("name", params.Name.Value)
|
||||
}
|
||||
if params.Source.IsSet(){
|
||||
filter.AddNotNil("source", params.Source.Value)
|
||||
filter.Add("source", params.Source.Value)
|
||||
}
|
||||
if params.ResourceType.IsSet(){
|
||||
filter.AddNotNil("resource_type", params.ResourceType.Value)
|
||||
filter.Add("resource_type", params.ResourceType.Value)
|
||||
}
|
||||
if params.ResourceID.IsSet(){
|
||||
filter.AddNotNil("resource_id", params.ResourceID.Value)
|
||||
filter.Add("resource_id", params.ResourceID.Value)
|
||||
}
|
||||
|
||||
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{
|
||||
@@ -122,13 +122,6 @@ func (svc *Service) DeleteScript(ctx context.Context, params api.DeleteScriptPar
|
||||
//
|
||||
// GET /scripts/{ScriptID}
|
||||
func (svc *Service) GetScript(ctx context.Context, params api.GetScriptParams) (*api.Script, error) {
|
||||
_, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
}
|
||||
|
||||
// Read permission for scripts only requires you to be logged in
|
||||
|
||||
script, err := svc.DB.Scripts().Get(ctx, params.ScriptID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -88,13 +88,6 @@ func (usr UserInfoHandle) Validate() (bool, error) {
|
||||
}
|
||||
return validate.Valid, nil
|
||||
}
|
||||
func (usr UserInfoHandle) IsSubmitter(submitter uint64) (bool, error) {
|
||||
userId, err := usr.GetUserID()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return userId == submitter, nil
|
||||
}
|
||||
func (usr UserInfoHandle) hasRoles(wantRoles Roles) (bool, error) {
|
||||
haveroles, err := usr.GetRoles()
|
||||
if err != nil {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"git.itzana.me/strafesnet/go-grpc/maps"
|
||||
"git.itzana.me/strafesnet/go-grpc/users"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/api"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"github.com/nats-io/nats.go"
|
||||
@@ -19,17 +20,21 @@ var (
|
||||
ErrDelayReset = errors.New("Please give the validator at least 10 seconds to operate before attempting to reset the status")
|
||||
ErrPermissionDeniedNotSubmitter = fmt.Errorf("%w: You must be the submitter to perform this action", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleSubmissionRelease = fmt.Errorf("%w: Need Role SubmissionRelease", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMapUpload = fmt.Errorf("%w: Need Role MapUpload", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMapReview = fmt.Errorf("%w: Need Role MapReview", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMapfixUpload = fmt.Errorf("%w: Need Role MapfixUpload", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMapfixReview = fmt.Errorf("%w: Need Role MapfixReview", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleSubmissionUpload = fmt.Errorf("%w: Need Role SubmissionUpload", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleSubmissionReview = fmt.Errorf("%w: Need Role SubmissionReview", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMapDownload = fmt.Errorf("%w: Need Role MapDownload", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleScriptWrite = fmt.Errorf("%w: Need Role ScriptWrite", ErrPermissionDenied)
|
||||
ErrPermissionDeniedNeedRoleMaptest = fmt.Errorf("%w: Need Role Maptest", ErrPermissionDenied)
|
||||
ErrNegativeID = errors.New("A negative ID was provided")
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
DB datastore.Datastore
|
||||
Nats nats.JetStreamContext
|
||||
Client maps.MapsServiceClient
|
||||
Maps maps.MapsServiceClient
|
||||
Users users.UsersServiceClient
|
||||
}
|
||||
|
||||
// NewError creates *ErrorStatusCode from error returned by handler.
|
||||
|
||||
@@ -25,8 +25,11 @@ var(
|
||||
model.SubmissionStatusUploading,
|
||||
model.SubmissionStatusValidated,
|
||||
model.SubmissionStatusValidating,
|
||||
model.SubmissionStatusAccepted,
|
||||
model.SubmissionStatusAcceptedUnvalidated,
|
||||
}
|
||||
// Allow 5 submissions every 10 minutes
|
||||
CreateSubmissionRateLimit int64 = 5
|
||||
CreateSubmissionRecencyWindow = time.Second*600
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -35,10 +38,17 @@ var (
|
||||
ErrReleaseInvalidStatus = errors.New("Only submissions with Uploaded status can be released")
|
||||
ErrReleaseNoUploadedAssetID = errors.New("Only submissions with a UploadedAssetID can be released")
|
||||
ErrAcceptOwnSubmission = fmt.Errorf("%w: You cannot accept your own submission as the submitter", ErrPermissionDenied)
|
||||
ErrCreateSubmissionRateLimit = errors.New("You must not create more than 5 submissions every 10 minutes")
|
||||
)
|
||||
|
||||
// POST /submissions
|
||||
func (svc *Service) CreateSubmission(ctx context.Context, request *api.SubmissionTriggerCreate) (*api.OperationID, error) {
|
||||
// sanitization
|
||||
if request.AssetID<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var ModelID=uint64(request.AssetID);
|
||||
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
@@ -66,8 +76,24 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
|
||||
return nil, ErrCreationPhaseSubmissionsLimit
|
||||
}
|
||||
}
|
||||
|
||||
// Check if too many operations have been created recently
|
||||
{
|
||||
count, err := svc.DB.Operations().CountSince(ctx,
|
||||
int64(userId),
|
||||
time.Now().Add(-CreateSubmissionRecencyWindow),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if CreateSubmissionRateLimit < count {
|
||||
return nil, ErrCreateSubmissionRateLimit
|
||||
}
|
||||
}
|
||||
|
||||
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
|
||||
Owner: int64(userId),
|
||||
Owner: userId,
|
||||
StatusID: model.OperationStatusCreated,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -75,8 +101,13 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
|
||||
}
|
||||
|
||||
create_request := model.CreateSubmissionRequest{
|
||||
OperationID: operation.ID,
|
||||
ModelID: request.AssetID,
|
||||
OperationID: operation.ID,
|
||||
ModelID: ModelID,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: uint32(request.GameID),
|
||||
Status: uint32(model.SubmissionStatusUnderConstruction),
|
||||
Roles: uint32(RolesEmpty),
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
@@ -84,7 +115,86 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *api.Submissio
|
||||
return nil, err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.submissions.create", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.submissions.create", []byte(j))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.OperationID{
|
||||
OperationID: operation.ID,
|
||||
}, nil
|
||||
}
|
||||
// POST /submissions-admin
|
||||
func (svc *Service) CreateSubmissionAdmin(ctx context.Context, request *api.SubmissionTriggerCreate) (*api.OperationID, error) {
|
||||
// sanitization
|
||||
if request.AssetID<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var ModelID=uint64(request.AssetID);
|
||||
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return nil, ErrUserInfo
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles, err := userInfo.GetRoles()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// check if caller has required role
|
||||
has_role := roles & RolesSubmissionReview == RolesSubmissionReview
|
||||
if !has_role {
|
||||
return nil, ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
// Check if too many operations have been created recently
|
||||
{
|
||||
count, err := svc.DB.Operations().CountSince(ctx,
|
||||
int64(userId),
|
||||
time.Now().Add(-CreateSubmissionRecencyWindow),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if CreateSubmissionRateLimit < count {
|
||||
return nil, ErrCreateSubmissionRateLimit
|
||||
}
|
||||
}
|
||||
|
||||
operation, err := svc.DB.Operations().Create(ctx, model.Operation{
|
||||
Owner: userId,
|
||||
StatusID: model.OperationStatusCreated,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
create_request := model.CreateSubmissionRequest{
|
||||
OperationID: operation.ID,
|
||||
ModelID: ModelID,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: uint32(request.GameID),
|
||||
Status: uint32(model.SubmissionStatusChangesRequested),
|
||||
Roles: uint32(roles),
|
||||
}
|
||||
|
||||
j, err := json.Marshal(create_request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.submissions.create", []byte(j))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.OperationID{
|
||||
OperationID: operation.ID,
|
||||
@@ -105,7 +215,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
|
||||
ID: submission.ID,
|
||||
DisplayName: submission.DisplayName,
|
||||
Creator: submission.Creator,
|
||||
GameID: submission.GameID,
|
||||
GameID: int32(submission.GameID),
|
||||
CreatedAt: submission.CreatedAt.Unix(),
|
||||
UpdatedAt: submission.UpdatedAt.Unix(),
|
||||
Submitter: int64(submission.Submitter),
|
||||
@@ -114,7 +224,6 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
|
||||
Completed: submission.Completed,
|
||||
UploadedAssetID: api.NewOptInt64(int64(submission.UploadedAssetID)),
|
||||
StatusID: int32(submission.StatusID),
|
||||
StatusMessage: submission.StatusMessage,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -123,7 +232,7 @@ func (svc *Service) GetSubmission(ctx context.Context, params api.GetSubmissionP
|
||||
// Get list of submissions.
|
||||
//
|
||||
// GET /submissions
|
||||
func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissionsParams) ([]api.Submission, error) {
|
||||
func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissionsParams) (*api.Submissions, error) {
|
||||
filter := datastore.Optional()
|
||||
|
||||
if params.DisplayName.IsSet(){
|
||||
@@ -135,10 +244,22 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
|
||||
if params.GameID.IsSet(){
|
||||
filter.Add("game_id", params.GameID.Value)
|
||||
}
|
||||
if params.Submitter.IsSet(){
|
||||
filter.Add("submitter", params.Submitter.Value)
|
||||
}
|
||||
if params.AssetID.IsSet(){
|
||||
filter.Add("asset_id", params.AssetID.Value)
|
||||
}
|
||||
if params.UploadedAssetID.IsSet(){
|
||||
filter.Add("uploaded_asset_id", params.UploadedAssetID.Value)
|
||||
}
|
||||
if params.StatusID.IsSet(){
|
||||
filter.Add("status_id", params.StatusID.Value)
|
||||
}
|
||||
|
||||
sort := datastore.ListSort(params.Sort.Or(int32(datastore.ListSortDisabled)))
|
||||
|
||||
items, err := svc.DB.Submissions().List(ctx, filter, model.Page{
|
||||
total, items, err := svc.DB.Submissions().ListWithTotal(ctx, filter, model.Page{
|
||||
Number: params.Page,
|
||||
Size: params.Limit,
|
||||
},sort)
|
||||
@@ -146,13 +267,14 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp []api.Submission
|
||||
var resp api.Submissions
|
||||
resp.Total=total
|
||||
for _, item := range items {
|
||||
resp = append(resp, api.Submission{
|
||||
resp.Submissions = append(resp.Submissions, api.Submission{
|
||||
ID: item.ID,
|
||||
DisplayName: item.DisplayName,
|
||||
Creator: item.Creator,
|
||||
GameID: item.GameID,
|
||||
GameID: int32(item.GameID),
|
||||
CreatedAt: item.CreatedAt.Unix(),
|
||||
UpdatedAt: item.UpdatedAt.Unix(),
|
||||
Submitter: int64(item.Submitter),
|
||||
@@ -164,7 +286,7 @@ func (svc *Service) ListSubmissions(ctx context.Context, params api.ListSubmissi
|
||||
})
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
// PatchSubmissionCompleted implements patchSubmissionCompleted operation.
|
||||
@@ -209,22 +331,58 @@ func (svc *Service) UpdateSubmissionModel(ctx context.Context, params api.Update
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == submission.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
OldModelID := submission.AssetID
|
||||
OldModelVersion := submission.AssetVersion
|
||||
NewModelID := uint64(params.ModelID)
|
||||
NewModelVersion := uint64(params.ModelVersion)
|
||||
|
||||
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||
pmap := datastore.Optional()
|
||||
pmap.AddNotNil("asset_id", params.ModelID)
|
||||
pmap.AddNotNil("asset_version", params.VersionID)
|
||||
pmap.Add("asset_id", NewModelID)
|
||||
pmap.Add("asset_version", NewModelVersion)
|
||||
//always reset completed when model changes
|
||||
pmap.Add("completed", false)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusSubmitted, model.SubmissionStatusUnderConstruction}, pmap)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusChangesRequested, model.SubmissionStatusUnderConstruction}, pmap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataChangeModel{
|
||||
OldModelID: OldModelID,
|
||||
OldModelVersion: OldModelVersion,
|
||||
NewModelID: NewModelID,
|
||||
NewModelVersion: NewModelVersion,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: submission.ID,
|
||||
EventType: model.AuditEventTypeChangeModel,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionReject invokes actionSubmissionReject operation.
|
||||
@@ -244,13 +402,45 @@ func (svc *Service) ActionSubmissionReject(ctx context.Context, params api.Actio
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusRejected
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusRejected)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges invokes actionSubmissionRequestChanges operation.
|
||||
@@ -270,13 +460,45 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params a
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusChangesRequested)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAccepted, model.SubmissionStatusSubmitted}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated, model.SubmissionStatusAcceptedUnvalidated, model.SubmissionStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRevoke invokes actionSubmissionRevoke operation.
|
||||
@@ -296,27 +518,56 @@ func (svc *Service) ActionSubmissionRevoke(ctx context.Context, params api.Actio
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
has_role := userId == submission.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusUnderConstruction)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted, model.SubmissionStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmit invokes actionSubmissionSubmit operation.
|
||||
// ActionSubmissionTriggerSubmit invokes actionSubmissionTriggerSubmit operation.
|
||||
//
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitted.
|
||||
// Role Submitter changes status from UnderConstruction|ChangesRequested -> Submitting.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/submit
|
||||
func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.ActionSubmissionSubmitParams) error {
|
||||
// POST /submissions/{SubmissionID}/status/trigger-submit
|
||||
func (svc *Service) ActionSubmissionTriggerSubmit(ctx context.Context, params api.ActionSubmissionTriggerSubmitParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
@@ -328,19 +579,134 @@ func (svc *Service) ActionSubmissionSubmit(ctx context.Context, params api.Actio
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err := userInfo.IsSubmitter(uint64(submission.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
has_submission_review, err := userInfo.HasRoleSubmissionReview()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is the submitter
|
||||
is_submitter := userId == submission.Submitter
|
||||
// neither = deny
|
||||
if !is_submitter && !has_submission_review {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusSubmitting
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
validate_request := model.CheckSubmissionRequest{
|
||||
SubmissionID: submission.ID,
|
||||
ModelID: submission.AssetID,
|
||||
}
|
||||
|
||||
j, err := json.Marshal(validate_request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.Nats.Publish("maptest.submissions.check", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionResetSubmitting implements actionSubmissionResetSubmitting operation.
|
||||
//
|
||||
// Role SubmissionReview changes status from Submitting -> UnderConstruction.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/reset-submitting
|
||||
func (svc *Service) ActionSubmissionResetSubmitting(ctx context.Context, params api.ActionSubmissionResetSubmittingParams) error {
|
||||
userInfo, ok := ctx.Value("UserInfo").(UserInfoHandle)
|
||||
if !ok {
|
||||
return ErrUserInfo
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when submission was updated
|
||||
submission, err := svc.DB.Submissions().Get(ctx, params.SubmissionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if time.Now().Before(submission.UpdatedAt.Add(time.Second*10)) {
|
||||
// the last time the submission was updated must be longer than 10 seconds ago
|
||||
return ErrDelayReset
|
||||
}
|
||||
|
||||
// check if caller has required role
|
||||
has_role := userId == submission.Submitter
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNotSubmitter
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusUnderConstruction
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusSubmitted)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUnderConstruction, model.SubmissionStatusChangesRequested}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionTriggerUpload invokes actionSubmissionTriggerUpload operation.
|
||||
@@ -360,12 +726,18 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapUpload
|
||||
return ErrPermissionDeniedNeedRoleSubmissionUpload
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusUploading
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusUploading)
|
||||
smap.Add("status_id", target_status)
|
||||
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidated}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -387,12 +759,36 @@ func (svc *Service) ActionSubmissionTriggerUpload(ctx context.Context, params ap
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.submissions.upload", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.submissions.upload", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// refuse to operate
|
||||
return ErrUploadedAssetIDAlreadyExists
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -413,7 +809,12 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapUpload
|
||||
return ErrPermissionDeniedNeedRoleSubmissionUpload
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when submission was updated
|
||||
@@ -427,9 +828,36 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params api.Ac
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusValidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusValidated)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionTriggerValidate invokes actionSubmissionTriggerValidate operation.
|
||||
@@ -449,7 +877,7 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
// read submission (this could be done with a transaction WHERE clause)
|
||||
@@ -458,18 +886,21 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
|
||||
return err
|
||||
}
|
||||
|
||||
has_role, err = userInfo.IsSubmitter(uint64(submission.Submitter))
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if caller is NOT the submitter
|
||||
has_role = userId == submission.Submitter
|
||||
if has_role {
|
||||
return ErrAcceptOwnSubmission
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusValidating
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusValidating)
|
||||
smap.Add("status_id", target_status)
|
||||
submission, err = svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitted}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -492,7 +923,31 @@ func (svc *Service) ActionSubmissionTriggerValidate(ctx context.Context, params
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.submissions.validate", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.submissions.validate", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -514,13 +969,19 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusValidating
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusValidating)
|
||||
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAccepted}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
submission, err := svc.DB.Submissions().IfStatusThenUpdateAndGet(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusAcceptedUnvalidated}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -542,7 +1003,31 @@ func (svc *Service) ActionSubmissionRetryValidate(ctx context.Context, params ap
|
||||
return err
|
||||
}
|
||||
|
||||
svc.Nats.Publish("maptest.submissions.validate", []byte(j))
|
||||
_, err = svc.Nats.Publish("maptest.submissions.validate", []byte(j))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -564,7 +1049,12 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
|
||||
}
|
||||
// check if caller has required role
|
||||
if !has_role {
|
||||
return ErrPermissionDeniedNeedRoleMapReview
|
||||
return ErrPermissionDeniedNeedRoleSubmissionReview
|
||||
}
|
||||
|
||||
userId, err := userInfo.GetUserID()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check when submission was updated
|
||||
@@ -578,10 +1068,36 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params api.Act
|
||||
}
|
||||
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusAccepted)
|
||||
smap.Add("status_message", "Manually forced reset")
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err = svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: userId,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReleaseSubmissions invokes releaseSubmissions operation.
|
||||
@@ -627,12 +1143,13 @@ func (svc *Service) ReleaseSubmissions(ctx context.Context, request []api.Releas
|
||||
|
||||
for i,submission := range submissions{
|
||||
date := request[i].Date.Unix()
|
||||
var GameID = int32(submission.GameID)
|
||||
// create each map with go-grpc
|
||||
_, err := svc.Client.Create(ctx, &maps.MapRequest{
|
||||
ID: submission.UploadedAssetID,
|
||||
_, err := svc.Maps.Create(ctx, &maps.MapRequest{
|
||||
ID: int64(submission.UploadedAssetID),
|
||||
DisplayName: &submission.DisplayName,
|
||||
Creator: &submission.Creator,
|
||||
GameID: &submission.GameID,
|
||||
GameID: &GameID,
|
||||
Date: &date,
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,7 @@ package service_internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -16,7 +17,7 @@ var(
|
||||
model.MapfixStatusUploading,
|
||||
model.MapfixStatusValidated,
|
||||
model.MapfixStatusValidating,
|
||||
model.MapfixStatusAccepted,
|
||||
model.MapfixStatusAcceptedUnvalidated,
|
||||
model.MapfixStatusChangesRequested,
|
||||
model.MapfixStatusSubmitted,
|
||||
model.MapfixStatusUnderConstruction,
|
||||
@@ -34,13 +35,148 @@ var(
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/validated-model
|
||||
func (svc *Service) UpdateMapfixValidatedModel(ctx context.Context, params internal.UpdateMapfixValidatedModelParams) error {
|
||||
ValidatedModelID := uint64(params.ValidatedModelID)
|
||||
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
|
||||
|
||||
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||
pmap := datastore.Optional()
|
||||
pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
|
||||
pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
|
||||
pmap.Add("validated_asset_id", ValidatedModelID)
|
||||
pmap.Add("validated_asset_version", ValidatedModelVersion)
|
||||
// DO NOT reset completed when validated model is updated
|
||||
// pmap.Add("completed", false)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, pmap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataChangeValidatedModel{
|
||||
ValidatedModelID: ValidatedModelID,
|
||||
ValidatedModelVersion: ValidatedModelVersion,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeChangeValidatedModel,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixSubmitted invokes actionMapfixSubmitted operation.
|
||||
//
|
||||
// Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-submitted
|
||||
func (svc *Service) ActionMapfixSubmitted(ctx context.Context, params internal.ActionMapfixSubmittedParams) error {
|
||||
// transaction
|
||||
target_status := model.MapfixStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("asset_version", params.ModelVersion)
|
||||
smap.Add("display_name", params.DisplayName)
|
||||
smap.Add("creator", params.Creator)
|
||||
smap.Add("game_id", params.GameID)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixRequestChanges implements actionMapfixRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
|
||||
//
|
||||
// POST /mapfixes/{MapfixID}/status/validator-request-changes
|
||||
func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params internal.ActionMapfixRequestChangesParams) error {
|
||||
// transaction
|
||||
target_status := model.MapfixStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixValidate invokes actionMapfixValidate operation.
|
||||
@@ -62,10 +198,61 @@ func (svc *Service) ActionMapfixValidated(ctx context.Context, params internal.A
|
||||
// POST /mapfixes/{MapfixID}/status/validator-failed
|
||||
func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.ActionMapfixAcceptedParams) error {
|
||||
// transaction
|
||||
target_status := model.MapfixStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusAccepted)
|
||||
smap.Add("status_message", params.StatusMessage)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionMapfixUploaded implements actionMapfixUploaded operation.
|
||||
@@ -75,13 +262,54 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.Ac
|
||||
// POST /mapfixes/{MapfixID}/status/validator-uploaded
|
||||
func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.ActionMapfixUploadedParams) error {
|
||||
// transaction
|
||||
target_status := model.MapfixStatusUploaded
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.MapfixStatusUploaded)
|
||||
return svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Mapfixes().IfStatusThenUpdate(ctx, params.MapfixID, []model.MapfixStatus{model.MapfixStatusUploading}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceMapfix,
|
||||
ResourceID: params.MapfixID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// POST /mapfixes
|
||||
func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCreate) (*internal.MapfixID, error) {
|
||||
// sanitization
|
||||
if request.GameID<0||
|
||||
request.AssetOwner<0||
|
||||
request.AssetID<0||
|
||||
request.AssetVersion<0||
|
||||
request.TargetAssetID<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var GameID=uint32(request.GameID);
|
||||
var Submitter=uint64(request.AssetOwner);
|
||||
var AssetID=uint64(request.AssetID);
|
||||
var AssetVersion=uint64(request.AssetVersion);
|
||||
var TargetAssetID=uint64(request.TargetAssetID);
|
||||
|
||||
// Check if an active mapfix with the same asset id exists
|
||||
{
|
||||
filter := datastore.Optional()
|
||||
@@ -107,7 +335,7 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
|
||||
|
||||
// check if user owns asset
|
||||
// TODO: allow bypass by admin
|
||||
if operation.Owner != request.AssetOwner {
|
||||
if operation.Owner != Submitter {
|
||||
return nil, ErrNotAssetOwner
|
||||
}
|
||||
|
||||
@@ -115,13 +343,14 @@ func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCr
|
||||
ID: 0,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: request.GameID,
|
||||
Submitter: request.AssetOwner,
|
||||
AssetID: request.AssetID,
|
||||
AssetVersion: request.AssetVersion,
|
||||
GameID: GameID,
|
||||
Submitter: Submitter,
|
||||
AssetID: AssetID,
|
||||
AssetVersion: AssetVersion,
|
||||
Completed: false,
|
||||
TargetAssetID: request.TargetAssetID,
|
||||
TargetAssetID: TargetAssetID,
|
||||
StatusID: model.MapfixStatusUnderConstruction,
|
||||
Description: request.Description,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
)
|
||||
|
||||
@@ -49,13 +49,13 @@ func (svc *Service) ListScriptPolicy(ctx context.Context, params api.ListScriptP
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.AddNotNil("from_script_hash", int64(hash)) // No type safety!
|
||||
filter.Add("from_script_hash", int64(hash)) // No type safety!
|
||||
}
|
||||
if params.ToScriptID.IsSet(){
|
||||
filter.AddNotNil("to_script_id", params.ToScriptID.Value)
|
||||
filter.Add("to_script_id", params.ToScriptID.Value)
|
||||
}
|
||||
if params.Policy.IsSet(){
|
||||
filter.AddNotNil("policy", params.Policy.Value)
|
||||
filter.Add("policy", params.Policy.Value)
|
||||
}
|
||||
|
||||
items, err := svc.DB.ScriptPolicy().List(ctx, filter, model.Page{
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
api "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
)
|
||||
|
||||
@@ -44,19 +44,19 @@ func (svc *Service) ListScripts(ctx context.Context, params api.ListScriptsParam
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filter.AddNotNil("hash", int64(hash)) // No type safety!
|
||||
filter.Add("hash", int64(hash)) // No type safety!
|
||||
}
|
||||
if params.Name.IsSet(){
|
||||
filter.AddNotNil("name", params.Name.Value)
|
||||
filter.Add("name", params.Name.Value)
|
||||
}
|
||||
if params.Source.IsSet(){
|
||||
filter.AddNotNil("source", params.Source.Value)
|
||||
filter.Add("source", params.Source.Value)
|
||||
}
|
||||
if params.ResourceType.IsSet(){
|
||||
filter.AddNotNil("resource_type", params.ResourceType.Value)
|
||||
filter.Add("resource_type", params.ResourceType.Value)
|
||||
}
|
||||
if params.ResourceID.IsSet(){
|
||||
filter.AddNotNil("resource_id", params.ResourceID.Value)
|
||||
filter.Add("resource_id", params.ResourceID.Value)
|
||||
}
|
||||
|
||||
items, err := svc.DB.Scripts().List(ctx, filter, model.Page{
|
||||
|
||||
@@ -3,12 +3,21 @@ package service_internal
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
"github.com/nats-io/nats.go"
|
||||
)
|
||||
|
||||
const (
|
||||
ValidtorUserID uint64 = uint64(math.MaxInt64)
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNegativeID = errors.New("A negative ID was provided")
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
DB datastore.Datastore
|
||||
Nats nats.JetStreamContext
|
||||
|
||||
@@ -2,12 +2,14 @@ package service_internal
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/datastore"
|
||||
internal "git.itzana.me/strafesnet/maps-service/pkg/internal"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/model"
|
||||
"git.itzana.me/strafesnet/maps-service/pkg/service"
|
||||
)
|
||||
|
||||
var(
|
||||
@@ -16,7 +18,7 @@ var(
|
||||
model.SubmissionStatusUploading,
|
||||
model.SubmissionStatusValidated,
|
||||
model.SubmissionStatusValidating,
|
||||
model.SubmissionStatusAccepted,
|
||||
model.SubmissionStatusAcceptedUnvalidated,
|
||||
model.SubmissionStatusChangesRequested,
|
||||
model.SubmissionStatusSubmitted,
|
||||
model.SubmissionStatusUnderConstruction,
|
||||
@@ -33,13 +35,150 @@ var(
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/validated-model
|
||||
func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params internal.UpdateSubmissionValidatedModelParams) error {
|
||||
ValidatedModelID := uint64(params.ValidatedModelID)
|
||||
ValidatedModelVersion := uint64(params.ValidatedModelVersion)
|
||||
|
||||
// check if Status is ChangesRequested|Submitted|UnderConstruction
|
||||
pmap := datastore.Optional()
|
||||
pmap.AddNotNil("validated_asset_id", params.ValidatedModelID)
|
||||
pmap.AddNotNil("validated_asset_version", params.ValidatedModelVersion)
|
||||
pmap.Add("validated_asset_id", ValidatedModelID)
|
||||
pmap.Add("validated_asset_version", ValidatedModelVersion)
|
||||
// DO NOT reset completed when validated model is updated
|
||||
// pmap.Add("completed", false)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, pmap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataChangeValidatedModel{
|
||||
ValidatedModelID: ValidatedModelID,
|
||||
ValidatedModelVersion: ValidatedModelVersion,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeChangeValidatedModel,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionSubmitted invokes actionSubmissionSubmitted operation.
|
||||
//
|
||||
// Role Validator changes status from Submitting -> Submitted.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-submitted
|
||||
func (svc *Service) ActionSubmissionSubmitted(ctx context.Context, params internal.ActionSubmissionSubmittedParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusSubmitted
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("asset_version", params.ModelVersion)
|
||||
smap.Add("display_name", params.DisplayName)
|
||||
smap.Add("creator", params.Creator)
|
||||
smap.Add("game_id", params.GameID)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionRequestChanges implements actionSubmissionRequestChanges operation.
|
||||
//
|
||||
// (Internal endpoint) Role Validator changes status from Submitting -> RequestChanges.
|
||||
//
|
||||
// POST /submissions/{SubmissionID}/status/validator-request-changes
|
||||
func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params internal.ActionSubmissionRequestChangesParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusChangesRequested
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusSubmitting}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionValidate invokes actionSubmissionValidate operation.
|
||||
@@ -49,9 +188,36 @@ func (svc *Service) UpdateSubmissionValidatedModel(ctx context.Context, params i
|
||||
// POST /submissions/{SubmissionID}/status/validator-validated
|
||||
func (svc *Service) ActionSubmissionValidated(ctx context.Context, params internal.ActionSubmissionValidatedParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusValidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusValidated)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionAccepted implements actionSubmissionAccepted operation.
|
||||
@@ -61,10 +227,62 @@ func (svc *Service) ActionSubmissionValidated(ctx context.Context, params intern
|
||||
// POST /submissions/{SubmissionID}/status/validator-failed
|
||||
func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params internal.ActionSubmissionAcceptedParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusAcceptedUnvalidated
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusAccepted)
|
||||
smap.Add("status_message", params.StatusMessage)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
smap.Add("status_id", target_status)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusValidating}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
//push an error audit event
|
||||
{
|
||||
event_data := model.AuditEventDataError{
|
||||
Error: params.ErrorMessage,
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeError,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// push an action audit event
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActionSubmissionUploaded implements actionSubmissionUploaded operation.
|
||||
@@ -74,14 +292,55 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna
|
||||
// POST /submissions/{SubmissionID}/status/validator-uploaded
|
||||
func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params internal.ActionSubmissionUploadedParams) error {
|
||||
// transaction
|
||||
target_status := model.SubmissionStatusUploaded
|
||||
smap := datastore.Optional()
|
||||
smap.Add("status_id", model.SubmissionStatusUploaded)
|
||||
smap.Add("status_id", target_status)
|
||||
smap.Add("uploaded_asset_id", params.UploadedAssetID)
|
||||
return svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
|
||||
err := svc.DB.Submissions().IfStatusThenUpdate(ctx, params.SubmissionID, []model.SubmissionStatus{model.SubmissionStatusUploading}, smap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
event_data := model.AuditEventDataAction{
|
||||
TargetStatus: uint32(target_status),
|
||||
}
|
||||
|
||||
EventData, err := json.Marshal(event_data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = svc.DB.AuditEvents().Create(ctx, model.AuditEvent{
|
||||
ID: 0,
|
||||
User: ValidtorUserID,
|
||||
ResourceType: model.ResourceSubmission,
|
||||
ResourceID: params.SubmissionID,
|
||||
EventType: model.AuditEventTypeAction,
|
||||
EventData: EventData,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// POST /submissions
|
||||
func (svc *Service) CreateSubmission(ctx context.Context, request *internal.SubmissionCreate) (*internal.SubmissionID, error) {
|
||||
// sanitization
|
||||
if request.GameID<0||
|
||||
request.AssetOwner<0||
|
||||
request.AssetID<0||
|
||||
request.AssetVersion<0{
|
||||
return nil, ErrNegativeID
|
||||
}
|
||||
var GameID=uint32(request.GameID);
|
||||
var Submitter=uint64(request.AssetOwner);
|
||||
var AssetID=uint64(request.AssetID);
|
||||
var AssetVersion=uint64(request.AssetVersion);
|
||||
var Status=model.SubmissionStatus(request.Status);
|
||||
var roles=service.Roles(request.Roles);
|
||||
|
||||
// Check if an active submission with the same asset id exists
|
||||
{
|
||||
filter := datastore.Optional()
|
||||
@@ -106,8 +365,11 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
|
||||
}
|
||||
|
||||
// check if user owns asset
|
||||
// TODO: allow bypass by admin
|
||||
if operation.Owner != request.AssetOwner {
|
||||
is_submitter := operation.Owner == Submitter
|
||||
// check if user is map admin
|
||||
has_submission_review := roles & service.RolesSubmissionReview == service.RolesSubmissionReview
|
||||
// if neither, u not allowed
|
||||
if !is_submitter && !has_submission_review {
|
||||
return nil, ErrNotAssetOwner
|
||||
}
|
||||
|
||||
@@ -115,12 +377,12 @@ func (svc *Service) CreateSubmission(ctx context.Context, request *internal.Subm
|
||||
ID: 0,
|
||||
DisplayName: request.DisplayName,
|
||||
Creator: request.Creator,
|
||||
GameID: request.GameID,
|
||||
Submitter: request.AssetOwner,
|
||||
AssetID: request.AssetID,
|
||||
AssetVersion: request.AssetVersion,
|
||||
GameID: GameID,
|
||||
Submitter: Submitter,
|
||||
AssetID: AssetID,
|
||||
AssetVersion: AssetVersion,
|
||||
Completed: false,
|
||||
StatusID: model.SubmissionStatusUnderConstruction,
|
||||
StatusID: Status,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
submissions-api = { path = "api", features = ["internal"], default-features = false, registry = "strafesnet" }
|
||||
async-nats = "0.40.0"
|
||||
futures = "0.3.31"
|
||||
rbx_asset = { version = "0.3.3", registry = "strafesnet" }
|
||||
rbx_asset = { version = "0.4.4-pre2", registry = "strafesnet" }
|
||||
rbx_binary = { version = "0.7.4", registry = "strafesnet"}
|
||||
rbx_dom_weak = { version = "2.9.0", registry = "strafesnet"}
|
||||
rbx_reflection_database = { version = "0.2.12", registry = "strafesnet"}
|
||||
@@ -16,3 +16,5 @@ serde = { version = "1.0.215", features = ["derive"] }
|
||||
serde_json = "1.0.133"
|
||||
siphasher = "1.0.1"
|
||||
tokio = { version = "1.41.1", features = ["macros", "rt-multi-thread", "signal"] }
|
||||
heck = "0.5.0"
|
||||
lazy-regex = "3.4.1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Using the `rust-musl-builder` as base image, instead of
|
||||
# the official Rust toolchain
|
||||
FROM docker.io/clux/muslrust:stable AS chef
|
||||
FROM registry.itzana.me/docker-proxy/clux/muslrust:1.86.0-stable AS chef
|
||||
USER root
|
||||
RUN cargo install cargo-chef
|
||||
WORKDIR /app
|
||||
@@ -17,7 +17,7 @@ RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path r
|
||||
COPY . .
|
||||
RUN cargo build --release --target x86_64-unknown-linux-musl --bin maps-validation
|
||||
|
||||
FROM docker.io/alpine:latest AS runtime
|
||||
FROM registry.itzana.me/docker-proxy/alpine:3.21 AS runtime
|
||||
RUN addgroup -S myuser && adduser -S myuser -G myuser
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/maps-validation /usr/local/bin/
|
||||
USER myuser
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "submissions-api"
|
||||
version = "0.6.1"
|
||||
version = "0.7.0"
|
||||
edition = "2021"
|
||||
publish = ["strafesnet"]
|
||||
repository = "https://git.itzana.me/StrafesNET/maps-service"
|
||||
|
||||
@@ -22,7 +22,7 @@ macro_rules! query_pairs{
|
||||
macro_rules! action{
|
||||
($system:expr,$fname:ident,$config:ident,$config_type:ident,$action:expr,$config_submission_id:expr,$(($param:expr,$value:expr))*)=>{
|
||||
pub async fn $fname(&self,$config:$config_type)->Result<(),Error>{
|
||||
let url_raw=format!(concat!("{}/",$system,"/{}/status/",$action),self.0.base_url,$config_submission_id);
|
||||
let url_raw=format!(concat!("{}/",$system,"/{}/",$action),self.0.base_url,$config_submission_id);
|
||||
let url=query_pairs!(reqwest::Url::parse(url_raw.as_str()).map_err(Error::Parse)?,$(($param,$value))*);
|
||||
|
||||
response_ok(
|
||||
@@ -162,16 +162,25 @@ impl Context{
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
// simple submission endpoints
|
||||
action!("submissions",action_submission_validated,config,SubmissionID,"validator-validated",config.0,);
|
||||
action!("submissions",action_submission_request_changes,config,ActionSubmissionRequestChangesRequest,"status/validator-request-changes",config.SubmissionID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
action!("submissions",action_submission_submitted,config,ActionSubmissionSubmittedRequest,"status/validator-submitted",config.SubmissionID,
|
||||
("ModelVersion",config.ModelVersion.to_string().as_str())
|
||||
("DisplayName",config.DisplayName.as_str())
|
||||
("Creator",config.Creator.as_str())
|
||||
("GameID",config.GameID.to_string().as_str())
|
||||
);
|
||||
action!("submissions",action_submission_validated,config,SubmissionID,"status/validator-validated",config.0,);
|
||||
action!("submissions",update_submission_validated_model,config,UpdateSubmissionModelRequest,"validated-model",config.SubmissionID,
|
||||
("ValidatedModelID",config.ModelID.to_string().as_str())
|
||||
("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
|
||||
);
|
||||
action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"validator-uploaded",config.SubmissionID,
|
||||
action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"status/validator-uploaded",config.SubmissionID,
|
||||
("UploadedAssetID",config.UploadedAssetID.to_string().as_str())
|
||||
);
|
||||
action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"validator-failed",config.SubmissionID,
|
||||
("StatusMessage",config.StatusMessage.as_str())
|
||||
action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"status/validator-failed",config.SubmissionID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
pub async fn create_mapfix<'a>(&self,config:CreateMapfixRequest<'a>)->Result<MapfixIDResponse,Error>{
|
||||
let url_raw=format!("{}/mapfixes",self.0.base_url);
|
||||
@@ -185,17 +194,26 @@ impl Context{
|
||||
.json().await.map_err(Error::ReqwestJson)
|
||||
}
|
||||
// simple mapfixes endpoints
|
||||
action!("mapfixes",action_mapfix_validated,config,MapfixID,"validator-validated",config.0,);
|
||||
action!("mapfixes",action_mapfix_request_changes,config,ActionMapfixRequestChangesRequest,"status/validator-request-changes",config.MapfixID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
action!("mapfixes",action_mapfix_submitted,config,ActionMapfixSubmittedRequest,"status/validator-submitted",config.MapfixID,
|
||||
("ModelVersion",config.ModelVersion.to_string().as_str())
|
||||
("DisplayName",config.DisplayName.as_str())
|
||||
("Creator",config.Creator.as_str())
|
||||
("GameID",config.GameID.to_string().as_str())
|
||||
);
|
||||
action!("mapfixes",action_mapfix_validated,config,MapfixID,"status/validator-validated",config.0,);
|
||||
action!("mapfixes",update_mapfix_validated_model,config,UpdateMapfixModelRequest,"validated-model",config.MapfixID,
|
||||
("ValidatedModelID",config.ModelID.to_string().as_str())
|
||||
("ValidatedModelVersion",config.ModelVersion.to_string().as_str())
|
||||
);
|
||||
action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"validator-uploaded",config.MapfixID,);
|
||||
action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"validator-failed",config.MapfixID,
|
||||
("StatusMessage",config.StatusMessage.as_str())
|
||||
action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"status/validator-uploaded",config.MapfixID,);
|
||||
action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"status/validator-failed",config.MapfixID,
|
||||
("ErrorMessage",config.ErrorMessage.as_str())
|
||||
);
|
||||
// simple operation endpoint
|
||||
action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"operation-failed",config.OperationID,
|
||||
action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"status/operation-failed",config.OperationID,
|
||||
("StatusMessage",config.StatusMessage.as_str())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,6 +73,7 @@ pub struct CreateMapfixRequest<'a>{
|
||||
pub AssetID:u64,
|
||||
pub AssetVersion:u64,
|
||||
pub TargetAssetID:u64,
|
||||
pub Description:&'a str,
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug,serde::Deserialize)]
|
||||
@@ -90,6 +91,8 @@ pub struct CreateSubmissionRequest<'a>{
|
||||
pub GameID:i32,
|
||||
pub AssetID:u64,
|
||||
pub AssetVersion:u64,
|
||||
pub Status:u32,
|
||||
pub Roles:u32,
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug,serde::Deserialize)]
|
||||
@@ -222,6 +225,23 @@ pub struct UpdateSubmissionModelRequest{
|
||||
pub ModelVersion:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionSubmittedRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ModelVersion:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionRequestChangesRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionUploadedRequest{
|
||||
@@ -233,7 +253,7 @@ pub struct ActionSubmissionUploadedRequest{
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionSubmissionAcceptedRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub StatusMessage:String,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,serde::Deserialize)]
|
||||
@@ -247,6 +267,23 @@ pub struct UpdateMapfixModelRequest{
|
||||
pub ModelVersion:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixSubmittedRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ModelVersion:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixRequestChangesRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixUploadedRequest{
|
||||
@@ -257,7 +294,7 @@ pub struct ActionMapfixUploadedRequest{
|
||||
#[derive(Clone,Debug)]
|
||||
pub struct ActionMapfixAcceptedRequest{
|
||||
pub MapfixID:i64,
|
||||
pub StatusMessage:String,
|
||||
pub ErrorMessage:String,
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,serde::Deserialize)]
|
||||
|
||||
645
validation/src/check.rs
Normal file
645
validation/src/check.rs
Normal file
@@ -0,0 +1,645 @@
|
||||
use std::collections::{HashSet,HashMap};
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{class_is_a,get_mapinfo,get_root_instance,read_dom,ReadDomError,GameID,ParseGameIDError,MapInfo,GetRootInstanceError,StringValueError};
|
||||
|
||||
use heck::{ToSnakeCase,ToTitleCase};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
ModelInfoDownload(rbx_asset::cloud::GetError),
|
||||
CreatorTypeMustBeUser,
|
||||
Download(crate::download::Error),
|
||||
ModelFileDecode(ReadDomError),
|
||||
GetRootInstance(GetRootInstanceError),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct CheckRequest{
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
impl From<crate::nats_types::CheckMapfixRequest> for CheckRequest{
|
||||
fn from(value:crate::nats_types::CheckMapfixRequest)->Self{
|
||||
Self{
|
||||
ModelID:value.ModelID,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<crate::nats_types::CheckSubmissionRequest> for CheckRequest{
|
||||
fn from(value:crate::nats_types::CheckSubmissionRequest)->Self{
|
||||
Self{
|
||||
ModelID:value.ModelID,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct ModeID(u64);
|
||||
impl ModeID{
|
||||
const MAIN:Self=Self(0);
|
||||
const BONUS:Self=Self(1);
|
||||
}
|
||||
enum Zone{
|
||||
Start(ModeID),
|
||||
Finish(ModeID),
|
||||
Anticheat(ModeID),
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
pub enum IDParseError{
|
||||
NoCaptures,
|
||||
ParseInt(core::num::ParseIntError)
|
||||
}
|
||||
impl std::str::FromStr for Zone{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
match s{
|
||||
"MapStart"=>Ok(Self::Start(ModeID::MAIN)),
|
||||
"MapFinish"=>Ok(Self::Finish(ModeID::MAIN)),
|
||||
"MapAnticheat"=>Ok(Self::Anticheat(ModeID::MAIN)),
|
||||
"BonusStart"=>Ok(Self::Start(ModeID::BONUS)),
|
||||
"BonusFinish"=>Ok(Self::Finish(ModeID::BONUS)),
|
||||
"BonusAnticheat"=>Ok(Self::Anticheat(ModeID::BONUS)),
|
||||
other=>{
|
||||
let bonus_start_pattern=lazy_regex::lazy_regex!(r"^Bonus(\d+)Start$|^BonusStart(\d+)$");
|
||||
if let Some(captures)=bonus_start_pattern.captures(other){
|
||||
return Ok(Self::Start(ModeID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^Bonus(\d+)Finish$|^BonusFinish(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(other){
|
||||
return Ok(Self::Finish(ModeID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^Bonus(\d+)Anticheat$|^BonusAnticheat(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(other){
|
||||
return Ok(Self::Anticheat(ModeID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct SpawnID(u64);
|
||||
impl SpawnID{
|
||||
const FIRST:Self=Self(1);
|
||||
}
|
||||
enum SpawnTeleport{
|
||||
Teleport(SpawnID),
|
||||
Spawn(SpawnID),
|
||||
}
|
||||
impl std::str::FromStr for SpawnTeleport{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
// Trigger ForceTrigger Teleport ForceTeleport SpawnAt ForceSpawnAt
|
||||
let bonus_start_pattern=lazy_regex::lazy_regex!(r"^(?:Force)?(Teleport|SpawnAt|Trigger)(\d+)$");
|
||||
if let Some(captures)=bonus_start_pattern.captures(s){
|
||||
return Ok(Self::Teleport(SpawnID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
// Spawn
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^Spawn(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(s){
|
||||
return Ok(Self::Spawn(SpawnID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq)]
|
||||
struct WormholeID(u64);
|
||||
enum Wormhole{
|
||||
In(WormholeID),
|
||||
Out(WormholeID),
|
||||
}
|
||||
impl std::str::FromStr for Wormhole{
|
||||
type Err=IDParseError;
|
||||
fn from_str(s:&str)->Result<Self,Self::Err>{
|
||||
let bonus_start_pattern=lazy_regex::lazy_regex!(r"^WormholeIn(\d+)$");
|
||||
if let Some(captures)=bonus_start_pattern.captures(s){
|
||||
return Ok(Self::In(WormholeID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
let bonus_finish_pattern=lazy_regex::lazy_regex!(r"^WormholeOut(\d+)$");
|
||||
if let Some(captures)=bonus_finish_pattern.captures(s){
|
||||
return Ok(Self::Out(WormholeID(captures[1].parse().map_err(IDParseError::ParseInt)?)));
|
||||
}
|
||||
Err(IDParseError::NoCaptures)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Counts<'a>{
|
||||
mode_start_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
mode_finish_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
mode_anticheat_counts:HashMap<ModeID,Vec<&'a str>>,
|
||||
teleport_counts:HashMap<SpawnID,Vec<&'a str>>,
|
||||
spawn_counts:HashMap<SpawnID,u64>,
|
||||
wormhole_in_counts:HashMap<WormholeID,u64>,
|
||||
wormhole_out_counts:HashMap<WormholeID,u64>,
|
||||
}
|
||||
|
||||
pub struct ModelInfo<'a>{
|
||||
model_class:&'a str,
|
||||
model_name:&'a str,
|
||||
map_info:MapInfo<'a>,
|
||||
counts:Counts<'a>,
|
||||
}
|
||||
|
||||
pub fn get_model_info<'a>(dom:&'a rbx_dom_weak::WeakDom,model_instance:&'a rbx_dom_weak::Instance)->ModelInfo<'a>{
|
||||
// extract model info
|
||||
let map_info=get_mapinfo(&dom,model_instance);
|
||||
|
||||
// count objects (default count is 0)
|
||||
let mut counts=Counts::default();
|
||||
for instance in dom.descendants_of(model_instance.referent()){
|
||||
if class_is_a(instance.class.as_str(),"BasePart"){
|
||||
// Zones
|
||||
match instance.name.parse(){
|
||||
Ok(Zone::Start(mode_id))=>counts.mode_start_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Ok(Zone::Finish(mode_id))=>counts.mode_finish_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Ok(Zone::Anticheat(mode_id))=>counts.mode_anticheat_counts.entry(mode_id).or_default().push(instance.name.as_str()),
|
||||
Err(_)=>(),
|
||||
}
|
||||
// Spawns & Teleports
|
||||
match instance.name.parse(){
|
||||
Ok(SpawnTeleport::Teleport(spawn_id))=>counts.teleport_counts.entry(spawn_id).or_default().push(instance.name.as_str()),
|
||||
Ok(SpawnTeleport::Spawn(spawn_id))=>*counts.spawn_counts.entry(spawn_id).or_insert(0)+=1,
|
||||
Err(_)=>(),
|
||||
}
|
||||
// Wormholes
|
||||
match instance.name.parse(){
|
||||
Ok(Wormhole::In(wormhole_id))=>*counts.wormhole_in_counts.entry(wormhole_id).or_insert(0)+=1,
|
||||
Ok(Wormhole::Out(wormhole_id))=>*counts.wormhole_out_counts.entry(wormhole_id).or_insert(0)+=1,
|
||||
Err(_)=>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ModelInfo{
|
||||
model_class:model_instance.class.as_str(),
|
||||
model_name:model_instance.name.as_str(),
|
||||
map_info,
|
||||
counts,
|
||||
}
|
||||
}
|
||||
|
||||
// check if an observed string matches an expected string
|
||||
pub struct StringCheck<'a,T,Str>(Result<T,StringCheckContext<'a,Str>>);
|
||||
pub struct StringCheckContext<'a,Str>{
|
||||
observed:&'a str,
|
||||
expected:Str,
|
||||
}
|
||||
impl<'a,Str> StringCheckContext<'a,Str>
|
||||
where
|
||||
&'a str:PartialEq<Str>,
|
||||
{
|
||||
fn check<T>(self,value:T)->StringCheck<'a,T,Str>{
|
||||
if self.observed==self.expected{
|
||||
StringCheck(Ok(value))
|
||||
}else{
|
||||
StringCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a,Str:std::fmt::Display> std::fmt::Display for StringCheckContext<'a,Str>{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"expected: {}, observed: {}",self.expected,self.observed)
|
||||
}
|
||||
}
|
||||
|
||||
// check if a string is empty
|
||||
pub struct StringEmpty;
|
||||
impl std::fmt::Display for StringEmpty{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"Empty string")
|
||||
}
|
||||
}
|
||||
fn check_empty(value:&str)->Result<&str,StringEmpty>{
|
||||
(!value.is_empty()).then_some(value).ok_or(StringEmpty)
|
||||
}
|
||||
|
||||
// check for duplicate objects
|
||||
pub struct DuplicateCheckContext<ID,T>(HashMap<ID,T>);
|
||||
pub struct DuplicateCheck<ID,T>(Result<(),DuplicateCheckContext<ID,T>>);
|
||||
impl<ID,T> DuplicateCheckContext<ID,T>{
|
||||
fn check(self,f:impl Fn(&T)->bool)->DuplicateCheck<ID,T>{
|
||||
let Self(mut set)=self;
|
||||
// remove correct entries
|
||||
set.retain(|_,c|f(c));
|
||||
// if any entries remain, they are incorrect
|
||||
if set.is_empty(){
|
||||
DuplicateCheck(Ok(()))
|
||||
}else{
|
||||
DuplicateCheck(Err(Self(set)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that there is at least one matching item for each item in a reference set, and no extra items
|
||||
pub struct SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
extra:HashMap<ID,T>,
|
||||
}
|
||||
pub struct SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
extra:HashMap<ID,T>,
|
||||
missing:HashSet<ID>,
|
||||
}
|
||||
pub struct SetDifferenceCheck<Context>(Result<(),Context>);
|
||||
impl<ID,T> SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
fn new(initial_set:HashMap<ID,T>)->Self{
|
||||
Self{
|
||||
extra:initial_set,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID:Eq+std::hash::Hash,T> SetDifferenceCheckContextAllowNone<ID,T>{
|
||||
fn check<U>(mut self,reference_set:&HashMap<ID,U>)->SetDifferenceCheck<Self>{
|
||||
// remove correct entries
|
||||
for (id,_) in reference_set{
|
||||
self.extra.remove(id);
|
||||
}
|
||||
// if any entries remain, they are incorrect
|
||||
if self.extra.is_empty(){
|
||||
SetDifferenceCheck(Ok(()))
|
||||
}else{
|
||||
SetDifferenceCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID,T> SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
fn new(initial_set:HashMap<ID,T>)->Self{
|
||||
Self{
|
||||
extra:initial_set,
|
||||
missing:HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<ID:Copy+Eq+std::hash::Hash,T> SetDifferenceCheckContextAtLeastOne<ID,T>{
|
||||
fn check<U>(mut self,reference_set:&HashMap<ID,U>)->SetDifferenceCheck<Self>{
|
||||
// remove correct entries
|
||||
for (id,_) in reference_set{
|
||||
if self.extra.remove(id).is_none(){
|
||||
// the set did not contain a required item. This is a fail
|
||||
self.missing.insert(*id);
|
||||
}
|
||||
}
|
||||
// if any entries remain, they are incorrect
|
||||
if self.extra.is_empty()&&self.missing.is_empty(){
|
||||
SetDifferenceCheck(Ok(()))
|
||||
}else{
|
||||
SetDifferenceCheck(Err(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapInfoOwned{
|
||||
pub display_name:String,
|
||||
pub creator:String,
|
||||
pub game_id:GameID,
|
||||
}
|
||||
|
||||
// crazy!
|
||||
pub struct MapCheck<'a>{
|
||||
// === METADATA CHECKS ===
|
||||
// The root must be of class Model
|
||||
model_class:StringCheck<'a,(),&'static str>,
|
||||
// Model's name must be in snake case
|
||||
model_name:StringCheck<'a,(),String>,
|
||||
// Map must have a StringValue named DisplayName.
|
||||
// Value must not be empty, must be in title case.
|
||||
display_name:Result<Result<StringCheck<'a,&'a str,String>,StringEmpty>,StringValueError>,
|
||||
// Map must have a StringValue named Creator.
|
||||
// Value must not be empty.
|
||||
creator:Result<Result<&'a str,StringEmpty>,StringValueError>,
|
||||
// The prefix of the model's name must match the game it was submitted for.
|
||||
// bhop_ for bhop, and surf_ for surf
|
||||
game_id:Result<GameID,ParseGameIDError>,
|
||||
|
||||
// === MODE CHECKS ===
|
||||
// MapStart must exist
|
||||
mapstart:Result<(),()>,
|
||||
// No duplicate map starts (including bonuses)
|
||||
mode_start_counts:DuplicateCheck<ModeID,Vec<&'a str>>,
|
||||
// At least one finish zone for each start zone, and no finishes with no start
|
||||
mode_finish_counts:SetDifferenceCheck<SetDifferenceCheckContextAtLeastOne<ModeID,Vec<&'a str>>>,
|
||||
// Check for dangling MapAnticheat zones (no associated MapStart)
|
||||
mode_anticheat_counts:SetDifferenceCheck<SetDifferenceCheckContextAllowNone<ModeID,Vec<&'a str>>>,
|
||||
// Spawn1 must exist
|
||||
spawn1:Result<(),()>,
|
||||
// Check for dangling Teleport# (no associated Spawn#)
|
||||
teleport_counts:SetDifferenceCheck<SetDifferenceCheckContextAllowNone<SpawnID,Vec<&'a str>>>,
|
||||
// No duplicate Spawn#
|
||||
spawn_counts:DuplicateCheck<SpawnID,u64>,
|
||||
// Check for dangling WormholeIn# (no associated WormholeOut#)
|
||||
wormhole_in_counts:SetDifferenceCheck<SetDifferenceCheckContextAtLeastOne<WormholeID,u64>>,
|
||||
// No duplicate WormholeOut# (duplicate WormholeIn# ok)
|
||||
// No dangling WormholeOut#
|
||||
wormhole_out_counts:DuplicateCheck<WormholeID,u64>,
|
||||
}
|
||||
|
||||
impl<'a> ModelInfo<'a>{
|
||||
fn check(self)->MapCheck<'a>{
|
||||
// Check class is exactly "Model"
|
||||
let model_class=StringCheckContext{
|
||||
observed:self.model_class,
|
||||
expected:"Model",
|
||||
}.check(());
|
||||
|
||||
// Check model name is snake case
|
||||
let model_name=StringCheckContext{
|
||||
observed:self.model_name,
|
||||
expected:self.model_name.to_snake_case(),
|
||||
}.check(());
|
||||
|
||||
// Check display name is not empty and has title case
|
||||
let display_name=self.map_info.display_name.map(|display_name|{
|
||||
check_empty(display_name).map(|display_name|StringCheckContext{
|
||||
observed:display_name,
|
||||
expected:display_name.to_title_case(),
|
||||
}.check(display_name))
|
||||
});
|
||||
|
||||
// Check Creator is not empty
|
||||
let creator=self.map_info.creator.map(check_empty);
|
||||
|
||||
// Check GameID (model name was prefixed with bhop_ surf_ etc)
|
||||
let game_id=self.map_info.game_id;
|
||||
|
||||
// MapStart must exist
|
||||
let mapstart=if self.counts.mode_start_counts.get(&ModeID::MAIN).is_some(){
|
||||
Ok(())
|
||||
}else{
|
||||
Err(())
|
||||
};
|
||||
|
||||
// Spawn1 must exist
|
||||
let spawn1=if self.counts.spawn_counts.get(&SpawnID::FIRST).is_some(){
|
||||
Ok(())
|
||||
}else{
|
||||
Err(())
|
||||
};
|
||||
|
||||
// Check that at least one finish zone exists for each start zone.
|
||||
// This also checks that there are no finish zones without a corresponding start zone.
|
||||
let mode_finish_counts=SetDifferenceCheckContextAtLeastOne::new(self.counts.mode_finish_counts)
|
||||
.check(&self.counts.mode_start_counts);
|
||||
|
||||
// Check that there are no anticheat zones without a corresponding start zone.
|
||||
// Modes are allowed to have 0 anticheat zones.
|
||||
let mode_anticheat_counts=SetDifferenceCheckContextAllowNone::new(self.counts.mode_anticheat_counts)
|
||||
.check(&self.counts.mode_start_counts);
|
||||
|
||||
// There must be exactly one start zone for every mode in the map.
|
||||
let mode_start_counts=DuplicateCheckContext(self.counts.mode_start_counts).check(|c|1<c.len());
|
||||
|
||||
// Check that there are no Teleports without a corresponding Spawn.
|
||||
// Spawns are allowed to have 0 Teleports.
|
||||
let teleport_counts=SetDifferenceCheckContextAllowNone::new(self.counts.teleport_counts)
|
||||
.check(&self.counts.spawn_counts);
|
||||
|
||||
// There must be exactly one of any perticular spawn id in the map.
|
||||
let spawn_counts=DuplicateCheckContext(self.counts.spawn_counts).check(|&c|1<c);
|
||||
|
||||
// Check that at least one WormholeIn exists for each WormholeOut.
|
||||
// This also checks that there are no WormholeIn without a corresponding WormholeOut.
|
||||
let wormhole_in_counts=SetDifferenceCheckContextAtLeastOne::new(self.counts.wormhole_in_counts)
|
||||
.check(&self.counts.wormhole_out_counts);
|
||||
|
||||
// There must be exactly one of any perticular wormhole out id in the map.
|
||||
let wormhole_out_counts=DuplicateCheckContext(self.counts.wormhole_out_counts).check(|&c|1<c);
|
||||
|
||||
MapCheck{
|
||||
model_class,
|
||||
model_name,
|
||||
display_name,
|
||||
creator,
|
||||
game_id,
|
||||
mapstart,
|
||||
mode_start_counts,
|
||||
mode_finish_counts,
|
||||
mode_anticheat_counts,
|
||||
spawn1,
|
||||
teleport_counts,
|
||||
spawn_counts,
|
||||
wormhole_in_counts,
|
||||
wormhole_out_counts,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MapCheck<'a>{
|
||||
fn pass(self)->Result<MapInfoOwned,Self>{
|
||||
match self{
|
||||
MapCheck{
|
||||
model_class:StringCheck(Ok(())),
|
||||
model_name:StringCheck(Ok(())),
|
||||
display_name:Ok(Ok(StringCheck(Ok(display_name)))),
|
||||
creator:Ok(Ok(creator)),
|
||||
game_id:Ok(game_id),
|
||||
mapstart:Ok(()),
|
||||
mode_start_counts:DuplicateCheck(Ok(())),
|
||||
mode_finish_counts:SetDifferenceCheck(Ok(())),
|
||||
mode_anticheat_counts:SetDifferenceCheck(Ok(())),
|
||||
spawn1:Ok(()),
|
||||
teleport_counts:SetDifferenceCheck(Ok(())),
|
||||
spawn_counts:DuplicateCheck(Ok(())),
|
||||
wormhole_in_counts:SetDifferenceCheck(Ok(())),
|
||||
wormhole_out_counts:DuplicateCheck(Ok(())),
|
||||
}=>{
|
||||
Ok(MapInfoOwned{
|
||||
display_name:display_name.to_owned(),
|
||||
creator:creator.to_owned(),
|
||||
game_id,
|
||||
})
|
||||
},
|
||||
other=>Err(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_comma_separated<T>(
|
||||
f:&mut std::fmt::Formatter<'_>,
|
||||
mut it:impl Iterator<Item=T>,
|
||||
custom_write:impl Fn(&mut std::fmt::Formatter<'_>,T)->std::fmt::Result
|
||||
)->std::fmt::Result{
|
||||
if let Some(t)=it.next(){
|
||||
custom_write(f,t)?;
|
||||
for t in it{
|
||||
write!(f,", ")?;
|
||||
custom_write(f,t)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
macro_rules! write_zone{
|
||||
($f:expr,$mode:expr,$zone:expr)=>{
|
||||
match $mode{
|
||||
ModeID(0)=>write!($f,concat!("Map",$zone)),
|
||||
ModeID(1)=>write!($f,concat!("Bonus",$zone)),
|
||||
ModeID(other)=>write!($f,concat!("Bonus{}",$zone),other),
|
||||
}
|
||||
};
|
||||
}
|
||||
impl<'a> std::fmt::Display for MapCheck<'a>{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
if let StringCheck(Err(context))=&self.model_class{
|
||||
writeln!(f,"Invalid model class: {context}")?;
|
||||
}
|
||||
if let StringCheck(Err(context))=&self.model_name{
|
||||
writeln!(f,"Model name must have snake_case: {context}")?;
|
||||
}
|
||||
match &self.display_name{
|
||||
Ok(Ok(StringCheck(Ok(_))))=>(),
|
||||
Ok(Ok(StringCheck(Err(context))))=>writeln!(f,"DisplayName must have Title Case: {context}")?,
|
||||
Ok(Err(context))=>writeln!(f,"Invalid DisplayName: {context}")?,
|
||||
Err(StringValueError::ObjectNotFound)=>writeln!(f,"Missing DisplayName StringValue")?,
|
||||
Err(StringValueError::ValueNotSet)=>writeln!(f,"DisplayName Value not set")?,
|
||||
Err(StringValueError::NonStringValue)=>writeln!(f,"DisplayName Value is not a String")?,
|
||||
}
|
||||
match &self.creator{
|
||||
Ok(Ok(_))=>(),
|
||||
Ok(Err(context))=>writeln!(f,"Invalid Creator: {context}")?,
|
||||
Err(StringValueError::ObjectNotFound)=>writeln!(f,"Missing Creator StringValue")?,
|
||||
Err(StringValueError::ValueNotSet)=>writeln!(f,"Creator Value not set")?,
|
||||
Err(StringValueError::NonStringValue)=>writeln!(f,"Creator Value is not a String")?,
|
||||
}
|
||||
if let Err(_parse_game_id_error)=&self.game_id{
|
||||
writeln!(f,"Model name must be prefixed with bhop_ surf_ or flytrials_")?;
|
||||
}
|
||||
if let Err(())=&self.mapstart{
|
||||
writeln!(f,"Model has no MapStart")?;
|
||||
}
|
||||
if let DuplicateCheck(Err(DuplicateCheckContext(context)))=&self.mode_start_counts{
|
||||
write!(f,"Duplicate start zones: ")?;
|
||||
write_comma_separated(f,context.iter(),|f,(mode_id,names)|{
|
||||
write_zone!(f,mode_id,"Start")?;
|
||||
write!(f," ({} duplicates)",names.len())?;
|
||||
Ok(())
|
||||
})?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
if let SetDifferenceCheck(Err(context))=&self.mode_finish_counts{
|
||||
if !context.extra.is_empty(){
|
||||
let plural=if context.extra.len()==1{"zone"}else{"zones"};
|
||||
write!(f,"No matching start zone for finish {plural}: ")?;
|
||||
write_comma_separated(f,context.extra.iter(),|f,(mode_id,_names)|
|
||||
write_zone!(f,mode_id,"Finish")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
if !context.missing.is_empty(){
|
||||
let plural=if context.missing.len()==1{"zone"}else{"zones"};
|
||||
write!(f,"Missing finish {plural}: ")?;
|
||||
write_comma_separated(f,context.missing.iter(),|f,mode_id|
|
||||
write_zone!(f,mode_id,"Finish")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
}
|
||||
if let SetDifferenceCheck(Err(context))=&self.mode_anticheat_counts{
|
||||
if !context.extra.is_empty(){
|
||||
let plural=if context.extra.len()==1{"zone"}else{"zones"};
|
||||
write!(f,"No matching start zone for anticheat {plural}: ")?;
|
||||
write_comma_separated(f,context.extra.iter(),|f,(mode_id,_names)|
|
||||
write_zone!(f,mode_id,"Anticheat")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
}
|
||||
if let Err(())=&self.spawn1{
|
||||
writeln!(f,"Model has no Spawn1")?;
|
||||
}
|
||||
if let SetDifferenceCheck(Err(context))=&self.teleport_counts{
|
||||
for (_,names) in &context.extra{
|
||||
let plural=if names.len()==1{"object"}else{"objects"};
|
||||
write!(f,"No matching Spawn for {plural}: ")?;
|
||||
write_comma_separated(f,names.iter(),|f,&name|{
|
||||
write!(f,"{name}")
|
||||
})?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
}
|
||||
if let DuplicateCheck(Err(DuplicateCheckContext(context)))=&self.spawn_counts{
|
||||
write!(f,"Duplicate Spawn: ")?;
|
||||
write_comma_separated(f,context.iter(),|f,(SpawnID(spawn_id),count)|
|
||||
write!(f,"Spawn{spawn_id} ({count} duplicates)")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
if let SetDifferenceCheck(Err(context))=&self.wormhole_in_counts{
|
||||
if !context.extra.is_empty(){
|
||||
write!(f,"WormholeIn with no matching WormholeOut: ")?;
|
||||
write_comma_separated(f,context.extra.iter(),|f,(WormholeID(wormhole_id),_count)|
|
||||
write!(f,"WormholeIn{wormhole_id}")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
if !context.missing.is_empty(){
|
||||
// This counts WormholeIn objects, but
|
||||
// flipped logic is easier to understand
|
||||
write!(f,"WormholeOut with no matching WormholeIn: ")?;
|
||||
write_comma_separated(f,context.missing.iter(),|f,WormholeID(wormhole_id)|
|
||||
write!(f,"WormholeOut{wormhole_id}")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
}
|
||||
if let DuplicateCheck(Err(DuplicateCheckContext(context)))=&self.wormhole_out_counts{
|
||||
write!(f,"Duplicate WormholeOut: ")?;
|
||||
write_comma_separated(f,context.iter(),|f,(WormholeID(wormhole_id),count)|
|
||||
write!(f,"WormholeOut{wormhole_id} ({count} duplicates)")
|
||||
)?;
|
||||
writeln!(f,"")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CheckReportAndVersion{
|
||||
pub status:Result<MapInfoOwned,String>,
|
||||
pub version:u64,
|
||||
}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_inner(&self,check_info:CheckRequest)->Result<CheckReportAndVersion,Error>{
|
||||
// discover asset creator and latest version
|
||||
let info=self.cloud_context.get_asset_info(
|
||||
rbx_asset::cloud::GetAssetLatestRequest{asset_id:check_info.ModelID}
|
||||
).await.map_err(Error::ModelInfoDownload)?;
|
||||
|
||||
// reject models created by a group
|
||||
let rbx_asset::cloud::Creator::userId(_user_id)=info.creationContext.creator else{
|
||||
return Err(Error::CreatorTypeMustBeUser);
|
||||
};
|
||||
|
||||
// parse model version string
|
||||
let version=info.revisionId;
|
||||
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:check_info.ModelID,
|
||||
version,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
// extract the root instance
|
||||
let model_instance=get_root_instance(&dom).map_err(Error::GetRootInstance)?;
|
||||
|
||||
// extract information from the model
|
||||
let model_info=get_model_info(&dom,model_instance);
|
||||
|
||||
// convert the model information into a structured report
|
||||
let map_check=model_info.check();
|
||||
|
||||
// check the report, generate an error message if it fails the check
|
||||
let status=map_check.pass().map_err(|e|e.to_string());
|
||||
|
||||
Ok(CheckReportAndVersion{status,version})
|
||||
}
|
||||
}
|
||||
52
validation/src/check_mapfix.rs
Normal file
52
validation/src/check_mapfix.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
use crate::check::CheckReportAndVersion;
|
||||
use crate::nats_types::CheckMapfixRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Check(crate::check::Error),
|
||||
ApiActionMapfixCheck(submissions_api::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_mapfix(&self,check_info:CheckMapfixRequest)->Result<(),Error>{
|
||||
let mapfix_id=check_info.MapfixID;
|
||||
let check_result=self.check_inner(check_info.into()).await;
|
||||
|
||||
// update the mapfix depending on the result
|
||||
match check_result{
|
||||
Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_mapfix_submitted(
|
||||
submissions_api::types::ActionMapfixSubmittedRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ModelVersion:version,
|
||||
DisplayName:map_info.display_name,
|
||||
Creator:map_info.creator,
|
||||
GameID:map_info.game_id as u32,
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?,
|
||||
// update the mapfix model status to request changes
|
||||
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_mapfix_request_changes(
|
||||
submissions_api::types::ActionMapfixRequestChangesRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ErrorMessage:report,
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?,
|
||||
// TODO: report the error
|
||||
// update the mapfix model status to request changes
|
||||
Err(e)=>self.api.action_mapfix_request_changes(
|
||||
submissions_api::types::ActionMapfixRequestChangesRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
}
|
||||
).await.map_err(Error::ApiActionMapfixCheck)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
53
validation/src/check_submission.rs
Normal file
53
validation/src/check_submission.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use crate::check::CheckReportAndVersion;
|
||||
use crate::nats_types::CheckSubmissionRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Check(crate::check::Error),
|
||||
ApiActionSubmissionCheck(submissions_api::Error),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn check_submission(&self,check_info:CheckSubmissionRequest)->Result<(),Error>{
|
||||
let submission_id=check_info.SubmissionID;
|
||||
let check_result=self.check_inner(check_info.into()).await;
|
||||
|
||||
// update the submission depending on the result
|
||||
match check_result{
|
||||
// update the submission model status to submitted
|
||||
Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_submission_submitted(
|
||||
submissions_api::types::ActionSubmissionSubmittedRequest{
|
||||
SubmissionID:submission_id,
|
||||
ModelVersion:version,
|
||||
DisplayName:map_info.display_name,
|
||||
Creator:map_info.creator,
|
||||
GameID:map_info.game_id as u32,
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?,
|
||||
// update the submission model status to request changes
|
||||
Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_submission_request_changes(
|
||||
submissions_api::types::ActionSubmissionRequestChangesRequest{
|
||||
SubmissionID:submission_id,
|
||||
ErrorMessage:report,
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?,
|
||||
// TODO: report the error
|
||||
// update the submission model status to request changes
|
||||
Err(e)=>self.api.action_submission_request_changes(
|
||||
submissions_api::types::ActionSubmissionRequestChangesRequest{
|
||||
SubmissionID:submission_id,
|
||||
ErrorMessage:e.to_string(),
|
||||
}
|
||||
).await.map_err(Error::ApiActionSubmissionCheck)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,14 @@
|
||||
use crate::rbx_util::{get_mapinfo,read_dom,MapInfo,ReadDomError,GetMapInfoError,ParseGameIDError};
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{get_root_instance,get_mapinfo,read_dom,MapInfo,ReadDomError,GetRootInstanceError,GameID};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
ModelVersionsPage(rbx_asset::cookie::PageError),
|
||||
EmptyVersionsPage,
|
||||
CreatorTypeMustBeUser(rbx_asset::cookie::CreatorType),
|
||||
ModelDetails(rbx_asset::cookie::GetError),
|
||||
ModelInfoDownload(rbx_asset::cookie::GetAssetV2Error),
|
||||
ModelFileDownload(rbx_asset::cookie::GetError),
|
||||
NoLocations,
|
||||
CreatorTypeMustBeUser,
|
||||
ModelInfoDownload(rbx_asset::cloud::GetError),
|
||||
Download(crate::download::Error),
|
||||
ModelFileDecode(ReadDomError),
|
||||
GetMapInfo(GetMapInfoError),
|
||||
ParseGameID(ParseGameIDError),
|
||||
GetRootInstance(GetRootInstanceError),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
@@ -27,57 +23,50 @@ pub struct CreateRequest{
|
||||
}
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct CreateResult{
|
||||
pub AssetOwner:i64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:i32,
|
||||
pub AssetOwner:u64,
|
||||
pub DisplayName:Option<String>,
|
||||
pub Creator:Option<String>,
|
||||
pub GameID:Option<GameID>,
|
||||
pub AssetVersion:u64,
|
||||
}
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn create_inner(&self,create_info:CreateRequest)->Result<CreateResult,Error>{
|
||||
// discover asset creator
|
||||
let creator_fut=async{
|
||||
self.cookie_context.get_asset_details(
|
||||
rbx_asset::cookie::GetAssetDetailsRequest{asset_id:create_info.ModelID}
|
||||
).await.map_err(Error::ModelDetails)
|
||||
// discover asset creator and latest version
|
||||
let info=self.cloud_context.get_asset_info(
|
||||
rbx_asset::cloud::GetAssetLatestRequest{asset_id:create_info.ModelID}
|
||||
).await.map_err(Error::ModelInfoDownload)?;
|
||||
|
||||
// reject models created by a group
|
||||
let rbx_asset::cloud::Creator::userId(user_id)=info.creationContext.creator else{
|
||||
return Err(Error::CreatorTypeMustBeUser);
|
||||
};
|
||||
|
||||
let asset_version=info.revisionId;
|
||||
|
||||
// download the map model
|
||||
let asset_fut=async{
|
||||
let asset_info=self.cookie_context.get_asset_v2(rbx_asset::cookie::GetAssetRequest{
|
||||
asset_id:create_info.ModelID,
|
||||
version:None,
|
||||
}).await.map_err(Error::ModelInfoDownload)?;
|
||||
|
||||
let location=asset_info.info.locations.first().ok_or(Error::NoLocations)?;
|
||||
let data=self.cookie_context.get_asset_v2_download(location).await.map_err(Error::ModelFileDownload)?;
|
||||
|
||||
Ok((asset_info.version,data))
|
||||
};
|
||||
|
||||
let (details,(asset_version,model_data))=tokio::try_join!(creator_fut,asset_fut)?;
|
||||
|
||||
if details.Creator.CreatorType!=rbx_asset::cookie::CreatorType::User{
|
||||
return Err(Error::CreatorTypeMustBeUser(details.Creator.CreatorType));
|
||||
}
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:create_info.ModelID,
|
||||
version:asset_version,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let dom=read_dom(&mut std::io::Cursor::new(model_data)).map_err(Error::ModelFileDecode)?;
|
||||
let dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
// extract the root instance
|
||||
let model_instance=get_root_instance(&dom).map_err(Error::GetRootInstance)?;
|
||||
|
||||
// parse create fields out of asset
|
||||
let MapInfo{
|
||||
display_name,
|
||||
creator,
|
||||
game_id,
|
||||
}=get_mapinfo(&dom).map_err(Error::GetMapInfo)?;
|
||||
|
||||
let game_id=game_id.map_err(Error::ParseGameID)?;
|
||||
}=get_mapinfo(&dom,model_instance);
|
||||
|
||||
Ok(CreateResult{
|
||||
AssetOwner:details.Creator.Id as i64,
|
||||
DisplayName:display_name.unwrap_or_default().to_owned(),
|
||||
Creator:creator.unwrap_or_default().to_owned(),
|
||||
GameID:game_id as i32,
|
||||
AssetOwner:user_id,
|
||||
DisplayName:display_name.ok().map(ToOwned::to_owned),
|
||||
Creator:creator.ok().map(ToOwned::to_owned),
|
||||
GameID:game_id.ok(),
|
||||
AssetVersion:asset_version,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -24,13 +24,15 @@ impl crate::message_handler::MessageHandler{
|
||||
// call create on api
|
||||
self.api.create_mapfix(submissions_api::types::CreateMapfixRequest{
|
||||
OperationID:create_info.OperationID,
|
||||
AssetOwner:create_request.AssetOwner,
|
||||
DisplayName:create_request.DisplayName.as_str(),
|
||||
Creator:create_request.Creator.as_str(),
|
||||
GameID:create_request.GameID,
|
||||
AssetOwner:create_request.AssetOwner as i64,
|
||||
DisplayName:create_request.DisplayName.as_deref().unwrap_or_default(),
|
||||
Creator:create_request.Creator.as_deref().unwrap_or_default(),
|
||||
// not great TODO: make this great
|
||||
GameID:create_request.GameID.unwrap_or(crate::rbx_util::GameID::Bhop) as i32,
|
||||
AssetID:create_info.ModelID,
|
||||
AssetVersion:create_request.AssetVersion,
|
||||
TargetAssetID:create_info.TargetAssetID,
|
||||
Description:create_info.Description.as_str(),
|
||||
}).await.map_err(Error::ApiActionMapfixCreate)?;
|
||||
|
||||
Ok(())
|
||||
@@ -43,7 +45,7 @@ impl crate::message_handler::MessageHandler{
|
||||
if let Err(e)=create_result{
|
||||
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
|
||||
OperationID:operation_id,
|
||||
StatusMessage:format!("{e}"),
|
||||
StatusMessage:e.to_string(),
|
||||
}).await?;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::nats_types::CreateSubmissionRequest;
|
||||
use crate::create::CreateRequest;
|
||||
use crate::rbx_util::GameID;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
@@ -19,15 +20,33 @@ impl crate::message_handler::MessageHandler{
|
||||
let create_request=self.create_inner(CreateRequest{
|
||||
ModelID:create_info.ModelID,
|
||||
}).await.map_err(Error::Create)?;
|
||||
|
||||
// grab values from submission form, otherwise try to fill blanks from map data
|
||||
let display_name=if create_info.DisplayName.is_empty(){
|
||||
create_request.DisplayName.as_deref().unwrap_or_default()
|
||||
}else{
|
||||
create_info.DisplayName.as_str()
|
||||
};
|
||||
|
||||
let creator=if create_info.Creator.is_empty(){
|
||||
create_request.Creator.as_deref().unwrap_or_default()
|
||||
}else{
|
||||
create_info.Creator.as_str()
|
||||
};
|
||||
|
||||
let game_id=create_info.GameID.try_into().ok().or(create_request.GameID).unwrap_or(GameID::Bhop);
|
||||
|
||||
// call create on api
|
||||
self.api.create_submission(submissions_api::types::CreateSubmissionRequest{
|
||||
OperationID:create_info.OperationID,
|
||||
AssetOwner:create_request.AssetOwner,
|
||||
DisplayName:create_request.DisplayName.as_str(),
|
||||
Creator:create_request.Creator.as_str(),
|
||||
GameID:create_request.GameID,
|
||||
AssetOwner:create_request.AssetOwner as i64,
|
||||
DisplayName:display_name,
|
||||
Creator:creator,
|
||||
GameID:game_id as i32,
|
||||
AssetID:create_info.ModelID,
|
||||
AssetVersion:create_request.AssetVersion,
|
||||
Status:create_info.Status,
|
||||
Roles:create_info.Roles,
|
||||
}).await.map_err(Error::ApiActionSubmissionCreate)?;
|
||||
|
||||
Ok(())
|
||||
@@ -40,7 +59,7 @@ impl crate::message_handler::MessageHandler{
|
||||
if let Err(e)=create_result{
|
||||
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
|
||||
OperationID:operation_id,
|
||||
StatusMessage:format!("{e}"),
|
||||
StatusMessage:e.to_string(),
|
||||
}).await?;
|
||||
}
|
||||
|
||||
|
||||
26
validation/src/download.rs
Normal file
26
validation/src/download.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
ModelLocationDownload(rbx_asset::cloud::GetError),
|
||||
NonFreeModel,
|
||||
ModelFileDownload(rbx_asset::cloud::GetError),
|
||||
}
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
pub async fn download_asset_version(cloud_context:&rbx_asset::cloud::Context,request:rbx_asset::cloud::GetAssetVersionRequest)->Result<rbx_asset::types::MaybeGzippedBytes,Error>{
|
||||
// download the location of the map model
|
||||
let location=cloud_context.get_asset_version_location(request).await.map_err(Error::ModelLocationDownload)?;
|
||||
|
||||
// if the location does not exist, you are not allowed to download it
|
||||
let location=location.location.ok_or(Error::NonFreeModel)?;
|
||||
|
||||
// download the map model
|
||||
let maybe_gzip=cloud_context.get_asset(&location).await.map_err(Error::ModelFileDownload)?;
|
||||
|
||||
Ok(maybe_gzip)
|
||||
}
|
||||
@@ -4,6 +4,10 @@ mod rbx_util;
|
||||
mod message_handler;
|
||||
mod nats_types;
|
||||
mod types;
|
||||
mod download;
|
||||
mod check;
|
||||
mod check_mapfix;
|
||||
mod check_submission;
|
||||
mod create;
|
||||
mod create_mapfix;
|
||||
mod create_submission;
|
||||
@@ -20,6 +24,7 @@ pub enum StartupError{
|
||||
NatsConnect(async_nats::ConnectError),
|
||||
NatsGetStream(async_nats::jetstream::context::GetStreamError),
|
||||
NatsConsumer(async_nats::jetstream::stream::ConsumerError),
|
||||
NatsConsumerUpdate(async_nats::jetstream::stream::ConsumerUpdateError),
|
||||
NatsStream(async_nats::jetstream::consumer::StreamError),
|
||||
}
|
||||
impl std::fmt::Display for StartupError{
|
||||
@@ -41,9 +46,12 @@ async fn main()->Result<(),StartupError>{
|
||||
Err(e)=>Err(e).expect("ROBLOX_GROUP_ID env required"),
|
||||
};
|
||||
|
||||
// talk to roblox through STRAFESNET_CI2 account
|
||||
// create / upload models through STRAFESNET_CI2 account
|
||||
let cookie=std::env::var("RBXCOOKIE").expect("RBXCOOKIE env required");
|
||||
let cookie_context=rbx_asset::cookie::CookieContext::new(rbx_asset::cookie::Cookie::new(cookie));
|
||||
let cookie_context=rbx_asset::cookie::Context::new(rbx_asset::cookie::Cookie::new(cookie));
|
||||
// download models through cloud api
|
||||
let api_key=std::env::var("RBX_API_KEY").expect("RBX_API_KEY env required");
|
||||
let cloud_context=rbx_asset::cloud::Context::new(rbx_asset::cloud::ApiKey::new(api_key));
|
||||
|
||||
// maps-service api
|
||||
let api_host_internal=std::env::var("API_HOST_INTERNAL").expect("API_HOST_INTERNAL env required");
|
||||
@@ -52,20 +60,35 @@ async fn main()->Result<(),StartupError>{
|
||||
// nats
|
||||
let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required");
|
||||
let nats_fut=async{
|
||||
const STREAM_NAME:&str="maptest";
|
||||
const DURABLE_NAME:&str="validation";
|
||||
const FILTER_SUBJECT:&str="maptest.>";
|
||||
|
||||
let nats_config=async_nats::jetstream::consumer::pull::Config{
|
||||
name:Some(DURABLE_NAME.to_owned()),
|
||||
durable_name:Some(DURABLE_NAME.to_owned()),
|
||||
filter_subject:FILTER_SUBJECT.to_owned(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let nasty=async_nats::connect(nats_host).await.map_err(StartupError::NatsConnect)?;
|
||||
|
||||
// use nats jetstream
|
||||
async_nats::jetstream::new(nasty)
|
||||
.get_stream("maptest").await.map_err(StartupError::NatsGetStream)?
|
||||
.get_or_create_consumer("validation",async_nats::jetstream::consumer::pull::Config{
|
||||
name:Some("validation".to_owned()),
|
||||
durable_name:Some("validation".to_owned()),
|
||||
filter_subject:"maptest.>".to_owned(),
|
||||
..Default::default()
|
||||
}).await.map_err(StartupError::NatsConsumer)?
|
||||
.messages().await.map_err(StartupError::NatsStream)
|
||||
let stream=async_nats::jetstream::new(nasty)
|
||||
.get_stream(STREAM_NAME).await.map_err(StartupError::NatsGetStream)?;
|
||||
|
||||
let consumer=stream.get_or_create_consumer(DURABLE_NAME,nats_config.clone()).await.map_err(StartupError::NatsConsumer)?;
|
||||
|
||||
// check if config matches expected config
|
||||
if consumer.cached_info().config.filter_subject!=FILTER_SUBJECT{
|
||||
stream.update_consumer(nats_config).await.map_err(StartupError::NatsConsumerUpdate)?;
|
||||
}
|
||||
|
||||
// only need messages
|
||||
consumer.messages().await.map_err(StartupError::NatsStream)
|
||||
};
|
||||
|
||||
let message_handler=message_handler::MessageHandler::new(cookie_context,group_id,api);
|
||||
let message_handler=message_handler::MessageHandler::new(cloud_context,cookie_context,group_id,api);
|
||||
|
||||
// Create a signal listener for SIGTERM
|
||||
let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener");
|
||||
|
||||
@@ -7,6 +7,8 @@ pub enum HandleMessageError{
|
||||
UnknownSubject(String),
|
||||
CreateMapfix(submissions_api::Error),
|
||||
CreateSubmission(submissions_api::Error),
|
||||
CheckMapfix(crate::check_mapfix::Error),
|
||||
CheckSubmission(crate::check_submission::Error),
|
||||
UploadMapfix(crate::upload_mapfix::Error),
|
||||
UploadSubmission(crate::upload_submission::Error),
|
||||
ValidateMapfix(crate::validate_mapfix::Error),
|
||||
@@ -26,18 +28,21 @@ fn from_slice<'a,T:serde::de::Deserialize<'a>>(slice:&'a [u8])->Result<T,HandleM
|
||||
}
|
||||
|
||||
pub struct MessageHandler{
|
||||
pub(crate) cookie_context:rbx_asset::cookie::CookieContext,
|
||||
pub(crate) cloud_context:rbx_asset::cloud::Context,
|
||||
pub(crate) cookie_context:rbx_asset::cookie::Context,
|
||||
pub(crate) group_id:Option<u64>,
|
||||
pub(crate) api:submissions_api::internal::Context,
|
||||
}
|
||||
|
||||
impl MessageHandler{
|
||||
pub fn new(
|
||||
cookie_context:rbx_asset::cookie::CookieContext,
|
||||
cloud_context:rbx_asset::cloud::Context,
|
||||
cookie_context:rbx_asset::cookie::Context,
|
||||
group_id:Option<u64>,
|
||||
api:submissions_api::internal::Context,
|
||||
)->Self{
|
||||
Self{
|
||||
cloud_context,
|
||||
cookie_context,
|
||||
group_id,
|
||||
api,
|
||||
@@ -49,6 +54,8 @@ impl MessageHandler{
|
||||
match message.subject.as_str(){
|
||||
"maptest.mapfixes.create"=>self.create_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::CreateMapfix),
|
||||
"maptest.submissions.create"=>self.create_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::CreateSubmission),
|
||||
"maptest.mapfixes.check"=>self.check_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::CheckMapfix),
|
||||
"maptest.submissions.check"=>self.check_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::CheckSubmission),
|
||||
"maptest.mapfixes.upload"=>self.upload_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadMapfix),
|
||||
"maptest.submissions.upload"=>self.upload_submission(from_slice(&message.payload)?).await.map_err(HandleMessageError::UploadSubmission),
|
||||
"maptest.mapfixes.validate"=>self.validate_mapfix(from_slice(&message.payload)?).await.map_err(HandleMessageError::ValidateMapfix),
|
||||
|
||||
@@ -10,6 +10,12 @@ pub struct CreateSubmissionRequest{
|
||||
// operation_id is passed back in the response message
|
||||
pub OperationID:i32,
|
||||
pub ModelID:u64,
|
||||
pub DisplayName:String,
|
||||
pub Creator:String,
|
||||
pub GameID:u32,
|
||||
// initial status is passed back on create
|
||||
pub Status:u32,
|
||||
pub Roles:u32,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
@@ -18,6 +24,21 @@ pub struct CreateMapfixRequest{
|
||||
pub OperationID:i32,
|
||||
pub ModelID:u64,
|
||||
pub TargetAssetID:u64,
|
||||
pub Description:String,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CheckSubmissionRequest{
|
||||
pub SubmissionID:i64,
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct CheckMapfixRequest{
|
||||
pub MapfixID:i64,
|
||||
pub ModelID:u64,
|
||||
}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
|
||||
@@ -5,8 +5,7 @@ pub enum ReadDomError{
|
||||
Binary(rbx_binary::DecodeError),
|
||||
Xml(rbx_xml::DecodeError),
|
||||
Read(std::io::Error),
|
||||
Seek(std::io::Error),
|
||||
UnknownFormat([u8;8]),
|
||||
UnknownFormat(Vec<u8>),
|
||||
}
|
||||
impl std::fmt::Display for ReadDomError{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
@@ -15,19 +14,13 @@ impl std::fmt::Display for ReadDomError{
|
||||
}
|
||||
impl std::error::Error for ReadDomError{}
|
||||
|
||||
pub fn read_dom<R:std::io::Read+std::io::Seek>(input:&mut R)->Result<rbx_dom_weak::WeakDom,ReadDomError>{
|
||||
let mut first_8=[0u8;8];
|
||||
std::io::Read::read_exact(input,&mut first_8).map_err(ReadDomError::Read)?;
|
||||
std::io::Seek::rewind(input).map_err(ReadDomError::Seek)?;
|
||||
match &first_8[0..4]{
|
||||
b"<rob"=>{
|
||||
match &first_8[4..8]{
|
||||
b"lox!"=>rbx_binary::from_reader(input).map_err(ReadDomError::Binary),
|
||||
b"lox "=>rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()).map_err(ReadDomError::Xml),
|
||||
_=>Err(ReadDomError::UnknownFormat(first_8)),
|
||||
}
|
||||
},
|
||||
_=>Err(ReadDomError::UnknownFormat(first_8)),
|
||||
pub fn read_dom<R:std::io::Read>(input:R)->Result<rbx_dom_weak::WeakDom,ReadDomError>{
|
||||
let mut buf=std::io::BufReader::new(input);
|
||||
let peek=std::io::BufRead::fill_buf(&mut buf).map_err(ReadDomError::Read)?;
|
||||
match peek.get(0..8){
|
||||
Some(b"<roblox!")=>rbx_binary::from_reader(buf).map_err(ReadDomError::Binary),
|
||||
Some(b"<roblox ")=>rbx_xml::from_reader_default(buf).map_err(ReadDomError::Xml),
|
||||
_=>Err(ReadDomError::UnknownFormat(peek.to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +70,18 @@ impl std::str::FromStr for GameID{
|
||||
return Err(ParseGameIDError);
|
||||
}
|
||||
}
|
||||
pub struct GameIDError;
|
||||
impl TryFrom<u32> for GameID{
|
||||
type Error=GameIDError;
|
||||
fn try_from(value:u32)->Result<Self,Self::Error>{
|
||||
match value{
|
||||
1=>Ok(GameID::Bhop),
|
||||
2=>Ok(GameID::Surf),
|
||||
5=>Ok(GameID::FlyTrials),
|
||||
_=>Err(GameIDError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MapInfo<'a>{
|
||||
pub display_name:Result<&'a str,StringValueError>,
|
||||
@@ -84,6 +89,7 @@ pub struct MapInfo<'a>{
|
||||
pub game_id:Result<GameID,ParseGameIDError>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StringValueError{
|
||||
ObjectNotFound,
|
||||
ValueNotSet,
|
||||
@@ -100,20 +106,24 @@ fn string_value(instance:Option<&rbx_dom_weak::Instance>)->Result<&str,StringVal
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GetMapInfoError{
|
||||
pub enum GetRootInstanceError{
|
||||
ModelFileRootMustHaveOneChild,
|
||||
ModelFileChildRefIsNil,
|
||||
}
|
||||
|
||||
pub fn get_mapinfo(dom:&rbx_dom_weak::WeakDom)->Result<MapInfo,GetMapInfoError>{
|
||||
pub fn get_root_instance(dom:&rbx_dom_weak::WeakDom)->Result<&rbx_dom_weak::Instance,GetRootInstanceError>{
|
||||
let &[map_ref]=dom.root().children()else{
|
||||
return Err(GetMapInfoError::ModelFileRootMustHaveOneChild);
|
||||
return Err(GetRootInstanceError::ModelFileRootMustHaveOneChild);
|
||||
};
|
||||
let model_instance=dom.get_by_ref(map_ref).ok_or(GetMapInfoError::ModelFileChildRefIsNil)?;
|
||||
let model_instance=dom.get_by_ref(map_ref).ok_or(GetRootInstanceError::ModelFileChildRefIsNil)?;
|
||||
|
||||
Ok(MapInfo{
|
||||
Ok(model_instance)
|
||||
}
|
||||
|
||||
pub fn get_mapinfo<'a>(dom:&'a rbx_dom_weak::WeakDom,model_instance:&rbx_dom_weak::Instance)->MapInfo<'a>{
|
||||
MapInfo{
|
||||
display_name:string_value(find_first_child_class(dom,model_instance,"DisplayName","StringValue")),
|
||||
creator:string_value(find_first_child_class(dom,model_instance,"Creator","StringValue")),
|
||||
game_id:model_instance.name.parse(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::download::download_asset_version;
|
||||
use crate::nats_types::UploadMapfixRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Get(rbx_asset::cookie::GetError),
|
||||
Download(crate::download::Error),
|
||||
IO(std::io::Error),
|
||||
Json(serde_json::Error),
|
||||
Upload(rbx_asset::cookie::UploadError),
|
||||
ApiActionMapfixUploaded(submissions_api::Error),
|
||||
@@ -17,11 +19,14 @@ impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn upload_mapfix(&self,upload_info:UploadMapfixRequest)->Result<(),Error>{
|
||||
// download the map model version
|
||||
let model_data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:upload_info.ModelID,
|
||||
version:Some(upload_info.ModelVersion),
|
||||
}).await.map_err(Error::Get)?;
|
||||
version:upload_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// transparently handle gzipped models
|
||||
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
|
||||
|
||||
// upload the map to the strafesnet group
|
||||
let _upload_response=self.cookie_context.upload(rbx_asset::cookie::UploadRequest{
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::download::download_asset_version;
|
||||
use crate::nats_types::UploadSubmissionRequest;
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum Error{
|
||||
Get(rbx_asset::cookie::GetError),
|
||||
Download(crate::download::Error),
|
||||
IO(std::io::Error),
|
||||
Json(serde_json::Error),
|
||||
Create(rbx_asset::cookie::CreateError),
|
||||
SystemTime(std::time::SystemTimeError),
|
||||
@@ -18,11 +20,14 @@ impl std::error::Error for Error{}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn upload_submission(&self,upload_info:UploadSubmissionRequest)->Result<(),Error>{
|
||||
// download the map model version
|
||||
let model_data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:upload_info.ModelID,
|
||||
version:Some(upload_info.ModelVersion),
|
||||
}).await.map_err(Error::Get)?;
|
||||
version:upload_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// transparently handle gzipped models
|
||||
let model_data=maybe_gzip.to_vec().map_err(Error::IO)?;
|
||||
|
||||
// upload the map to the strafesnet group
|
||||
let upload_response=self.cookie_context.create(rbx_asset::cookie::CreateRequest{
|
||||
|
||||
@@ -29,7 +29,7 @@ impl crate::message_handler::MessageHandler{
|
||||
// update the mapfix model status to accepted
|
||||
self.api.action_mapfix_accepted(submissions_api::types::ActionMapfixAcceptedRequest{
|
||||
MapfixID:mapfix_id,
|
||||
StatusMessage:format!("{e}"),
|
||||
ErrorMessage:e.to_string(),
|
||||
}).await.map_err(Error::ApiActionMapfixValidate)?;
|
||||
},
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ impl crate::message_handler::MessageHandler{
|
||||
// update the submission model status to accepted
|
||||
self.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{
|
||||
SubmissionID:submission_id,
|
||||
StatusMessage:format!("{e}"),
|
||||
ErrorMessage:e.to_string(),
|
||||
}).await.map_err(Error::ApiActionSubmissionValidate)?;
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use futures::TryStreamExt;
|
||||
use submissions_api::types::ResourceType;
|
||||
|
||||
use crate::download::download_asset_version;
|
||||
use crate::rbx_util::{class_is_a,read_dom,ReadDomError};
|
||||
use crate::types::ResourceID;
|
||||
|
||||
@@ -32,11 +33,11 @@ fn hash_source(source:&str)->String{
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub enum ValidateError{
|
||||
pub enum Error{
|
||||
ScriptFlaggedIllegalKeyword(String),
|
||||
ScriptBlocked(Option<submissions_api::types::ScriptID>),
|
||||
ScriptNotYetReviewed(Option<submissions_api::types::ScriptID>),
|
||||
ModelFileDownload(rbx_asset::cookie::GetError),
|
||||
Download(crate::download::Error),
|
||||
ModelFileDecode(ReadDomError),
|
||||
ApiGetScriptPolicyFromHash(submissions_api::types::SingleItemError),
|
||||
ApiGetScript(submissions_api::Error),
|
||||
@@ -51,12 +52,12 @@ pub enum ValidateError{
|
||||
AssetUpload(rbx_asset::cookie::UploadError),
|
||||
AssetCreate(rbx_asset::cookie::CreateError),
|
||||
}
|
||||
impl std::fmt::Display for ValidateError{
|
||||
impl std::fmt::Display for Error{
|
||||
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
|
||||
write!(f,"{self:?}")
|
||||
}
|
||||
}
|
||||
impl std::error::Error for ValidateError{}
|
||||
impl std::error::Error for Error{}
|
||||
|
||||
#[allow(nonstandard_style)]
|
||||
pub struct ValidateRequest{
|
||||
@@ -88,15 +89,15 @@ impl From<crate::nats_types::ValidateSubmissionRequest> for ValidateRequest{
|
||||
}
|
||||
|
||||
impl crate::message_handler::MessageHandler{
|
||||
pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),ValidateError>{
|
||||
// download map
|
||||
let data=self.cookie_context.get_asset(rbx_asset::cookie::GetAssetRequest{
|
||||
pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),Error>{
|
||||
// download the map model
|
||||
let maybe_gzip=download_asset_version(&self.cloud_context,rbx_asset::cloud::GetAssetVersionRequest{
|
||||
asset_id:validate_info.ModelID,
|
||||
version:Some(validate_info.ModelVersion),
|
||||
}).await.map_err(ValidateError::ModelFileDownload)?;
|
||||
version:validate_info.ModelVersion,
|
||||
}).await.map_err(Error::Download)?;
|
||||
|
||||
// decode dom (slow!)
|
||||
let mut dom=read_dom(&mut std::io::Cursor::new(data)).map_err(ValidateError::ModelFileDecode)?;
|
||||
let mut dom=maybe_gzip.read_with(read_dom,read_dom).map_err(Error::ModelFileDecode)?;
|
||||
|
||||
/* VALIDATE MAP */
|
||||
|
||||
@@ -111,7 +112,7 @@ impl crate::message_handler::MessageHandler{
|
||||
// immediately abort
|
||||
// grab path to offending script
|
||||
let path=get_partial_path(&dom,script);
|
||||
return Err(ValidateError::ScriptFlaggedIllegalKeyword(path));
|
||||
return Err(Error::ScriptFlaggedIllegalKeyword(path));
|
||||
}
|
||||
// associate a name and policy with the source code
|
||||
// policy will be fetched from the database to replace the default policy
|
||||
@@ -132,7 +133,7 @@ impl crate::message_handler::MessageHandler{
|
||||
// fetch the script policy
|
||||
let script_policy=self.api.get_script_policy_from_hash(submissions_api::types::HashRequest{
|
||||
hash:hash.as_str(),
|
||||
}).await.map_err(ValidateError::ApiGetScriptPolicyFromHash)?;
|
||||
}).await.map_err(Error::ApiGetScriptPolicyFromHash)?;
|
||||
|
||||
// write the policy to the script_map, fetching the replacement code if necessary
|
||||
if let Some(script_policy)=script_policy{
|
||||
@@ -144,7 +145,7 @@ impl crate::message_handler::MessageHandler{
|
||||
submissions_api::types::Policy::Replace=>{
|
||||
let script=self.api.get_script(submissions_api::types::GetScriptRequest{
|
||||
ScriptID:script_policy.ToScriptID,
|
||||
}).await.map_err(ValidateError::ApiGetScript)?;
|
||||
}).await.map_err(Error::ApiGetScript)?;
|
||||
Policy::Replace(script.Source)
|
||||
},
|
||||
};
|
||||
@@ -160,14 +161,14 @@ impl crate::message_handler::MessageHandler{
|
||||
Source:source.as_str(),
|
||||
ResourceType:resource_type,
|
||||
ResourceID:Some(resource_id),
|
||||
}).await.map_err(ValidateError::ApiCreateScript)?;
|
||||
}).await.map_err(Error::ApiCreateScript)?;
|
||||
|
||||
// create a None policy (pending review by yours truly)
|
||||
self.api.create_script_policy(submissions_api::types::CreateScriptPolicyRequest{
|
||||
ToScriptID:script.ScriptID,
|
||||
FromScriptID:script.ScriptID,
|
||||
Policy:submissions_api::types::Policy::None,
|
||||
}).await.map_err(ValidateError::ApiCreateScriptPolicy)?;
|
||||
}).await.map_err(Error::ApiCreateScriptPolicy)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -175,7 +176,7 @@ impl crate::message_handler::MessageHandler{
|
||||
.await?;
|
||||
|
||||
// make the replacements
|
||||
let mut modified=true;
|
||||
let mut modified=false;
|
||||
for &script_ref in &script_refs{
|
||||
if let Some(script)=dom.get_by_ref_mut(script_ref){
|
||||
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut("Source"){
|
||||
@@ -184,8 +185,8 @@ impl crate::message_handler::MessageHandler{
|
||||
let hash=hash_source(source.as_str());
|
||||
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
|
||||
hash:hash.as_str(),
|
||||
}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
|
||||
return Err(ValidateError::ScriptBlocked(script.map(|s|s.ID)));
|
||||
}).await.map_err(Error::ApiGetScriptFromHash)?;
|
||||
return Err(Error::ScriptBlocked(script.map(|s|s.ID)));
|
||||
},
|
||||
None
|
||||
|Some(Policy::None)
|
||||
@@ -193,8 +194,8 @@ impl crate::message_handler::MessageHandler{
|
||||
let hash=hash_source(source.as_str());
|
||||
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
|
||||
hash:hash.as_str(),
|
||||
}).await.map_err(ValidateError::ApiGetScriptFromHash)?;
|
||||
return Err(ValidateError::ScriptNotYetReviewed(script.map(|s|s.ID)));
|
||||
}).await.map_err(Error::ApiGetScriptFromHash)?;
|
||||
return Err(Error::ScriptNotYetReviewed(script.map(|s|s.ID)));
|
||||
},
|
||||
Some(Policy::Allowed)=>(),
|
||||
Some(Policy::Delete)=>{
|
||||
@@ -211,19 +212,17 @@ impl crate::message_handler::MessageHandler{
|
||||
}
|
||||
}
|
||||
|
||||
println!("[Validator] Forcing model upload! modified=true");
|
||||
|
||||
// if the model was validated, the submission must be changed to use the modified model
|
||||
if modified{
|
||||
let (validated_model_id,validated_model_version)=if modified{
|
||||
// serialize model (slow!)
|
||||
let mut data=Vec::new();
|
||||
let &[map_ref]=dom.root().children()else{
|
||||
return Err(ValidateError::ModelFileRootMustHaveOneChild);
|
||||
return Err(Error::ModelFileRootMustHaveOneChild);
|
||||
};
|
||||
rbx_binary::to_writer(&mut data,&dom,&[map_ref]).map_err(ValidateError::ModelFileEncode)?;
|
||||
rbx_binary::to_writer(&mut data,&dom,&[map_ref]).map_err(Error::ModelFileEncode)?;
|
||||
|
||||
// upload a model lol
|
||||
let model_id=if let Some(model_id)=validate_info.ValidatedModelID{
|
||||
if let Some(model_id)=validate_info.ValidatedModelID{
|
||||
// upload to existing id
|
||||
let response=self.cookie_context.upload(rbx_asset::cookie::UploadRequest{
|
||||
assetid:model_id,
|
||||
@@ -232,13 +231,13 @@ impl crate::message_handler::MessageHandler{
|
||||
ispublic:None,
|
||||
allowComments:None,
|
||||
groupId:None,
|
||||
},data).await.map_err(ValidateError::AssetUpload)?;
|
||||
},data).await.map_err(Error::AssetUpload)?;
|
||||
|
||||
response.AssetId
|
||||
(response.AssetId,response.AssetVersion)
|
||||
}else{
|
||||
// grab the map instance from the map re
|
||||
// grab the map instance from the map ref
|
||||
let Some(map_instance)=dom.get_by_ref(map_ref)else{
|
||||
return Err(ValidateError::ModelFileChildRefIsNil);
|
||||
return Err(Error::ModelFileChildRefIsNil);
|
||||
};
|
||||
// create new model
|
||||
let response=self.cookie_context.create(rbx_asset::cookie::CreateRequest{
|
||||
@@ -247,29 +246,31 @@ impl crate::message_handler::MessageHandler{
|
||||
ispublic:true,
|
||||
allowComments:true,
|
||||
groupId:None,
|
||||
},data).await.map_err(ValidateError::AssetCreate)?;
|
||||
},data).await.map_err(Error::AssetCreate)?;
|
||||
|
||||
response.AssetId
|
||||
};
|
||||
|
||||
match validate_info.ResourceID{
|
||||
ResourceID::Mapfix(mapfix_id)=>{
|
||||
// update the mapfix to use the validated model
|
||||
self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ModelID:model_id,
|
||||
ModelVersion:1, //TODO
|
||||
}).await.map_err(ValidateError::ApiUpdateMapfixModel)?;
|
||||
},
|
||||
ResourceID::Submission(submission_id)=>{
|
||||
// update the submission to use the validated model
|
||||
self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
|
||||
SubmissionID:submission_id,
|
||||
ModelID:model_id,
|
||||
ModelVersion:1, //TODO
|
||||
}).await.map_err(ValidateError::ApiUpdateSubmissionModel)?;
|
||||
},
|
||||
(response.AssetId,response.AssetVersion)
|
||||
}
|
||||
}else{
|
||||
(validate_info.ModelID,validate_info.ModelVersion)
|
||||
};
|
||||
|
||||
match validate_info.ResourceID{
|
||||
ResourceID::Mapfix(mapfix_id)=>{
|
||||
// update the mapfix to use the validated model
|
||||
self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
|
||||
MapfixID:mapfix_id,
|
||||
ModelID:validated_model_id,
|
||||
ModelVersion:validated_model_version,
|
||||
}).await.map_err(Error::ApiUpdateMapfixModel)?;
|
||||
},
|
||||
ResourceID::Submission(submission_id)=>{
|
||||
// update the submission to use the validated model
|
||||
self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
|
||||
SubmissionID:submission_id,
|
||||
ModelID:validated_model_id,
|
||||
ModelVersion:validated_model_version,
|
||||
}).await.map_err(Error::ApiUpdateSubmissionModel)?;
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM oven/bun:latest
|
||||
FROM registry.itzana.me/docker-proxy/oven/bun:1.2.8
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -10,4 +10,4 @@ ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN bun install
|
||||
RUN bun run build
|
||||
ENTRYPOINT ["bun", "run", "start"]
|
||||
ENTRYPOINT ["bun", "run", "start"]
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
"use client"
|
||||
|
||||
import Link from "next/link"
|
||||
import Image from "next/image";
|
||||
|
||||
import "./styles/header.scss"
|
||||
import { UserInfo } from "@/app/ts/User";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
interface HeaderButton {
|
||||
name: string,
|
||||
@@ -15,6 +20,25 @@ function HeaderButton(header: HeaderButton) {
|
||||
}
|
||||
|
||||
export default function Header() {
|
||||
const handleLoginClick = () => {
|
||||
window.location.href = "/auth/oauth2/login?redirect=" + window.location.href;
|
||||
};
|
||||
|
||||
const [valid, setValid] = useState<boolean>(false)
|
||||
const [user, setUser] = useState<UserInfo | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
async function getLoginInfo() {
|
||||
const [validateData, userData] = await Promise.all([
|
||||
fetch("/api/session/validate").then(validateResponse => validateResponse.json()),
|
||||
fetch("/api/session/user").then(userResponse => userResponse.json())
|
||||
]);
|
||||
setValid(validateData)
|
||||
setUser(userData)
|
||||
}
|
||||
getLoginInfo()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<header className="header-bar">
|
||||
<nav className="left">
|
||||
@@ -24,6 +48,16 @@ export default function Header() {
|
||||
</nav>
|
||||
<nav className="right">
|
||||
<HeaderButton name="Submit" href="/submit"/>
|
||||
{valid && user ? (
|
||||
<div className="author">
|
||||
<Link href="/auth">
|
||||
<Image className="avatar" width={28} height={28} priority={true} src={user.AvatarURL} alt={user.Username}/>
|
||||
<button>{user.Username}</button>
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<button onClick={handleLoginClick}>Login</button>
|
||||
)}
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
|
||||
@@ -12,7 +12,7 @@ interface SubmissionCardProps {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export default function SubmissionCard(props: SubmissionCardProps) {
|
||||
export function SubmissionCard(props: SubmissionCardProps) {
|
||||
return (
|
||||
<Link href={`/submissions/${props.id}`}>
|
||||
<div className="submissionCard">
|
||||
@@ -40,3 +40,32 @@ export default function SubmissionCard(props: SubmissionCardProps) {
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
export function MapfixCard(props: SubmissionCardProps) {
|
||||
return (
|
||||
<Link href={`/mapfixes/${props.id}`}>
|
||||
<div className="MapfixCard">
|
||||
<div className="content">
|
||||
<div className="map-image">
|
||||
{/* TODO: Grab image of model */}
|
||||
<Image width={230} height={230} layout="fixed" priority={true} src={`/thumbnails/asset/${props.assetId}`} alt={props.displayName} />
|
||||
</div>
|
||||
<div className="details">
|
||||
<div className="header">
|
||||
<span className="displayName">{props.displayName}</span>
|
||||
<div className="rating">
|
||||
<Rating value={props.rating} readOnly size="small" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="footer">
|
||||
<div className="author">
|
||||
<Image className="avatar" width={28} height={28} priority={true} src={`/thumbnails/user/${props.authorId}`} alt={props.author}/>
|
||||
<span>{props.author}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,25 +1,8 @@
|
||||
"use client"
|
||||
|
||||
import { redirect } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import Header from "./header";
|
||||
|
||||
async function login_check() {
|
||||
const response = await fetch("/api/session/validate")
|
||||
if (response.ok) {
|
||||
const logged_in = await response.json()
|
||||
if (!logged_in) {
|
||||
redirect("https://auth.staging.strafes.net/oauth2/login?redirect=" + window.location.href)
|
||||
}
|
||||
} else {
|
||||
console.error("No response from /api/session/validate")
|
||||
}
|
||||
}
|
||||
|
||||
export default function Webpage({children}: Readonly<{children?: React.ReactNode}>) {
|
||||
useEffect(() => { login_check() }, [])
|
||||
|
||||
return <>
|
||||
<Header/>
|
||||
{children}
|
||||
|
||||
54
web/src/app/admin-submit/(styles)/page.scss
Normal file
54
web/src/app/admin-submit/(styles)/page.scss
Normal file
@@ -0,0 +1,54 @@
|
||||
@use "../../globals.scss";
|
||||
|
||||
::placeholder {
|
||||
color: var(--placeholder-text)
|
||||
}
|
||||
|
||||
.form-spacer {
|
||||
margin-bottom: 20px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
#target-asset-radio {
|
||||
color: var(--text-color);
|
||||
font-size: globals.$form-label-fontsize;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
width: 850px;
|
||||
|
||||
& label, & input {
|
||||
color: var(--text-color);
|
||||
}
|
||||
& fieldset {
|
||||
border-color: rgb(100,100,100);
|
||||
}
|
||||
& span {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
main {
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-inline: auto;
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
text-align: center;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
gap: 25px;
|
||||
|
||||
fieldset {
|
||||
border: blue
|
||||
}
|
||||
}
|
||||
65
web/src/app/admin-submit/_game.tsx
Normal file
65
web/src/app/admin-submit/_game.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { FormControl, Select, InputLabel, MenuItem } from "@mui/material";
|
||||
import { styled } from '@mui/material/styles';
|
||||
import InputBase from '@mui/material/InputBase';
|
||||
import React from "react";
|
||||
import { SelectChangeEvent } from "@mui/material";
|
||||
|
||||
// TODO: Properly style everything instead of pasting 🤚
|
||||
|
||||
type GameSelectionProps = {
|
||||
game: number;
|
||||
setGame: React.Dispatch<React.SetStateAction<number>>;
|
||||
};
|
||||
|
||||
const BootstrapInput = styled(InputBase)(({ theme }) => ({
|
||||
'label + &': {
|
||||
marginTop: theme.spacing(3),
|
||||
},
|
||||
'& .MuiInputBase-input': {
|
||||
backgroundColor: '#0000',
|
||||
color: '#FFF',
|
||||
border: '1px solid rgba(175, 175, 175, 0.66)',
|
||||
fontSize: 16,
|
||||
padding: '10px 26px 10px 12px',
|
||||
transition: theme.transitions.create(['border-color', 'box-shadow']),
|
||||
fontFamily: [
|
||||
'-apple-system',
|
||||
'BlinkMacSystemFont',
|
||||
'"Segoe UI"',
|
||||
'Roboto',
|
||||
'"Helvetica Neue"',
|
||||
'Arial',
|
||||
'sans-serif',
|
||||
'"Apple Color Emoji"',
|
||||
'"Segoe UI Emoji"',
|
||||
'"Segoe UI Symbol"',
|
||||
].join(','),
|
||||
'&:focus': {
|
||||
borderRadius: 4,
|
||||
borderColor: '#80bdff',
|
||||
boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
export default function GameSelection({ game, setGame }: GameSelectionProps) {
|
||||
const handleChange = (event: SelectChangeEvent) => {
|
||||
setGame(Number(event.target.value)); // TODO: Change later!! there's 100% a proper way of doing this
|
||||
};
|
||||
|
||||
return (
|
||||
<FormControl>
|
||||
<InputLabel sx={{ color: "#646464" }}>Game</InputLabel>
|
||||
<Select
|
||||
value={String(game)}
|
||||
label="Game"
|
||||
onChange={handleChange}
|
||||
input={<BootstrapInput />}
|
||||
>
|
||||
<MenuItem value={1}>Bhop</MenuItem>
|
||||
<MenuItem value={2}>Surf</MenuItem>
|
||||
<MenuItem value={3}>Fly Trials</MenuItem>
|
||||
</Select>
|
||||
</FormControl>
|
||||
);
|
||||
}
|
||||
90
web/src/app/admin-submit/page.tsx
Normal file
90
web/src/app/admin-submit/page.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client"
|
||||
|
||||
import { Button, TextField } from "@mui/material"
|
||||
|
||||
import GameSelection from "./_game";
|
||||
import SendIcon from '@mui/icons-material/Send';
|
||||
import Webpage from "@/app/_components/webpage"
|
||||
import React, { useState } from "react";
|
||||
|
||||
import "./(styles)/page.scss"
|
||||
|
||||
interface SubmissionPayload {
|
||||
AssetID: number;
|
||||
DisplayName: string;
|
||||
Creator: string;
|
||||
GameID: number;
|
||||
}
|
||||
interface IdResponse {
|
||||
OperationID: number;
|
||||
}
|
||||
|
||||
export default function SubmissionInfoPage() {
|
||||
const [game, setGame] = useState(1);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const form = event.currentTarget;
|
||||
const formData = new FormData(form);
|
||||
|
||||
const payload: SubmissionPayload = {
|
||||
DisplayName: (formData.get("display-name") as string) ?? "unknown", // TEMPORARY! TODO: Change
|
||||
Creator: (formData.get("creator") as string) ?? "unknown", // TEMPORARY! TODO: Change
|
||||
GameID: game,
|
||||
AssetID: Number((formData.get("asset-id") as string) ?? "0"),
|
||||
};
|
||||
|
||||
console.log(payload)
|
||||
console.log(JSON.stringify(payload))
|
||||
|
||||
try {
|
||||
// Send the POST request
|
||||
const response = await fetch("/api/submissions-admin", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
// Check if the HTTP request was successful
|
||||
if (!response.ok) {
|
||||
const errorDetails = await response.text();
|
||||
|
||||
// Throw an error with detailed information
|
||||
throw new Error(`HTTP error! status: ${response.status}, details: ${errorDetails}`);
|
||||
}
|
||||
|
||||
// Allow any HTTP status
|
||||
const id_response:IdResponse = await response.json();
|
||||
|
||||
// navigate to newly created submission
|
||||
window.location.assign(`/operations/${id_response.OperationID}`)
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error submitting data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Webpage>
|
||||
<main>
|
||||
<header>
|
||||
<h1>Submit New Map on Behalf of Another User (Admin)</h1>
|
||||
<span className="spacer form-spacer"></span>
|
||||
</header>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<TextField className="form-field" id="asset-id" name="asset-id" label="Asset ID (required)" variant="outlined"/>
|
||||
<TextField className="form-field" id="display-name" name="display-name" label="Display Name" variant="outlined"/>
|
||||
<TextField className="form-field" id="creator" name="creator" label="Creator" variant="outlined"/>
|
||||
<GameSelection game={game} setGame={setGame} />
|
||||
<span className="spacer form-spacer"></span>
|
||||
<Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{
|
||||
width: "400px",
|
||||
height: "50px",
|
||||
marginInline: "auto"
|
||||
}}>Create Submission in ChangesRequested Status (Ready to Force-Submit)</Button>
|
||||
</form>
|
||||
</main>
|
||||
</Webpage>
|
||||
)
|
||||
}
|
||||
@@ -12,7 +12,9 @@ interface CreatorAndReviewStatus {
|
||||
asset_id: MapfixInfo["AssetID"],
|
||||
creator: MapfixInfo["DisplayName"],
|
||||
review: MapfixInfo["StatusID"],
|
||||
status_message: MapfixInfo["StatusMessage"],
|
||||
submitter: MapfixInfo["Submitter"],
|
||||
target_asset_id: MapfixInfo["TargetAssetID"],
|
||||
description: MapfixInfo["Description"],
|
||||
comments: Comment[],
|
||||
name: string
|
||||
}
|
||||
@@ -50,7 +52,7 @@ function LeaveAComment() {
|
||||
)
|
||||
}
|
||||
|
||||
export default function Comments(stats: CommentersProps) {
|
||||
export function Comments(stats: CommentersProps) {
|
||||
return (<>
|
||||
<section className="comments">
|
||||
{stats.comments_data.comments.length===0
|
||||
@@ -64,5 +66,6 @@ export default function Comments(stats: CommentersProps) {
|
||||
}
|
||||
|
||||
export {
|
||||
type CreatorAndReviewStatus
|
||||
type CreatorAndReviewStatus,
|
||||
type Comment,
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { MapfixInfo } from "@/app/ts/Mapfix"
|
||||
|
||||
interface AssetID {
|
||||
id: MapfixInfo["AssetID"]
|
||||
}
|
||||
|
||||
function MapImage() {
|
||||
return <p>Fetching map image...</p>
|
||||
}
|
||||
|
||||
export {
|
||||
type AssetID,
|
||||
MapImage
|
||||
}
|
||||
31
web/src/app/mapfixes/[mapfixId]/_mapImage.tsx
Normal file
31
web/src/app/mapfixes/[mapfixId]/_mapImage.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import Image from "next/image";
|
||||
import { MapfixInfo } from "@/app/ts/Mapfix"
|
||||
|
||||
interface AssetID {
|
||||
id: MapfixInfo["AssetID"]
|
||||
}
|
||||
|
||||
function MapImage({ id }: AssetID) {
|
||||
if (!id) {
|
||||
return <p>Missing asset ID</p>;
|
||||
}
|
||||
|
||||
const imageUrl = `/thumbnails/asset/${id}`;
|
||||
|
||||
return (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="Map Thumbnail"
|
||||
layout="responsive"
|
||||
width={512}
|
||||
height={512}
|
||||
priority={true}
|
||||
className="map-image"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
type AssetID,
|
||||
MapImage
|
||||
}
|
||||
@@ -1,21 +1,39 @@
|
||||
import { Roles, RolesConstants } from "@/app/ts/Roles";
|
||||
import { MapfixStatus } from "@/app/ts/Mapfix";
|
||||
import { Button, ButtonOwnProps } from "@mui/material";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
type Actions = "Completed" | "Submit" | "Reject" | "Revoke"
|
||||
type ApiActions = Lowercase<Actions> | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
|
||||
type Review = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
|
||||
interface ReviewAction {
|
||||
name: string,
|
||||
action: string,
|
||||
}
|
||||
|
||||
const ReviewActions = {
|
||||
Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
|
||||
ResetSubmitting: {name:"Reset Submitting (fix softlocked status)",action:"reset-submitting"} as ReviewAction,
|
||||
Revoke: {name:"Revoke",action:"revoke"} as ReviewAction,
|
||||
Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction,
|
||||
Reject: {name:"Reject",action:"reject"} as ReviewAction,
|
||||
Validate: {name:"Validate",action:"retry-validate"} as ReviewAction,
|
||||
ResetValidating: {name:"Reset Validating (fix softlocked status)",action:"reset-validating"} as ReviewAction,
|
||||
RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction,
|
||||
Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction,
|
||||
ResetUploading: {name:"Reset Uploading (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
|
||||
}
|
||||
|
||||
interface ReviewButton {
|
||||
name: Review,
|
||||
action: ApiActions,
|
||||
action: ReviewAction,
|
||||
mapfixId: string,
|
||||
color: ButtonOwnProps["color"]
|
||||
}
|
||||
|
||||
interface ReviewId {
|
||||
mapfixId: string
|
||||
mapfixId: string,
|
||||
mapfixStatus: number,
|
||||
mapfixSubmitter: number,
|
||||
}
|
||||
|
||||
async function ReviewButtonClicked(action: ApiActions, mapfixId: string) {
|
||||
async function ReviewButtonClicked(action: string, mapfixId: string) {
|
||||
try {
|
||||
const response = await fetch(`/api/mapfixes/${mapfixId}/status/${action}`, {
|
||||
method: "POST",
|
||||
@@ -41,11 +59,10 @@ function ReviewButton(props: ReviewButton) {
|
||||
return <Button
|
||||
color={props.color}
|
||||
variant="contained"
|
||||
onClick={() => { ReviewButtonClicked(props.action, props.mapfixId) }}>{props.name}</Button>
|
||||
onClick={() => { ReviewButtonClicked(props.action.action, props.mapfixId) }}>{props.action.name}</Button>
|
||||
}
|
||||
|
||||
export default function ReviewButtons(props: ReviewId) {
|
||||
const mapfixId = props.mapfixId
|
||||
// When is each button visible?
|
||||
// Multiple buttons can be visible at once.
|
||||
// Action | Role | When Current Status is One of:
|
||||
@@ -59,16 +76,89 @@ export default function ReviewButtons(props: ReviewId) {
|
||||
// RequestChanges | Reviewer | Validated, Accepted, Submitted
|
||||
// Upload | MapAdmin | Validated
|
||||
// ResetUploading | MapAdmin | Uploading
|
||||
const { mapfixId, mapfixStatus } = props;
|
||||
const [user, setUser] = useState<number|null>(null);
|
||||
const [roles, setRoles] = useState<Roles>(RolesConstants.Empty);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const [rolesData, userData] = await Promise.all([
|
||||
fetch("/api/session/roles").then(rolesResponse => rolesResponse.json()),
|
||||
fetch("/api/session/user").then(userResponse => userResponse.json())
|
||||
]);
|
||||
|
||||
setRoles(rolesData.Roles);
|
||||
setUser(userData.UserID);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, [mapfixId]);
|
||||
|
||||
if (loading) return <p>Loading...</p>;
|
||||
|
||||
const visibleButtons: ReviewButton[] = [];
|
||||
|
||||
const is_submitter = user === props.mapfixSubmitter;
|
||||
if (is_submitter) {
|
||||
if ([MapfixStatus.UnderConstruction, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
|
||||
visibleButtons.push({ action: ReviewActions.Submit, color: "info", mapfixId });
|
||||
}
|
||||
if ([MapfixStatus.Submitted, MapfixStatus.ChangesRequested].includes(mapfixStatus!)) {
|
||||
visibleButtons.push({ action: ReviewActions.Revoke, color: "info", mapfixId });
|
||||
}
|
||||
if (mapfixStatus === MapfixStatus.Submitting && mapfix.UpdatedAt<Math.floor(Date.now() / 1000)) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetSubmitting, color: "error", mapfixId });
|
||||
}
|
||||
}
|
||||
|
||||
if (roles&RolesConstants.MapfixReview) {
|
||||
// you can't review your own mapfix!
|
||||
// note that this means there needs to be more than one person with MapfixReview
|
||||
if (!is_submitter && mapfixStatus === MapfixStatus.Submitted) {
|
||||
visibleButtons.push({ action: ReviewActions.Accept, color: "info", mapfixId });
|
||||
visibleButtons.push({ action: ReviewActions.Reject, color: "error", mapfixId });
|
||||
}
|
||||
if (mapfixStatus === MapfixStatus.AcceptedUnvalidated) {
|
||||
visibleButtons.push({ action: ReviewActions.Validate, color: "info", mapfixId });
|
||||
}
|
||||
if (mapfixStatus === MapfixStatus.Validating) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", mapfixId });
|
||||
}
|
||||
// this button serves the same purpose as Revoke if you are both
|
||||
// the map submitter and have MapfixReview when status is Submitted
|
||||
if (
|
||||
[MapfixStatus.Validated, MapfixStatus.AcceptedUnvalidated].includes(mapfixStatus!)
|
||||
|| !is_submitter && mapfixStatus == MapfixStatus.Submitted
|
||||
) {
|
||||
visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", mapfixId });
|
||||
}
|
||||
}
|
||||
|
||||
if (roles&RolesConstants.MapfixUpload) {
|
||||
if (mapfixStatus === MapfixStatus.Validated) {
|
||||
visibleButtons.push({ action: ReviewActions.Upload, color: "info", mapfixId });
|
||||
}
|
||||
if (mapfixStatus === MapfixStatus.Uploading) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", mapfixId });
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="review-set">
|
||||
<ReviewButton color="info" name="Submit" action="submit" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="info" name="Revoke" action="revoke" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="info" name="Accept" action="trigger-validate" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="info" name="Validate" action="retry-validate" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="error" name="Reject" action="reject" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="info" name="Upload" action="trigger-upload" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="error" name="Reset Uploading (fix softlocked status)" action="reset-uploading" mapfixId={mapfixId}/>
|
||||
<ReviewButton color="error" name="Reset Validating (fix softlocked status)" action="reset-validating" mapfixId={mapfixId}/>
|
||||
{visibleButtons.length === 0 ? (
|
||||
<p>No available actions</p>
|
||||
) : (
|
||||
visibleButtons.map((btn) => (
|
||||
<ReviewButton key={btn.action.action} {...btn} />
|
||||
))
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,51 +2,39 @@
|
||||
|
||||
import { MapfixInfo, MapfixStatusToString } from "@/app/ts/Mapfix";
|
||||
import type { CreatorAndReviewStatus } from "./_comments";
|
||||
import { MapImage } from "./_map";
|
||||
import { MapImage } from "./_mapImage";
|
||||
import { useParams } from "next/navigation";
|
||||
import ReviewButtons from "./_reviewButtons";
|
||||
import { Rating } from "@mui/material";
|
||||
import Comments from "./_comments";
|
||||
import { Comments, Comment } from "./_comments";
|
||||
import { AuditEvent, decodeAuditEvent as auditEventMessage } from "@/app/ts/AuditEvent";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
import Window from "./_window";
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
import "./(styles)/page.scss";
|
||||
|
||||
interface ReviewId {
|
||||
mapfixId: string
|
||||
}
|
||||
|
||||
function Ratings() {
|
||||
return (
|
||||
<Window className="rating-window" title="Rating">
|
||||
<section className="rating-type">
|
||||
<aside className="rating-left">
|
||||
<p>Quality</p>
|
||||
<p>Difficulty</p>
|
||||
<p>Fun</p>
|
||||
<p>Length</p>
|
||||
</aside>
|
||||
<aside className="rating-right">
|
||||
<Rating defaultValue={2.5} precision={0.5}/>
|
||||
<Rating defaultValue={2.5} precision={0.5}/>
|
||||
<Rating defaultValue={2.5} precision={0.5}/>
|
||||
<Rating defaultValue={2.5} precision={0.5}/>
|
||||
</aside>
|
||||
</section>
|
||||
</Window>
|
||||
)
|
||||
mapfixId: string,
|
||||
mapfixStatus: number,
|
||||
mapfixSubmitter: number,
|
||||
mapfixAssetId: number,
|
||||
mapfixTargetAssetId: number,
|
||||
}
|
||||
|
||||
function RatingArea(mapfix: ReviewId) {
|
||||
return (
|
||||
<aside className="review-area">
|
||||
<section className="map-image-area">
|
||||
<MapImage/>
|
||||
<div>
|
||||
<p className="this-mapfix">This Mapfix:</p>
|
||||
<MapImage id={mapfix.mapfixAssetId}/>
|
||||
</div>
|
||||
<div>
|
||||
<p className="target-map">Target Map Being Fixed:</p>
|
||||
<MapImage id={mapfix.mapfixTargetAssetId}/>
|
||||
</div>
|
||||
</section>
|
||||
<Ratings/>
|
||||
<ReviewButtons mapfixId={mapfix.mapfixId}/>
|
||||
<ReviewButtons mapfixId={mapfix.mapfixId} mapfixStatus={mapfix.mapfixStatus} mapfixSubmitter={mapfix.mapfixSubmitter}/>
|
||||
</aside>
|
||||
)
|
||||
}
|
||||
@@ -64,8 +52,10 @@ function TitleAndComments(stats: CreatorAndReviewStatus) {
|
||||
</aside>
|
||||
</div>
|
||||
<p className="by-creator">by <Link href="" target="_blank">{stats.creator}</Link></p>
|
||||
<p className="submitter">Submitter {stats.submitter}</p>
|
||||
<p className="asset-id">Model Asset ID {stats.asset_id}</p>
|
||||
<p className="status-message">Validation Error: {stats.status_message}</p>
|
||||
<p className="target-asset-id">Target Asset ID {stats.target_asset_id}</p>
|
||||
<p className="description">Description: {stats.description}</p>
|
||||
<span className="spacer"></span>
|
||||
<Comments comments_data={stats}/>
|
||||
</main>
|
||||
@@ -73,19 +63,42 @@ function TitleAndComments(stats: CreatorAndReviewStatus) {
|
||||
}
|
||||
|
||||
export default function MapfixInfoPage() {
|
||||
const dynamicId = useParams<{mapfixId: string}>()
|
||||
const { mapfixId } = useParams < { mapfixId: string } >()
|
||||
|
||||
const [mapfix, setMapfix] = useState<MapfixInfo | null>(null)
|
||||
const [auditEvents, setAuditEvents] = useState<AuditEvent[]>([])
|
||||
|
||||
useEffect(() => { // needs to be client sided since server doesn't have a session, nextjs got mad at me for exporting an async function: (https://nextjs.org/docs/messages/no-async-client-component)
|
||||
async function getMapfix() {
|
||||
const res = await fetch(`/api/mapfixes/${dynamicId.mapfixId}`)
|
||||
const res = await fetch(`/api/mapfixes/${mapfixId}`)
|
||||
if (res.ok) {
|
||||
setMapfix(await res.json())
|
||||
}
|
||||
}
|
||||
getMapfix()
|
||||
}, [dynamicId.mapfixId])
|
||||
async function getAuditEvents() {
|
||||
const res = await fetch(`/api/mapfixes/${mapfixId}/audit-events?Page=1&Limit=100`)
|
||||
if (res.ok) {
|
||||
setAuditEvents(await res.json())
|
||||
}
|
||||
}
|
||||
getMapfix()
|
||||
getAuditEvents()
|
||||
}, [mapfixId])
|
||||
|
||||
const comments:Comment[] = auditEvents.map((auditEvent) => {
|
||||
let username = auditEvent.Username;
|
||||
if (auditEvent.User == 9223372036854776000) {
|
||||
username = "[Validator]";
|
||||
}
|
||||
if (username === "" && mapfix && auditEvent.User == mapfix.Submitter) {
|
||||
username = "[Submitter]";
|
||||
}
|
||||
return {
|
||||
date: auditEvent.CreatedAt,
|
||||
name: username,
|
||||
comment: auditEventMessage(auditEvent),
|
||||
}
|
||||
})
|
||||
|
||||
if (!mapfix) {
|
||||
return <Webpage>
|
||||
@@ -96,8 +109,17 @@ export default function MapfixInfoPage() {
|
||||
<Webpage>
|
||||
<main className="map-page-main">
|
||||
<section className="review-section">
|
||||
<RatingArea mapfixId={dynamicId.mapfixId}/>
|
||||
<TitleAndComments name={mapfix.DisplayName} creator={mapfix.Creator} review={mapfix.StatusID} status_message={mapfix.StatusMessage} asset_id={mapfix.AssetID} comments={[]}/>
|
||||
<RatingArea mapfixId={mapfixId} mapfixStatus={mapfix.StatusID} mapfixSubmitter={mapfix.Submitter} mapfixAssetId={mapfix.AssetID} mapfixTargetAssetId={mapfix.TargetAssetID} />
|
||||
<TitleAndComments
|
||||
name={mapfix.DisplayName}
|
||||
creator={mapfix.Creator}
|
||||
review={mapfix.StatusID}
|
||||
asset_id={mapfix.AssetID}
|
||||
submitter={mapfix.Submitter}
|
||||
target_asset_id={mapfix.TargetAssetID}
|
||||
description={mapfix.Description}
|
||||
comments={comments}
|
||||
/>
|
||||
</section>
|
||||
</main>
|
||||
</Webpage>
|
||||
|
||||
@@ -1,41 +1,42 @@
|
||||
'use client'
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { MapfixInfo } from "../ts/Mapfix";
|
||||
import MapfixCard from "../_components/mapCard";
|
||||
import { useState, useEffect } from "react";
|
||||
import { MapfixList } from "../ts/Mapfix";
|
||||
import { MapfixCard } from "../_components/mapCard";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
|
||||
// TODO: MAKE MAPFIX & SUBMISSIONS USE THE SAME COMPONENTS :angry: (currently too lazy)
|
||||
|
||||
import "./(styles)/page.scss";
|
||||
import { ListSortConstants } from "../ts/Sort";
|
||||
|
||||
export default function MapfixInfoPage() {
|
||||
const [mapfixes, setMapfixes] = useState<MapfixInfo[]>([])
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const [mapfixes, setMapfixes] = useState<MapfixList>({Total:0,Mapfixes:[]})
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const cardsPerPage = 24; // built to fit on a 1920x1080 monitor
|
||||
|
||||
const totalPages = Math.ceil(mapfixes.length / cardsPerPage);
|
||||
const totalPages = Math.ceil(mapfixes.Total / cardsPerPage);
|
||||
|
||||
const currentCards = mapfixes.slice(
|
||||
currentPage * cardsPerPage,
|
||||
(currentPage + 1) * cardsPerPage
|
||||
const currentCards = mapfixes.Mapfixes.slice(
|
||||
(currentPage - 1) * cardsPerPage,
|
||||
currentPage * cardsPerPage
|
||||
);
|
||||
|
||||
const nextPage = () => {
|
||||
if (currentPage < totalPages - 1) {
|
||||
if (currentPage < totalPages) {
|
||||
setCurrentPage(currentPage + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const prevPage = () => {
|
||||
if (currentPage > 0) {
|
||||
if (currentPage > 1) {
|
||||
setCurrentPage(currentPage - 1);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchMapfixes() {
|
||||
const res = await fetch('/api/mapfixes?Page=1&Limit=100')
|
||||
const res = await fetch(`/api/mapfixes?Page=${currentPage}&Limit=${cardsPerPage}&Sort=${ListSortConstants.ListSortDateDescending}`)
|
||||
if (res.ok) {
|
||||
setMapfixes(await res.json())
|
||||
}
|
||||
@@ -44,7 +45,7 @@ export default function MapfixInfoPage() {
|
||||
setTimeout(() => {
|
||||
fetchMapfixes()
|
||||
}, 50);
|
||||
}, [])
|
||||
}, [currentPage])
|
||||
|
||||
if (!mapfixes) {
|
||||
return <Webpage>
|
||||
@@ -54,7 +55,7 @@ export default function MapfixInfoPage() {
|
||||
</Webpage>
|
||||
}
|
||||
|
||||
if (mapfixes && mapfixes.length == 0) {
|
||||
if (mapfixes && mapfixes.Total == 0) {
|
||||
return <Webpage>
|
||||
<main>
|
||||
Mapfixes list is empty.
|
||||
@@ -82,17 +83,17 @@ export default function MapfixInfoPage() {
|
||||
{Array.from({ length: totalPages }).map((_, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className={`dot ${index === currentPage ? 'active' : ''}`}
|
||||
onClick={() => setCurrentPage(index)}
|
||||
className={`dot ${index+1 === currentPage ? 'active' : ''}`}
|
||||
onClick={() => setCurrentPage(index+1)}
|
||||
></span>
|
||||
))}
|
||||
</div>
|
||||
<div className="pagination">
|
||||
<button onClick={prevPage} disabled={currentPage === 0}><</button>
|
||||
<button onClick={prevPage} disabled={currentPage === 1}><</button>
|
||||
<span>
|
||||
Page {currentPage + 1} of {totalPages}
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<button onClick={nextPage} disabled={currentPage === totalPages - 1}>></button>
|
||||
<button onClick={nextPage} disabled={currentPage === totalPages}>></button>
|
||||
</div>
|
||||
<div className="grid">
|
||||
{currentCards.map((mapfix) => (
|
||||
|
||||
28
web/src/app/maps/[mapId]/_mapImage.tsx
Normal file
28
web/src/app/maps/[mapId]/_mapImage.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import Image from "next/image";
|
||||
import { MapInfo } from "@/app/ts/Map";
|
||||
|
||||
interface AssetID {
|
||||
id: MapInfo["ID"];
|
||||
}
|
||||
|
||||
function MapImage({ id }: AssetID) {
|
||||
if (!id) {
|
||||
return <p>Missing asset ID</p>;
|
||||
}
|
||||
|
||||
const imageUrl = `/thumbnails/asset/${id}`;
|
||||
|
||||
return (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="Map Thumbnail"
|
||||
layout="responsive"
|
||||
width={512}
|
||||
height={512}
|
||||
priority={true}
|
||||
className="map-image"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export { type AssetID, MapImage };
|
||||
@@ -11,9 +11,10 @@ import "./(styles)/page.scss"
|
||||
interface MapfixPayload {
|
||||
AssetID: number;
|
||||
TargetAssetID: number;
|
||||
Description: string;
|
||||
}
|
||||
interface IdResponse {
|
||||
ID: number;
|
||||
OperationID: number;
|
||||
}
|
||||
|
||||
export default function MapfixInfoPage() {
|
||||
@@ -28,6 +29,7 @@ export default function MapfixInfoPage() {
|
||||
const payload: MapfixPayload = {
|
||||
AssetID: Number((formData.get("asset-id") as string) ?? "0"),
|
||||
TargetAssetID: Number(dynamicId.mapId),
|
||||
Description: (formData.get("description") as string) ?? "unknown", // TEMPORARY! TODO: Change
|
||||
};
|
||||
|
||||
console.log(payload)
|
||||
@@ -53,7 +55,7 @@ export default function MapfixInfoPage() {
|
||||
const id_response:IdResponse = await response.json();
|
||||
|
||||
// navigate to newly created mapfix
|
||||
window.location.assign(`/mapfixes/${id_response.ID}`)
|
||||
window.location.assign(`/operations/${id_response.OperationID}`)
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error submitting data:", error);
|
||||
@@ -70,12 +72,13 @@ export default function MapfixInfoPage() {
|
||||
<form onSubmit={handleSubmit}>
|
||||
{/* TODO: Add form data for mapfixes, such as changes they did, and any times that need to be deleted & what styles */}
|
||||
<TextField className="form-field" id="asset-id" name="asset-id" label="Asset ID" variant="outlined"/>
|
||||
<TextField className="form-field" id="description" name="description" label="Describe the Mapfix" variant="outlined"/>
|
||||
<span className="spacer form-spacer"></span>
|
||||
<Button type="submit" variant="contained" startIcon={<SendIcon/>} sx={{
|
||||
width: "400px",
|
||||
height: "50px",
|
||||
marginInline: "auto"
|
||||
}}>Submit</Button>
|
||||
}}>Create Mapfix</Button>
|
||||
</form>
|
||||
</main>
|
||||
</Webpage>
|
||||
|
||||
@@ -1,14 +1,103 @@
|
||||
"use client"
|
||||
|
||||
import { MapInfo } from "@/app/ts/Map";
|
||||
import { MapImage } from "./_mapImage";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
import { useParams } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
// MUI Components
|
||||
import {
|
||||
Typography,
|
||||
Box,
|
||||
Button as MuiButton,
|
||||
Card,
|
||||
CardContent,
|
||||
Skeleton,
|
||||
ThemeProvider,
|
||||
createTheme,
|
||||
CssBaseline
|
||||
} from "@mui/material";
|
||||
|
||||
interface ButtonProps {
|
||||
name: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
function Button({ name, href }: ButtonProps) {
|
||||
return (
|
||||
<Link href={href} passHref>
|
||||
<MuiButton variant="contained" color="primary" sx={{ mt: 2 }}>
|
||||
{name}
|
||||
</MuiButton>
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
const darkTheme = createTheme({
|
||||
palette: {
|
||||
mode: "dark",
|
||||
},
|
||||
});
|
||||
|
||||
export default function Map() {
|
||||
const { mapId } = useParams<{mapId: string}>()
|
||||
const { mapId } = useParams();
|
||||
const [map, setMap] = useState<MapInfo | null>(null);
|
||||
|
||||
return (
|
||||
<Webpage>
|
||||
<p>map { mapId }</p>
|
||||
</Webpage>
|
||||
);
|
||||
useEffect(() => {
|
||||
async function getMap() {
|
||||
const res = await fetch(`/api/maps/${mapId}`);
|
||||
if (res.ok) {
|
||||
setMap(await res.json());
|
||||
}
|
||||
}
|
||||
getMap();
|
||||
}, [mapId]);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={darkTheme}>
|
||||
<CssBaseline />
|
||||
<Webpage>
|
||||
{!map ? (
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Skeleton variant="text" width={200} height={40} />
|
||||
<Skeleton variant="text" width={300} />
|
||||
<Skeleton variant="rectangular" height={200} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
) : (
|
||||
<Box display="flex" flexDirection={{ xs: "column", md: "row" }} gap={4}>
|
||||
<Box flex={1}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
Map Info
|
||||
</Typography>
|
||||
<Typography variant="body1"><strong>Map ID:</strong> {mapId}</Typography>
|
||||
<Typography variant="body1"><strong>Display Name:</strong> {map.DisplayName}</Typography>
|
||||
<Typography variant="body1"><strong>Creator:</strong> {map.Creator}</Typography>
|
||||
<Typography variant="body1"><strong>Game ID:</strong> {map.GameID}</Typography>
|
||||
<Typography variant="body1"><strong>Release Date:</strong> {new Date(map.Date * 1000).toLocaleString()}</Typography>
|
||||
<Button name="Submit A Mapfix For This Map" href={`/maps/${mapId}/fix`} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
|
||||
<Box flex={1}>
|
||||
<Card>
|
||||
<CardContent>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Map Preview
|
||||
</Typography>
|
||||
<MapImage id={map.ID} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
</Webpage>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useRef } from "react";
|
||||
import { useParams, useRouter } from "next/navigation";
|
||||
import { CircularProgress, Typography, Card, CardContent, Button } from "@mui/material";
|
||||
import Webpage from "@/app/_components/webpage";
|
||||
@@ -17,23 +17,31 @@ interface Operation {
|
||||
}
|
||||
|
||||
export default function OperationStatusPage() {
|
||||
const { operationId } = useParams();
|
||||
const router = useRouter();
|
||||
const [operation, setOperation] = useState<Operation | null>(null);
|
||||
const { operationId } = useParams();
|
||||
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [operation, setOperation] = useState<Operation | null>(null);
|
||||
|
||||
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!operationId) return;
|
||||
|
||||
|
||||
const fetchOperation = async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/operations/${operationId}`);
|
||||
|
||||
|
||||
if (!response.ok) throw new Error("Failed to fetch operation");
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
const data: Operation = await response.json();
|
||||
setOperation(data);
|
||||
|
||||
if (data.Status !== 0 && intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
intervalRef.current = null;
|
||||
}
|
||||
} catch (err: unknown) {
|
||||
if (err instanceof Error) {
|
||||
setError(err.message);
|
||||
@@ -44,39 +52,34 @@ export default function OperationStatusPage() {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
fetchOperation();
|
||||
const interval = setInterval(fetchOperation, 5000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
if (!intervalRef.current) {
|
||||
intervalRef.current = setInterval(fetchOperation, 1000);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (intervalRef.current) {
|
||||
clearInterval(intervalRef.current);
|
||||
}
|
||||
};
|
||||
}, [operationId]);
|
||||
|
||||
const getStatusClass = (status: number) => {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return "created";
|
||||
case 1:
|
||||
return "completed";
|
||||
case 2:
|
||||
return "failed";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = (status: number) => {
|
||||
switch (status) {
|
||||
case 0:
|
||||
return "Created";
|
||||
case 1:
|
||||
return "Completed";
|
||||
case 2:
|
||||
return "Failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
case 0:
|
||||
return "Created";
|
||||
case 1:
|
||||
return "Completed";
|
||||
case 2:
|
||||
return "Failed";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const getStatusClass = (status: number) => getStatusText(status).toLowerCase();
|
||||
|
||||
return (
|
||||
<Webpage>
|
||||
<main className="operation-status">
|
||||
@@ -96,13 +99,13 @@ export default function OperationStatusPage() {
|
||||
<Typography>Owner: {operation.Owner}</Typography>
|
||||
<Typography>Date: {new Date(operation.Date * 1000).toLocaleString()}</Typography>
|
||||
<Typography>Path: {operation.Path}</Typography>
|
||||
|
||||
|
||||
{operation.Status === 1 && (
|
||||
<div className="submission-button">
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
onClick={() => router.push(`/submissions/${operation.OperationID}`)}
|
||||
onClick={() => router.push(operation.Path)}
|
||||
>
|
||||
View Submission
|
||||
</Button>
|
||||
@@ -116,4 +119,4 @@ export default function OperationStatusPage() {
|
||||
</main>
|
||||
</Webpage>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ interface CreatorAndReviewStatus {
|
||||
asset_id: SubmissionInfo["AssetID"],
|
||||
creator: SubmissionInfo["DisplayName"],
|
||||
review: SubmissionInfo["StatusID"],
|
||||
status_message: SubmissionInfo["StatusMessage"],
|
||||
submitter: SubmissionInfo["Submitter"],
|
||||
uploaded_asset_id: SubmissionInfo["UploadedAssetID"],
|
||||
comments: Comment[],
|
||||
name: string
|
||||
}
|
||||
@@ -50,7 +51,7 @@ function LeaveAComment() {
|
||||
)
|
||||
}
|
||||
|
||||
export default function Comments(stats: CommentersProps) {
|
||||
export function Comments(stats: CommentersProps) {
|
||||
return (<>
|
||||
<section className="comments">
|
||||
{stats.comments_data.comments.length===0
|
||||
@@ -64,5 +65,6 @@ export default function Comments(stats: CommentersProps) {
|
||||
}
|
||||
|
||||
export {
|
||||
type CreatorAndReviewStatus
|
||||
type CreatorAndReviewStatus,
|
||||
type Comment,
|
||||
}
|
||||
|
||||
@@ -1,21 +1,40 @@
|
||||
import { Roles, RolesConstants } from "@/app/ts/Roles";
|
||||
import { SubmissionStatus } from "@/app/ts/Submission";
|
||||
import { Button, ButtonOwnProps } from "@mui/material";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
type Actions = "Completed" | "Submit" | "Reject" | "Revoke"
|
||||
type ApiActions = Lowercase<Actions> | "trigger-validate" | "retry-validate" | "trigger-upload" | "reset-uploading" | "reset-validating"
|
||||
type Review = Actions | "Accept" | "Validate" | "Upload" | "Reset Uploading (fix softlocked status)" | "Reset Validating (fix softlocked status)" | "Request Changes"
|
||||
interface ReviewAction {
|
||||
name: string,
|
||||
action: string,
|
||||
}
|
||||
|
||||
const ReviewActions = {
|
||||
Submit: {name:"Submit",action:"trigger-submit"} as ReviewAction,
|
||||
ForceSubmit: {name:"Force Submit",action:"trigger-submit"} as ReviewAction,
|
||||
ResetSubmitting: {name:"Reset Submitting (fix softlocked status)",action:"reset-submitting"} as ReviewAction,
|
||||
Revoke: {name:"Revoke",action:"revoke"} as ReviewAction,
|
||||
Accept: {name:"Accept",action:"trigger-validate"} as ReviewAction,
|
||||
Reject: {name:"Reject",action:"reject"} as ReviewAction,
|
||||
Validate: {name:"Validate",action:"retry-validate"} as ReviewAction,
|
||||
ResetValidating: {name:"Reset Validating (fix softlocked status)",action:"reset-validating"} as ReviewAction,
|
||||
RequestChanges: {name:"Request Changes",action:"request-changes"} as ReviewAction,
|
||||
Upload: {name:"Upload",action:"trigger-upload"} as ReviewAction,
|
||||
ResetUploading: {name:"Reset Uploading (fix softlocked status)",action:"reset-uploading"} as ReviewAction,
|
||||
}
|
||||
|
||||
interface ReviewButton {
|
||||
name: Review,
|
||||
action: ApiActions,
|
||||
action: ReviewAction,
|
||||
submissionId: string,
|
||||
color: ButtonOwnProps["color"]
|
||||
}
|
||||
|
||||
interface ReviewId {
|
||||
submissionId: string
|
||||
submissionId: string,
|
||||
submissionStatus: number,
|
||||
submissionSubmitter: number,
|
||||
}
|
||||
|
||||
async function ReviewButtonClicked(action: ApiActions, submissionId: string) {
|
||||
async function ReviewButtonClicked(action: string, submissionId: string) {
|
||||
try {
|
||||
const response = await fetch(`/api/submissions/${submissionId}/status/${action}`, {
|
||||
method: "POST",
|
||||
@@ -41,11 +60,10 @@ function ReviewButton(props: ReviewButton) {
|
||||
return <Button
|
||||
color={props.color}
|
||||
variant="contained"
|
||||
onClick={() => { ReviewButtonClicked(props.action, props.submissionId) }}>{props.name}</Button>
|
||||
onClick={() => { ReviewButtonClicked(props.action.action, props.submissionId) }}>{props.action.name}</Button>
|
||||
}
|
||||
|
||||
export default function ReviewButtons(props: ReviewId) {
|
||||
const submissionId = props.submissionId
|
||||
// When is each button visible?
|
||||
// Multiple buttons can be visible at once.
|
||||
// Action | Role | When Current Status is One of:
|
||||
@@ -59,16 +77,94 @@ export default function ReviewButtons(props: ReviewId) {
|
||||
// RequestChanges | Reviewer | Validated, Accepted, Submitted
|
||||
// Upload | MapAdmin | Validated
|
||||
// ResetUploading | MapAdmin | Uploading
|
||||
const { submissionId, submissionStatus } = props;
|
||||
const [user, setUser] = useState<number|null>(null);
|
||||
const [roles, setRoles] = useState<Roles>(RolesConstants.Empty);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const [rolesData, userData] = await Promise.all([
|
||||
fetch("/api/session/roles").then(rolesResponse => rolesResponse.json()),
|
||||
fetch("/api/session/user").then(userResponse => userResponse.json())
|
||||
]);
|
||||
|
||||
setRoles(rolesData.Roles);
|
||||
setUser(userData.UserID);
|
||||
} catch (error) {
|
||||
console.error("Error fetching data:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, [submissionId]);
|
||||
|
||||
if (loading) return <p>Loading...</p>;
|
||||
|
||||
const visibleButtons: ReviewButton[] = [];
|
||||
|
||||
const is_submitter = user === props.submissionSubmitter;
|
||||
if (is_submitter) {
|
||||
if ([SubmissionStatus.UnderConstruction, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
|
||||
visibleButtons.push({ action: ReviewActions.Submit, color: "info", submissionId });
|
||||
}
|
||||
if ([SubmissionStatus.Submitted, SubmissionStatus.ChangesRequested].includes(submissionStatus!)) {
|
||||
visibleButtons.push({ action: ReviewActions.Revoke, color: "info", submissionId });
|
||||
}
|
||||
if (submissionStatus === SubmissionStatus.Submitting) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetSubmitting, color: "error", submissionId });
|
||||
}
|
||||
}
|
||||
|
||||
if (roles&RolesConstants.SubmissionReview) {
|
||||
// you can force submit a map in ChangesRequested status
|
||||
if (!is_submitter && submissionStatus === SubmissionStatus.ChangesRequested) {
|
||||
visibleButtons.push({ action: ReviewActions.ForceSubmit, color: "error", submissionId });
|
||||
}
|
||||
// you can't review your own submission!
|
||||
// note that this means there needs to be more than one person with SubmissionReview
|
||||
if (!is_submitter && submissionStatus === SubmissionStatus.Submitted) {
|
||||
visibleButtons.push({ action: ReviewActions.Accept, color: "info", submissionId });
|
||||
visibleButtons.push({ action: ReviewActions.Reject, color: "error", submissionId });
|
||||
}
|
||||
if (submissionStatus === SubmissionStatus.AcceptedUnvalidated) {
|
||||
visibleButtons.push({ action: ReviewActions.Validate, color: "info", submissionId });
|
||||
}
|
||||
if (submissionStatus === SubmissionStatus.Validating) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetValidating, color: "error", submissionId });
|
||||
}
|
||||
// this button serves the same purpose as Revoke if you are both
|
||||
// the map submitter and have SubmissionReview when status is Submitted
|
||||
if (
|
||||
[SubmissionStatus.Validated, SubmissionStatus.AcceptedUnvalidated].includes(submissionStatus!)
|
||||
|| !is_submitter && submissionStatus == SubmissionStatus.Submitted
|
||||
) {
|
||||
visibleButtons.push({ action: ReviewActions.RequestChanges, color: "error", submissionId });
|
||||
}
|
||||
}
|
||||
|
||||
if (roles&RolesConstants.SubmissionUpload) {
|
||||
if (submissionStatus === SubmissionStatus.Validated) {
|
||||
visibleButtons.push({ action: ReviewActions.Upload, color: "info", submissionId });
|
||||
}
|
||||
// TODO: hide Reset buttons for 10 seconds
|
||||
if (submissionStatus === SubmissionStatus.Uploading) {
|
||||
visibleButtons.push({ action: ReviewActions.ResetUploading, color: "error", submissionId });
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<section className="review-set">
|
||||
<ReviewButton color="info" name="Submit" action="submit" submissionId={submissionId}/>
|
||||
<ReviewButton color="info" name="Revoke" action="revoke" submissionId={submissionId}/>
|
||||
<ReviewButton color="info" name="Accept" action="trigger-validate" submissionId={submissionId}/>
|
||||
<ReviewButton color="info" name="Validate" action="retry-validate" submissionId={submissionId}/>
|
||||
<ReviewButton color="error" name="Reject" action="reject" submissionId={submissionId}/>
|
||||
<ReviewButton color="info" name="Upload" action="trigger-upload" submissionId={submissionId}/>
|
||||
<ReviewButton color="error" name="Reset Uploading (fix softlocked status)" action="reset-uploading" submissionId={submissionId}/>
|
||||
<ReviewButton color="error" name="Reset Validating (fix softlocked status)" action="reset-validating" submissionId={submissionId}/>
|
||||
{visibleButtons.length === 0 ? (
|
||||
<p>No available actions</p>
|
||||
) : (
|
||||
visibleButtons.map((btn) => (
|
||||
<ReviewButton key={btn.action.action} {...btn} />
|
||||
))
|
||||
)}
|
||||
</section>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user