From 97e4d8e132db1d4deb78ccc885c5b8f0cc63fc4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Gonz=C3=A1lez?= <7822554+AlexTMjugador@users.noreply.github.com> Date: Mon, 16 Jun 2025 17:48:04 +0200 Subject: [PATCH] fix(labrinth): ensure versions get removed from search indexes before ending route execution (#3789) * fix(labrinth): ensure versions get removed from search indexes before ending route execution * chore: run `sqlx prepare` * chore(labrinth): simplify `remove_documents` a little * chore: tweak new comment --- ...4736b0245e752a90334c58209d8a02536c800.json | 14 - ...5dbc76d7385276a38ad79d9093c53c73bbde2.json | 14 - ...01754ff571de4f06e521bb4f7c0207268e03b.json | 15 - ...2961761c53b7375460ade15af921754d5d7da.json | 15 - ...15dc2a09e227d2f08e91167a43372a7ac6e35.json | 14 + ...5efb326864f8219941d1b696add39ed333ad1.json | 14 + ...e5a4edb8d5d6efda9b9dc124f344ae5c60e08.json | 14 - ...747245a98ea61bad3fae4b3ce284229d99955.json | 15 - ...6b608ea5441a96db9f7360fbdccceb4628202.json | 15 - ...0b1f09273ad02c319e6631c74d80a9b278328.json | 15 + ...6f68dff44badae9ae5c5aceba3c32e8d00356.json | 16 - ...393a12631fe6752a7d078bda06b24d50daae2.json | 15 - ...47232f9c341add2f3838cc3ae1a07a310d561.json | 15 + ...804d6fb2e05ffce07e7b4248d8705d6fc6e61.json | 15 + ...c6f97f18baf9eda30c64f32677158ada87478.json | 15 - ...a850cdd9fef3df1b3f7d5f62e079b4522f2ca.json | 15 + ...5ff71e654e5e6b386766e6c6047cf3861b26e.json | 14 + ...5e29589ee1b707729344e81d183c713aa0d28.json | 15 + ...c9220a95e309fb0dae41d9a05afa86e6b33af.json | 14 - ...0341fb1b4738f0ede71572d939ef0984bd65f.json | 14 - ...5687173b2fbde3405340a5579c5ef68cb5218.json | 15 + ...6e7746a96f9605afe2ca62d6d8337530cb5ad.json | 15 + ...620c89e6398f38ff066220fdadffe8e7481c1.json | 22 - ...9e368c6cea1800da8a5f9d50ba5b1ac3a15fc.json | 15 - ...87494979cb89d194805a5ce9e928eef796ae9.json | 15 - ...d734a92bb25f17a0536968e4b9a4dbe05cf5b.json | 14 + ...3c1ee3bfd357a6a8604febad3ed214a9b77b.json} | 5 +- ...45481c94edb1e8d8ac47db13ec0ff9b2f5328.json | 15 + ...ce4466824beaa00dea64cde90dc651a03024b.json | 15 - ...1f09a2799bf575af90beeac94193fe8c4388b.json | 22 + ...494da8738873b98aa608792af19e60b9fb998.json | 15 + ...eb00efcac9f6285a39d8df06d606613684ba3.json | 15 + ...0ed11cfd6749fa792d4eabed73b619f230585.json | 15 - ...661f7209bc1a7a04e2ea0026fa69c3f550a14.json | 22 - ...9430c5e58cd6d1c623c187d8661200400b1a4.json | 15 - ...9877229a451761be07f85a1dd04d027832329.json | 22 - ...b82b88af15477d616d0d3b3c6967b31d967f7.json | 15 + apps/labrinth/src/routes/v3/projects.rs | 1237 ++++++++--------- apps/labrinth/src/routes/v3/versions.rs | 3 +- apps/labrinth/src/search/indexing/mod.rs | 35 +- apps/labrinth/tests/search.rs | 19 +- 41 files changed, 888 insertions(+), 971 deletions(-) delete mode 100644 apps/labrinth/.sqlx/query-010cafcafb6adc25b00e3c81d844736b0245e752a90334c58209d8a02536c800.json delete mode 100644 apps/labrinth/.sqlx/query-124fbf0544ea6989d6dc5e840405dbc76d7385276a38ad79d9093c53c73bbde2.json delete mode 100644 apps/labrinth/.sqlx/query-186d0e933ece20163915926293a01754ff571de4f06e521bb4f7c0207268e03b.json delete mode 100644 apps/labrinth/.sqlx/query-19dc22c4d6d14222f8e8bace74c2961761c53b7375460ade15af921754d5d7da.json create mode 100644 apps/labrinth/.sqlx/query-299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35.json create mode 100644 apps/labrinth/.sqlx/query-3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1.json delete mode 100644 apps/labrinth/.sqlx/query-40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08.json delete mode 100644 apps/labrinth/.sqlx/query-4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955.json delete mode 100644 apps/labrinth/.sqlx/query-4fb5bd341369b4beb6b4a88de296b608ea5441a96db9f7360fbdccceb4628202.json create mode 100644 apps/labrinth/.sqlx/query-595f4e7432d5b41002988c6cc6b0b1f09273ad02c319e6631c74d80a9b278328.json delete mode 100644 apps/labrinth/.sqlx/query-6366891bb34a14278f1ae857b8d6f68dff44badae9ae5c5aceba3c32e8d00356.json delete mode 100644 apps/labrinth/.sqlx/query-66b06ddcd0a4cf01e716331befa393a12631fe6752a7d078bda06b24d50daae2.json create mode 100644 apps/labrinth/.sqlx/query-70be97b02e402de0490ade5866c47232f9c341add2f3838cc3ae1a07a310d561.json create mode 100644 apps/labrinth/.sqlx/query-79040825457845cc078be7b3293804d6fb2e05ffce07e7b4248d8705d6fc6e61.json delete mode 100644 apps/labrinth/.sqlx/query-7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478.json create mode 100644 apps/labrinth/.sqlx/query-7e403d399ddd3279c4c65db7b9ea850cdd9fef3df1b3f7d5f62e079b4522f2ca.json create mode 100644 apps/labrinth/.sqlx/query-92d805d2e13cfc0f2220f15b0a35ff71e654e5e6b386766e6c6047cf3861b26e.json create mode 100644 apps/labrinth/.sqlx/query-9482a3419337911ac6a10eeaf065e29589ee1b707729344e81d183c713aa0d28.json delete mode 100644 apps/labrinth/.sqlx/query-a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af.json delete mode 100644 apps/labrinth/.sqlx/query-a11d613479d09dff5fcdc45ab7a0341fb1b4738f0ede71572d939ef0984bd65f.json create mode 100644 apps/labrinth/.sqlx/query-a5ae1fe0ca4ca8432736398fed25687173b2fbde3405340a5579c5ef68cb5218.json create mode 100644 apps/labrinth/.sqlx/query-a74230ad1bb1b13bab850e204436e7746a96f9605afe2ca62d6d8337530cb5ad.json delete mode 100644 apps/labrinth/.sqlx/query-abf790170e3a807ffe8b3a188da620c89e6398f38ff066220fdadffe8e7481c1.json delete mode 100644 apps/labrinth/.sqlx/query-b677e66031752e66d2219079a559e368c6cea1800da8a5f9d50ba5b1ac3a15fc.json delete mode 100644 apps/labrinth/.sqlx/query-c100a3be0e1b7bf449576c4052d87494979cb89d194805a5ce9e928eef796ae9.json create mode 100644 apps/labrinth/.sqlx/query-c6693ea80ab1675dd2da72d70add734a92bb25f17a0536968e4b9a4dbe05cf5b.json rename apps/labrinth/.sqlx/{query-9c1b6ba7cbe2619ff767ee7bbfb01725dc3324d284b2f20cf393574ab3bc655f.json => query-cec98010827455127da68a2bc5cd3c1ee3bfd357a6a8604febad3ed214a9b77b.json} (55%) create mode 100644 apps/labrinth/.sqlx/query-d010207297e1c4f2ebfb0a81caf45481c94edb1e8d8ac47db13ec0ff9b2f5328.json delete mode 100644 apps/labrinth/.sqlx/query-d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b.json create mode 100644 apps/labrinth/.sqlx/query-d5ad5a67fe53351b760335b80501f09a2799bf575af90beeac94193fe8c4388b.json create mode 100644 apps/labrinth/.sqlx/query-e42e63db3ae4d1d745508b80651494da8738873b98aa608792af19e60b9fb998.json create mode 100644 apps/labrinth/.sqlx/query-e7654740161726b2aef4f7c9a26eb00efcac9f6285a39d8df06d606613684ba3.json delete mode 100644 apps/labrinth/.sqlx/query-e925b15ec46f0263c7775ba1ba00ed11cfd6749fa792d4eabed73b619f230585.json delete mode 100644 apps/labrinth/.sqlx/query-ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14.json delete mode 100644 apps/labrinth/.sqlx/query-ed1d5d9433bc7f4a360431ecfdd9430c5e58cd6d1c623c187d8661200400b1a4.json delete mode 100644 apps/labrinth/.sqlx/query-f34bbe639ad21801258dc8beaab9877229a451761be07f85a1dd04d027832329.json create mode 100644 apps/labrinth/.sqlx/query-fa874e2c55995feaa5e0d3cd54db82b88af15477d616d0d3b3c6967b31d967f7.json diff --git a/apps/labrinth/.sqlx/query-010cafcafb6adc25b00e3c81d844736b0245e752a90334c58209d8a02536c800.json b/apps/labrinth/.sqlx/query-010cafcafb6adc25b00e3c81d844736b0245e752a90334c58209d8a02536c800.json deleted file mode 100644 index 1336c5438..000000000 --- a/apps/labrinth/.sqlx/query-010cafcafb6adc25b00e3c81d844736b0245e752a90334c58209d8a02536c800.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET moderation_message = NULL, moderation_message_body = NULL, queued = NOW()\n WHERE (id = $1)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "010cafcafb6adc25b00e3c81d844736b0245e752a90334c58209d8a02536c800" -} diff --git a/apps/labrinth/.sqlx/query-124fbf0544ea6989d6dc5e840405dbc76d7385276a38ad79d9093c53c73bbde2.json b/apps/labrinth/.sqlx/query-124fbf0544ea6989d6dc5e840405dbc76d7385276a38ad79d9093c53c73bbde2.json deleted file mode 100644 index ecf7f3118..000000000 --- a/apps/labrinth/.sqlx/query-124fbf0544ea6989d6dc5e840405dbc76d7385276a38ad79d9093c53c73bbde2.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET webhook_sent = TRUE\n WHERE id = $1\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "124fbf0544ea6989d6dc5e840405dbc76d7385276a38ad79d9093c53c73bbde2" -} diff --git a/apps/labrinth/.sqlx/query-186d0e933ece20163915926293a01754ff571de4f06e521bb4f7c0207268e03b.json b/apps/labrinth/.sqlx/query-186d0e933ece20163915926293a01754ff571de4f06e521bb4f7c0207268e03b.json deleted file mode 100644 index e31392b44..000000000 --- a/apps/labrinth/.sqlx/query-186d0e933ece20163915926293a01754ff571de4f06e521bb4f7c0207268e03b.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n DELETE FROM mods_links\n WHERE joining_mod_id = $1 AND joining_platform_id IN (\n SELECT id FROM link_platforms WHERE name = ANY($2)\n )\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "TextArray" - ] - }, - "nullable": [] - }, - "hash": "186d0e933ece20163915926293a01754ff571de4f06e521bb4f7c0207268e03b" -} diff --git a/apps/labrinth/.sqlx/query-19dc22c4d6d14222f8e8bace74c2961761c53b7375460ade15af921754d5d7da.json b/apps/labrinth/.sqlx/query-19dc22c4d6d14222f8e8bace74c2961761c53b7375460ade15af921754d5d7da.json deleted file mode 100644 index 9254267e3..000000000 --- a/apps/labrinth/.sqlx/query-19dc22c4d6d14222f8e8bace74c2961761c53b7375460ade15af921754d5d7da.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET license = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "19dc22c4d6d14222f8e8bace74c2961761c53b7375460ade15af921754d5d7da" -} diff --git a/apps/labrinth/.sqlx/query-299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35.json b/apps/labrinth/.sqlx/query-299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35.json new file mode 100644 index 000000000..eecc67513 --- /dev/null +++ b/apps/labrinth/.sqlx/query-299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = FALSE\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35" +} diff --git a/apps/labrinth/.sqlx/query-3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1.json b/apps/labrinth/.sqlx/query-3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1.json new file mode 100644 index 000000000..73e76e5ed --- /dev/null +++ b/apps/labrinth/.sqlx/query-3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = TRUE\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1" +} diff --git a/apps/labrinth/.sqlx/query-40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08.json b/apps/labrinth/.sqlx/query-40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08.json deleted file mode 100644 index 4190c1eb4..000000000 --- a/apps/labrinth/.sqlx/query-40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = TRUE\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08" -} diff --git a/apps/labrinth/.sqlx/query-4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955.json b/apps/labrinth/.sqlx/query-4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955.json deleted file mode 100644 index be21454a5..000000000 --- a/apps/labrinth/.sqlx/query-4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET description = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "4e9f9eafbfd705dfc94571018cb747245a98ea61bad3fae4b3ce284229d99955" -} diff --git a/apps/labrinth/.sqlx/query-4fb5bd341369b4beb6b4a88de296b608ea5441a96db9f7360fbdccceb4628202.json b/apps/labrinth/.sqlx/query-4fb5bd341369b4beb6b4a88de296b608ea5441a96db9f7360fbdccceb4628202.json deleted file mode 100644 index 279dbcf75..000000000 --- a/apps/labrinth/.sqlx/query-4fb5bd341369b4beb6b4a88de296b608ea5441a96db9f7360fbdccceb4628202.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET slug = LOWER($1)\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "4fb5bd341369b4beb6b4a88de296b608ea5441a96db9f7360fbdccceb4628202" -} diff --git a/apps/labrinth/.sqlx/query-595f4e7432d5b41002988c6cc6b0b1f09273ad02c319e6631c74d80a9b278328.json b/apps/labrinth/.sqlx/query-595f4e7432d5b41002988c6cc6b0b1f09273ad02c319e6631c74d80a9b278328.json new file mode 100644 index 000000000..5474a7c6b --- /dev/null +++ b/apps/labrinth/.sqlx/query-595f4e7432d5b41002988c6cc6b0b1f09273ad02c319e6631c74d80a9b278328.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET summary = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "595f4e7432d5b41002988c6cc6b0b1f09273ad02c319e6631c74d80a9b278328" +} diff --git a/apps/labrinth/.sqlx/query-6366891bb34a14278f1ae857b8d6f68dff44badae9ae5c5aceba3c32e8d00356.json b/apps/labrinth/.sqlx/query-6366891bb34a14278f1ae857b8d6f68dff44badae9ae5c5aceba3c32e8d00356.json deleted file mode 100644 index b262237e9..000000000 --- a/apps/labrinth/.sqlx/query-6366891bb34a14278f1ae857b8d6f68dff44badae9ae5c5aceba3c32e8d00356.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO mods_links (joining_mod_id, joining_platform_id, url)\n VALUES ($1, $2, $3)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int4", - "Varchar" - ] - }, - "nullable": [] - }, - "hash": "6366891bb34a14278f1ae857b8d6f68dff44badae9ae5c5aceba3c32e8d00356" -} diff --git a/apps/labrinth/.sqlx/query-66b06ddcd0a4cf01e716331befa393a12631fe6752a7d078bda06b24d50daae2.json b/apps/labrinth/.sqlx/query-66b06ddcd0a4cf01e716331befa393a12631fe6752a7d078bda06b24d50daae2.json deleted file mode 100644 index f2e83cf92..000000000 --- a/apps/labrinth/.sqlx/query-66b06ddcd0a4cf01e716331befa393a12631fe6752a7d078bda06b24d50daae2.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET requested_status = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "66b06ddcd0a4cf01e716331befa393a12631fe6752a7d078bda06b24d50daae2" -} diff --git a/apps/labrinth/.sqlx/query-70be97b02e402de0490ade5866c47232f9c341add2f3838cc3ae1a07a310d561.json b/apps/labrinth/.sqlx/query-70be97b02e402de0490ade5866c47232f9c341add2f3838cc3ae1a07a310d561.json new file mode 100644 index 000000000..c75b97c5d --- /dev/null +++ b/apps/labrinth/.sqlx/query-70be97b02e402de0490ade5866c47232f9c341add2f3838cc3ae1a07a310d561.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET name = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "70be97b02e402de0490ade5866c47232f9c341add2f3838cc3ae1a07a310d561" +} diff --git a/apps/labrinth/.sqlx/query-79040825457845cc078be7b3293804d6fb2e05ffce07e7b4248d8705d6fc6e61.json b/apps/labrinth/.sqlx/query-79040825457845cc078be7b3293804d6fb2e05ffce07e7b4248d8705d6fc6e61.json new file mode 100644 index 000000000..5c989cc2a --- /dev/null +++ b/apps/labrinth/.sqlx/query-79040825457845cc078be7b3293804d6fb2e05ffce07e7b4248d8705d6fc6e61.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET moderation_message_body = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "79040825457845cc078be7b3293804d6fb2e05ffce07e7b4248d8705d6fc6e61" +} diff --git a/apps/labrinth/.sqlx/query-7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478.json b/apps/labrinth/.sqlx/query-7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478.json deleted file mode 100644 index 6996aa840..000000000 --- a/apps/labrinth/.sqlx/query-7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET monetization_status = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "7916fe4f04067324ae05598ec9dc6f97f18baf9eda30c64f32677158ada87478" -} diff --git a/apps/labrinth/.sqlx/query-7e403d399ddd3279c4c65db7b9ea850cdd9fef3df1b3f7d5f62e079b4522f2ca.json b/apps/labrinth/.sqlx/query-7e403d399ddd3279c4c65db7b9ea850cdd9fef3df1b3f7d5f62e079b4522f2ca.json new file mode 100644 index 000000000..8226261f5 --- /dev/null +++ b/apps/labrinth/.sqlx/query-7e403d399ddd3279c4c65db7b9ea850cdd9fef3df1b3f7d5f62e079b4522f2ca.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET slug = LOWER($1)\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Text", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "7e403d399ddd3279c4c65db7b9ea850cdd9fef3df1b3f7d5f62e079b4522f2ca" +} diff --git a/apps/labrinth/.sqlx/query-92d805d2e13cfc0f2220f15b0a35ff71e654e5e6b386766e6c6047cf3861b26e.json b/apps/labrinth/.sqlx/query-92d805d2e13cfc0f2220f15b0a35ff71e654e5e6b386766e6c6047cf3861b26e.json new file mode 100644 index 000000000..d627ef2dc --- /dev/null +++ b/apps/labrinth/.sqlx/query-92d805d2e13cfc0f2220f15b0a35ff71e654e5e6b386766e6c6047cf3861b26e.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET approved = NOW()\n WHERE id = $1 AND approved IS NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "92d805d2e13cfc0f2220f15b0a35ff71e654e5e6b386766e6c6047cf3861b26e" +} diff --git a/apps/labrinth/.sqlx/query-9482a3419337911ac6a10eeaf065e29589ee1b707729344e81d183c713aa0d28.json b/apps/labrinth/.sqlx/query-9482a3419337911ac6a10eeaf065e29589ee1b707729344e81d183c713aa0d28.json new file mode 100644 index 000000000..babe8ad64 --- /dev/null +++ b/apps/labrinth/.sqlx/query-9482a3419337911ac6a10eeaf065e29589ee1b707729344e81d183c713aa0d28.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET license_url = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "9482a3419337911ac6a10eeaf065e29589ee1b707729344e81d183c713aa0d28" +} diff --git a/apps/labrinth/.sqlx/query-a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af.json b/apps/labrinth/.sqlx/query-a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af.json deleted file mode 100644 index a8ec2492d..000000000 --- a/apps/labrinth/.sqlx/query-a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = FALSE\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "a0148ff25855202e7bb220b6a2bc9220a95e309fb0dae41d9a05afa86e6b33af" -} diff --git a/apps/labrinth/.sqlx/query-a11d613479d09dff5fcdc45ab7a0341fb1b4738f0ede71572d939ef0984bd65f.json b/apps/labrinth/.sqlx/query-a11d613479d09dff5fcdc45ab7a0341fb1b4738f0ede71572d939ef0984bd65f.json deleted file mode 100644 index 4b97bd691..000000000 --- a/apps/labrinth/.sqlx/query-a11d613479d09dff5fcdc45ab7a0341fb1b4738f0ede71572d939ef0984bd65f.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET approved = NOW()\n WHERE id = $1 AND approved IS NULL\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [] - }, - "hash": "a11d613479d09dff5fcdc45ab7a0341fb1b4738f0ede71572d939ef0984bd65f" -} diff --git a/apps/labrinth/.sqlx/query-a5ae1fe0ca4ca8432736398fed25687173b2fbde3405340a5579c5ef68cb5218.json b/apps/labrinth/.sqlx/query-a5ae1fe0ca4ca8432736398fed25687173b2fbde3405340a5579c5ef68cb5218.json new file mode 100644 index 000000000..799ce4489 --- /dev/null +++ b/apps/labrinth/.sqlx/query-a5ae1fe0ca4ca8432736398fed25687173b2fbde3405340a5579c5ef68cb5218.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET license = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a5ae1fe0ca4ca8432736398fed25687173b2fbde3405340a5579c5ef68cb5218" +} diff --git a/apps/labrinth/.sqlx/query-a74230ad1bb1b13bab850e204436e7746a96f9605afe2ca62d6d8337530cb5ad.json b/apps/labrinth/.sqlx/query-a74230ad1bb1b13bab850e204436e7746a96f9605afe2ca62d6d8337530cb5ad.json new file mode 100644 index 000000000..73d8a8eec --- /dev/null +++ b/apps/labrinth/.sqlx/query-a74230ad1bb1b13bab850e204436e7746a96f9605afe2ca62d6d8337530cb5ad.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET status = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "a74230ad1bb1b13bab850e204436e7746a96f9605afe2ca62d6d8337530cb5ad" +} diff --git a/apps/labrinth/.sqlx/query-abf790170e3a807ffe8b3a188da620c89e6398f38ff066220fdadffe8e7481c1.json b/apps/labrinth/.sqlx/query-abf790170e3a807ffe8b3a188da620c89e6398f38ff066220fdadffe8e7481c1.json deleted file mode 100644 index 20e672605..000000000 --- a/apps/labrinth/.sqlx/query-abf790170e3a807ffe8b3a188da620c89e6398f38ff066220fdadffe8e7481c1.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS(SELECT 1 FROM mods WHERE slug = LOWER($1))\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Text" - ] - }, - "nullable": [ - null - ] - }, - "hash": "abf790170e3a807ffe8b3a188da620c89e6398f38ff066220fdadffe8e7481c1" -} diff --git a/apps/labrinth/.sqlx/query-b677e66031752e66d2219079a559e368c6cea1800da8a5f9d50ba5b1ac3a15fc.json b/apps/labrinth/.sqlx/query-b677e66031752e66d2219079a559e368c6cea1800da8a5f9d50ba5b1ac3a15fc.json deleted file mode 100644 index a66547009..000000000 --- a/apps/labrinth/.sqlx/query-b677e66031752e66d2219079a559e368c6cea1800da8a5f9d50ba5b1ac3a15fc.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET summary = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "b677e66031752e66d2219079a559e368c6cea1800da8a5f9d50ba5b1ac3a15fc" -} diff --git a/apps/labrinth/.sqlx/query-c100a3be0e1b7bf449576c4052d87494979cb89d194805a5ce9e928eef796ae9.json b/apps/labrinth/.sqlx/query-c100a3be0e1b7bf449576c4052d87494979cb89d194805a5ce9e928eef796ae9.json deleted file mode 100644 index fff83ae5a..000000000 --- a/apps/labrinth/.sqlx/query-c100a3be0e1b7bf449576c4052d87494979cb89d194805a5ce9e928eef796ae9.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET license_url = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "c100a3be0e1b7bf449576c4052d87494979cb89d194805a5ce9e928eef796ae9" -} diff --git a/apps/labrinth/.sqlx/query-c6693ea80ab1675dd2da72d70add734a92bb25f17a0536968e4b9a4dbe05cf5b.json b/apps/labrinth/.sqlx/query-c6693ea80ab1675dd2da72d70add734a92bb25f17a0536968e4b9a4dbe05cf5b.json new file mode 100644 index 000000000..dc7aa810b --- /dev/null +++ b/apps/labrinth/.sqlx/query-c6693ea80ab1675dd2da72d70add734a92bb25f17a0536968e4b9a4dbe05cf5b.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET moderation_message = NULL, moderation_message_body = NULL, queued = NOW()\n WHERE (id = $1)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [] + }, + "hash": "c6693ea80ab1675dd2da72d70add734a92bb25f17a0536968e4b9a4dbe05cf5b" +} diff --git a/apps/labrinth/.sqlx/query-9c1b6ba7cbe2619ff767ee7bbfb01725dc3324d284b2f20cf393574ab3bc655f.json b/apps/labrinth/.sqlx/query-cec98010827455127da68a2bc5cd3c1ee3bfd357a6a8604febad3ed214a9b77b.json similarity index 55% rename from apps/labrinth/.sqlx/query-9c1b6ba7cbe2619ff767ee7bbfb01725dc3324d284b2f20cf393574ab3bc655f.json rename to apps/labrinth/.sqlx/query-cec98010827455127da68a2bc5cd3c1ee3bfd357a6a8604febad3ed214a9b77b.json index 5152ba222..5a26ce08b 100644 --- a/apps/labrinth/.sqlx/query-9c1b6ba7cbe2619ff767ee7bbfb01725dc3324d284b2f20cf393574ab3bc655f.json +++ b/apps/labrinth/.sqlx/query-cec98010827455127da68a2bc5cd3c1ee3bfd357a6a8604febad3ed214a9b77b.json @@ -1,15 +1,14 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET name = $1\n WHERE (id = $2)\n ", + "query": "\n UPDATE mods\n SET webhook_sent = TRUE\n WHERE id = $1\n ", "describe": { "columns": [], "parameters": { "Left": [ - "Varchar", "Int8" ] }, "nullable": [] }, - "hash": "9c1b6ba7cbe2619ff767ee7bbfb01725dc3324d284b2f20cf393574ab3bc655f" + "hash": "cec98010827455127da68a2bc5cd3c1ee3bfd357a6a8604febad3ed214a9b77b" } diff --git a/apps/labrinth/.sqlx/query-d010207297e1c4f2ebfb0a81caf45481c94edb1e8d8ac47db13ec0ff9b2f5328.json b/apps/labrinth/.sqlx/query-d010207297e1c4f2ebfb0a81caf45481c94edb1e8d8ac47db13ec0ff9b2f5328.json new file mode 100644 index 000000000..507b49c6c --- /dev/null +++ b/apps/labrinth/.sqlx/query-d010207297e1c4f2ebfb0a81caf45481c94edb1e8d8ac47db13ec0ff9b2f5328.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET moderation_message = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "d010207297e1c4f2ebfb0a81caf45481c94edb1e8d8ac47db13ec0ff9b2f5328" +} diff --git a/apps/labrinth/.sqlx/query-d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b.json b/apps/labrinth/.sqlx/query-d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b.json deleted file mode 100644 index 9df5df701..000000000 --- a/apps/labrinth/.sqlx/query-d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET moderation_message = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b" -} diff --git a/apps/labrinth/.sqlx/query-d5ad5a67fe53351b760335b80501f09a2799bf575af90beeac94193fe8c4388b.json b/apps/labrinth/.sqlx/query-d5ad5a67fe53351b760335b80501f09a2799bf575af90beeac94193fe8c4388b.json new file mode 100644 index 000000000..3d9785e4d --- /dev/null +++ b/apps/labrinth/.sqlx/query-d5ad5a67fe53351b760335b80501f09a2799bf575af90beeac94193fe8c4388b.json @@ -0,0 +1,22 @@ +{ + "db_name": "PostgreSQL", + "query": "\n SELECT tm.user_id id\n FROM team_members tm\n WHERE tm.team_id = $1 AND tm.accepted\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": "Int8" + } + ], + "parameters": { + "Left": [ + "Int8" + ] + }, + "nullable": [ + false + ] + }, + "hash": "d5ad5a67fe53351b760335b80501f09a2799bf575af90beeac94193fe8c4388b" +} diff --git a/apps/labrinth/.sqlx/query-e42e63db3ae4d1d745508b80651494da8738873b98aa608792af19e60b9fb998.json b/apps/labrinth/.sqlx/query-e42e63db3ae4d1d745508b80651494da8738873b98aa608792af19e60b9fb998.json new file mode 100644 index 000000000..e42fc661e --- /dev/null +++ b/apps/labrinth/.sqlx/query-e42e63db3ae4d1d745508b80651494da8738873b98aa608792af19e60b9fb998.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET requested_status = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "e42e63db3ae4d1d745508b80651494da8738873b98aa608792af19e60b9fb998" +} diff --git a/apps/labrinth/.sqlx/query-e7654740161726b2aef4f7c9a26eb00efcac9f6285a39d8df06d606613684ba3.json b/apps/labrinth/.sqlx/query-e7654740161726b2aef4f7c9a26eb00efcac9f6285a39d8df06d606613684ba3.json new file mode 100644 index 000000000..ef8f7b22c --- /dev/null +++ b/apps/labrinth/.sqlx/query-e7654740161726b2aef4f7c9a26eb00efcac9f6285a39d8df06d606613684ba3.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET description = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "e7654740161726b2aef4f7c9a26eb00efcac9f6285a39d8df06d606613684ba3" +} diff --git a/apps/labrinth/.sqlx/query-e925b15ec46f0263c7775ba1ba00ed11cfd6749fa792d4eabed73b619f230585.json b/apps/labrinth/.sqlx/query-e925b15ec46f0263c7775ba1ba00ed11cfd6749fa792d4eabed73b619f230585.json deleted file mode 100644 index 52bc085af..000000000 --- a/apps/labrinth/.sqlx/query-e925b15ec46f0263c7775ba1ba00ed11cfd6749fa792d4eabed73b619f230585.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET status = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "e925b15ec46f0263c7775ba1ba00ed11cfd6749fa792d4eabed73b619f230585" -} diff --git a/apps/labrinth/.sqlx/query-ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14.json b/apps/labrinth/.sqlx/query-ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14.json deleted file mode 100644 index dcdaa6f99..000000000 --- a/apps/labrinth/.sqlx/query-ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT tm.user_id id\n FROM team_members tm\n WHERE tm.team_id = $1 AND tm.accepted\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - false - ] - }, - "hash": "ea1525cbe7460d0d9e9da8f448c661f7209bc1a7a04e2ea0026fa69c3f550a14" -} diff --git a/apps/labrinth/.sqlx/query-ed1d5d9433bc7f4a360431ecfdd9430c5e58cd6d1c623c187d8661200400b1a4.json b/apps/labrinth/.sqlx/query-ed1d5d9433bc7f4a360431ecfdd9430c5e58cd6d1c623c187d8661200400b1a4.json deleted file mode 100644 index 4bcf71fd8..000000000 --- a/apps/labrinth/.sqlx/query-ed1d5d9433bc7f4a360431ecfdd9430c5e58cd6d1c623c187d8661200400b1a4.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n UPDATE mods\n SET moderation_message_body = $1\n WHERE (id = $2)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8" - ] - }, - "nullable": [] - }, - "hash": "ed1d5d9433bc7f4a360431ecfdd9430c5e58cd6d1c623c187d8661200400b1a4" -} diff --git a/apps/labrinth/.sqlx/query-f34bbe639ad21801258dc8beaab9877229a451761be07f85a1dd04d027832329.json b/apps/labrinth/.sqlx/query-f34bbe639ad21801258dc8beaab9877229a451761be07f85a1dd04d027832329.json deleted file mode 100644 index ec3004f9c..000000000 --- a/apps/labrinth/.sqlx/query-f34bbe639ad21801258dc8beaab9877229a451761be07f85a1dd04d027832329.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS(SELECT 1 FROM mods WHERE id=$1)\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "exists", - "type_info": "Bool" - } - ], - "parameters": { - "Left": [ - "Int8" - ] - }, - "nullable": [ - null - ] - }, - "hash": "f34bbe639ad21801258dc8beaab9877229a451761be07f85a1dd04d027832329" -} diff --git a/apps/labrinth/.sqlx/query-fa874e2c55995feaa5e0d3cd54db82b88af15477d616d0d3b3c6967b31d967f7.json b/apps/labrinth/.sqlx/query-fa874e2c55995feaa5e0d3cd54db82b88af15477d616d0d3b3c6967b31d967f7.json new file mode 100644 index 000000000..24a5dbb41 --- /dev/null +++ b/apps/labrinth/.sqlx/query-fa874e2c55995feaa5e0d3cd54db82b88af15477d616d0d3b3c6967b31d967f7.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE mods\n SET monetization_status = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "fa874e2c55995feaa5e0d3cd54db82b88af15477d616d0d3b3c6967b31d967f7" +} diff --git a/apps/labrinth/src/routes/v3/projects.rs b/apps/labrinth/src/routes/v3/projects.rs index f4dba4455..025b991aa 100644 --- a/apps/labrinth/src/routes/v3/projects.rs +++ b/apps/labrinth/src/routes/v3/projects.rs @@ -274,640 +274,623 @@ pub async fn project_edit( ApiError::Validation(validation_errors_to_string(err, None)) })?; - let string = info.into_inner().0; - let result = db_models::DBProject::get(&string, &**pool, &redis).await?; - if let Some(project_item) = result { - let id = project_item.inner.id; + let Some(project_item) = + db_models::DBProject::get(&info.into_inner().0, &**pool, &redis) + .await? + else { + return Err(ApiError::NotFound); + }; - let (team_member, organization_team_member) = - db_models::DBTeamMember::get_for_project_permissions( - &project_item.inner, - user.id.into(), - &**pool, - ) - .await?; + let id = project_item.inner.id; - let permissions = ProjectPermissions::get_permissions_by_role( - &user.role, - &team_member, - &organization_team_member, - ); + let (team_member, organization_team_member) = + db_models::DBTeamMember::get_for_project_permissions( + &project_item.inner, + user.id.into(), + &**pool, + ) + .await?; - if let Some(perms) = permissions { - let mut transaction = pool.begin().await?; + let Some(perms) = ProjectPermissions::get_permissions_by_role( + &user.role, + &team_member, + &organization_team_member, + ) else { + return Err(ApiError::CustomAuthentication( + "You do not have permission to edit this project!".to_string(), + )); + }; - if let Some(name) = &new_project.name { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the name of this project!" - .to_string(), - )); - } + let mut transaction = pool.begin().await?; - sqlx::query!( - " - UPDATE mods - SET name = $1 - WHERE (id = $2) - ", - name.trim(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(summary) = &new_project.summary { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the summary of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET summary = $1 - WHERE (id = $2) - ", - summary, - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(status) = &new_project.status { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the status of this project!" - .to_string(), - )); - } - - if !(user.role.is_mod() - || !project_item.inner.status.is_approved() - && status == &ProjectStatus::Processing - || project_item.inner.status.is_approved() - && status.can_be_requested()) - { - return Err(ApiError::CustomAuthentication( - "You don't have permission to set this status!" - .to_string(), - )); - } - - if status == &ProjectStatus::Processing { - if project_item.versions.is_empty() { - return Err(ApiError::InvalidInput(String::from( - "Project submitted for review with no initial versions", - ))); - } - - sqlx::query!( - " - UPDATE mods - SET moderation_message = NULL, moderation_message_body = NULL, queued = NOW() - WHERE (id = $1) - ", - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - - moderation_queue - .projects - .insert(project_item.inner.id.into()); - } - - if status.is_approved() - && !project_item.inner.status.is_approved() - { - sqlx::query!( - " - UPDATE mods - SET approved = NOW() - WHERE id = $1 AND approved IS NULL - ", - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - if status.is_searchable() && !project_item.inner.webhook_sent { - if let Ok(webhook_url) = - dotenvy::var("PUBLIC_DISCORD_WEBHOOK") - { - crate::util::webhook::send_discord_webhook( - project_item.inner.id.into(), - &pool, - &redis, - webhook_url, - None, - ) - .await - .ok(); - - sqlx::query!( - " - UPDATE mods - SET webhook_sent = TRUE - WHERE id = $1 - ", - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - } - - if user.role.is_mod() { - if let Ok(webhook_url) = - dotenvy::var("MODERATION_SLACK_WEBHOOK") - { - crate::util::webhook::send_slack_webhook( - project_item.inner.id.into(), - &pool, - &redis, - webhook_url, - Some( - format!( - "*<{}/user/{}|{}>* changed project status from *{}* to *{}*", - dotenvy::var("SITE_URL")?, - user.username, - user.username, - &project_item.inner.status.as_friendly_str(), - status.as_friendly_str(), - ) - .to_string(), - ), - ) - .await - .ok(); - } - } - - if team_member.is_none_or(|x| !x.accepted) { - let notified_members = sqlx::query!( - " - SELECT tm.user_id id - FROM team_members tm - WHERE tm.team_id = $1 AND tm.accepted - ", - project_item.inner.team_id as db_ids::DBTeamId - ) - .fetch(&mut *transaction) - .map_ok(|c| db_models::DBUserId(c.id)) - .try_collect::>() - .await?; - - NotificationBuilder { - body: NotificationBody::StatusChange { - project_id: project_item.inner.id.into(), - old_status: project_item.inner.status, - new_status: *status, - }, - } - .insert_many(notified_members, &mut transaction, &redis) - .await?; - } - - ThreadMessageBuilder { - author_id: Some(user.id.into()), - body: MessageBody::StatusChange { - new_status: *status, - old_status: project_item.inner.status, - }, - thread_id: project_item.thread_id, - hide_identity: user.role.is_mod(), - } - .insert(&mut transaction) - .await?; - - sqlx::query!( - " - UPDATE mods - SET status = $1 - WHERE (id = $2) - ", - status.as_str(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - - if project_item.inner.status.is_searchable() - && !status.is_searchable() - { - remove_documents( - &project_item - .versions - .into_iter() - .map(|x| x.into()) - .collect::>(), - &search_config, - ) - .await?; - } - } - - if let Some(requested_status) = &new_project.requested_status { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the requested status of this project!" - .to_string(), - )); - } - - if !requested_status - .map(|x| x.can_be_requested()) - .unwrap_or(true) - { - return Err(ApiError::InvalidInput(String::from( - "Specified status cannot be requested!", - ))); - } - - sqlx::query!( - " - UPDATE mods - SET requested_status = $1 - WHERE (id = $2) - ", - requested_status.map(|x| x.as_str()), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if perms.contains(ProjectPermissions::EDIT_DETAILS) { - if new_project.categories.is_some() { - sqlx::query!( - " - DELETE FROM mods_categories - WHERE joining_mod_id = $1 AND is_additional = FALSE - ", - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if new_project.additional_categories.is_some() { - sqlx::query!( - " - DELETE FROM mods_categories - WHERE joining_mod_id = $1 AND is_additional = TRUE - ", - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - } - - if let Some(categories) = &new_project.categories { - edit_project_categories( - categories, - &perms, - id as db_ids::DBProjectId, - false, - &mut transaction, - ) - .await?; - } - - if let Some(categories) = &new_project.additional_categories { - edit_project_categories( - categories, - &perms, - id as db_ids::DBProjectId, - true, - &mut transaction, - ) - .await?; - } - - if let Some(license_url) = &new_project.license_url { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the license URL of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET license_url = $1 - WHERE (id = $2) - ", - license_url.as_deref(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(slug) = &new_project.slug { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the slug of this project!" - .to_string(), - )); - } - - let slug_project_id_option: Option = - parse_base62(slug).ok(); - if let Some(slug_project_id) = slug_project_id_option { - let results = sqlx::query!( - " - SELECT EXISTS(SELECT 1 FROM mods WHERE id=$1) - ", - slug_project_id as i64 - ) - .fetch_one(&mut *transaction) - .await?; - - if results.exists.unwrap_or(true) { - return Err(ApiError::InvalidInput( - "Slug collides with other project's id!" - .to_string(), - )); - } - } - - // Make sure the new slug is different from the old one - // We are able to unwrap here because the slug is always set - if !slug.eq(&project_item - .inner - .slug - .clone() - .unwrap_or_default()) - { - let results = sqlx::query!( - " - SELECT EXISTS(SELECT 1 FROM mods WHERE slug = LOWER($1)) - ", - slug - ) - .fetch_one(&mut *transaction) - .await?; - - if results.exists.unwrap_or(true) { - return Err(ApiError::InvalidInput( - "Slug collides with other project's id!" - .to_string(), - )); - } - } - - sqlx::query!( - " - UPDATE mods - SET slug = LOWER($1) - WHERE (id = $2) - ", - Some(slug), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(license) = &new_project.license_id { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the license of this project!" - .to_string(), - )); - } - - let mut license = license.clone(); - - if license.to_lowercase() == "arr" { - license = models::projects::DEFAULT_LICENSE_ID.to_string(); - } - - spdx::Expression::parse(&license).map_err(|err| { - ApiError::InvalidInput(format!( - "Invalid SPDX license identifier: {err}" - )) - })?; - - sqlx::query!( - " - UPDATE mods - SET license = $1 - WHERE (id = $2) - ", - license, - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - if let Some(links) = &new_project.link_urls { - if !links.is_empty() { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the links of this project!" - .to_string(), - )); - } - - let ids_to_delete = - links.keys().cloned().collect::>(); - // Deletes all links from hashmap- either will be deleted or be replaced - sqlx::query!( - " - DELETE FROM mods_links - WHERE joining_mod_id = $1 AND joining_platform_id IN ( - SELECT id FROM link_platforms WHERE name = ANY($2) - ) - ", - id as db_ids::DBProjectId, - &ids_to_delete - ) - .execute(&mut *transaction) - .await?; - - for (platform, url) in links { - if let Some(url) = url { - let platform_id = - db_models::categories::LinkPlatform::get_id( - platform, - &mut *transaction, - ) - .await? - .ok_or_else( - || { - ApiError::InvalidInput(format!( - "Platform {} does not exist.", - platform.clone() - )) - }, - )?; - sqlx::query!( - " - INSERT INTO mods_links (joining_mod_id, joining_platform_id, url) - VALUES ($1, $2, $3) - ", - id as db_ids::DBProjectId, - platform_id as db_ids::LinkPlatformId, - url - ) - .execute(&mut *transaction) - .await?; - } - } - } - } - if let Some(moderation_message) = &new_project.moderation_message { - if !user.role.is_mod() - && (!project_item.inner.status.is_approved() - || moderation_message.is_some()) - { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the moderation message of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET moderation_message = $1 - WHERE (id = $2) - ", - moderation_message.as_deref(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(moderation_message_body) = - &new_project.moderation_message_body - { - if !user.role.is_mod() - && (!project_item.inner.status.is_approved() - || moderation_message_body.is_some()) - { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the moderation message body of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET moderation_message_body = $1 - WHERE (id = $2) - ", - moderation_message_body.as_deref(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(description) = &new_project.description { - if !perms.contains(ProjectPermissions::EDIT_BODY) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the description (body) of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET description = $1 - WHERE (id = $2) - ", - description, - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - if let Some(monetization_status) = &new_project.monetization_status - { - if !perms.contains(ProjectPermissions::EDIT_DETAILS) { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the monetization status of this project!" - .to_string(), - )); - } - - if (*monetization_status - == MonetizationStatus::ForceDemonetized - || project_item.inner.monetization_status - == MonetizationStatus::ForceDemonetized) - && !user.role.is_mod() - { - return Err(ApiError::CustomAuthentication( - "You do not have the permissions to edit the monetization status of this project!" - .to_string(), - )); - } - - sqlx::query!( - " - UPDATE mods - SET monetization_status = $1 - WHERE (id = $2) - ", - monetization_status.as_str(), - id as db_ids::DBProjectId, - ) - .execute(&mut *transaction) - .await?; - } - - // check new description and body for links to associated images - // if they no longer exist in the description or body, delete them - let checkable_strings: Vec<&str> = - vec![&new_project.description, &new_project.summary] - .into_iter() - .filter_map(|x| x.as_ref().map(|y| y.as_str())) - .collect(); - - let context = ImageContext::Project { - project_id: Some(id.into()), - }; - - img::delete_unused_images( - context, - checkable_strings, - &mut transaction, - &redis, - ) - .await?; - - transaction.commit().await?; - db_models::DBProject::clear_cache( - project_item.inner.id, - project_item.inner.slug, - None, - &redis, - ) - .await?; - - Ok(HttpResponse::NoContent().body("")) - } else { - Err(ApiError::CustomAuthentication( - "You do not have permission to edit this project!".to_string(), - )) + if let Some(name) = &new_project.name { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the name of this project!" + .to_string(), + )); } - } else { - Err(ApiError::NotFound) + + sqlx::query!( + " + UPDATE mods + SET name = $1 + WHERE (id = $2) + ", + name.trim(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; } + + if let Some(summary) = &new_project.summary { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the summary of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET summary = $1 + WHERE (id = $2) + ", + summary, + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(status) = &new_project.status { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the status of this project!" + .to_string(), + )); + } + + if !(user.role.is_mod() + || !project_item.inner.status.is_approved() + && status == &ProjectStatus::Processing + || project_item.inner.status.is_approved() + && status.can_be_requested()) + { + return Err(ApiError::CustomAuthentication( + "You don't have permission to set this status!".to_string(), + )); + } + + if status == &ProjectStatus::Processing { + if project_item.versions.is_empty() { + return Err(ApiError::InvalidInput(String::from( + "Project submitted for review with no initial versions", + ))); + } + + sqlx::query!( + " + UPDATE mods + SET moderation_message = NULL, moderation_message_body = NULL, queued = NOW() + WHERE (id = $1) + ", + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + + moderation_queue + .projects + .insert(project_item.inner.id.into()); + } + + if status.is_approved() && !project_item.inner.status.is_approved() { + sqlx::query!( + " + UPDATE mods + SET approved = NOW() + WHERE id = $1 AND approved IS NULL + ", + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if status.is_searchable() && !project_item.inner.webhook_sent { + if let Ok(webhook_url) = dotenvy::var("PUBLIC_DISCORD_WEBHOOK") { + crate::util::webhook::send_discord_webhook( + project_item.inner.id.into(), + &pool, + &redis, + webhook_url, + None, + ) + .await + .ok(); + + sqlx::query!( + " + UPDATE mods + SET webhook_sent = TRUE + WHERE id = $1 + ", + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + } + + if user.role.is_mod() { + if let Ok(webhook_url) = dotenvy::var("MODERATION_SLACK_WEBHOOK") { + crate::util::webhook::send_slack_webhook( + project_item.inner.id.into(), + &pool, + &redis, + webhook_url, + Some( + format!( + "*<{}/user/{}|{}>* changed project status from *{}* to *{}*", + dotenvy::var("SITE_URL")?, + user.username, + user.username, + &project_item.inner.status.as_friendly_str(), + status.as_friendly_str(), + ) + .to_string(), + ), + ) + .await + .ok(); + } + } + + if team_member.is_none_or(|x| !x.accepted) { + let notified_members = sqlx::query!( + " + SELECT tm.user_id id + FROM team_members tm + WHERE tm.team_id = $1 AND tm.accepted + ", + project_item.inner.team_id as db_ids::DBTeamId + ) + .fetch(&mut *transaction) + .map_ok(|c| db_models::DBUserId(c.id)) + .try_collect::>() + .await?; + + NotificationBuilder { + body: NotificationBody::StatusChange { + project_id: project_item.inner.id.into(), + old_status: project_item.inner.status, + new_status: *status, + }, + } + .insert_many(notified_members, &mut transaction, &redis) + .await?; + } + + ThreadMessageBuilder { + author_id: Some(user.id.into()), + body: MessageBody::StatusChange { + new_status: *status, + old_status: project_item.inner.status, + }, + thread_id: project_item.thread_id, + hide_identity: user.role.is_mod(), + } + .insert(&mut transaction) + .await?; + + sqlx::query!( + " + UPDATE mods + SET status = $1 + WHERE (id = $2) + ", + status.as_str(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(requested_status) = &new_project.requested_status { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the requested status of this project!" + .to_string(), + )); + } + + if !requested_status + .map(|x| x.can_be_requested()) + .unwrap_or(true) + { + return Err(ApiError::InvalidInput(String::from( + "Specified status cannot be requested!", + ))); + } + + sqlx::query!( + " + UPDATE mods + SET requested_status = $1 + WHERE (id = $2) + ", + requested_status.map(|x| x.as_str()), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if perms.contains(ProjectPermissions::EDIT_DETAILS) { + if new_project.categories.is_some() { + sqlx::query!( + " + DELETE FROM mods_categories + WHERE joining_mod_id = $1 AND is_additional = FALSE + ", + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if new_project.additional_categories.is_some() { + sqlx::query!( + " + DELETE FROM mods_categories + WHERE joining_mod_id = $1 AND is_additional = TRUE + ", + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + } + + if let Some(categories) = &new_project.categories { + edit_project_categories( + categories, + &perms, + id as db_ids::DBProjectId, + false, + &mut transaction, + ) + .await?; + } + + if let Some(categories) = &new_project.additional_categories { + edit_project_categories( + categories, + &perms, + id as db_ids::DBProjectId, + true, + &mut transaction, + ) + .await?; + } + + if let Some(license_url) = &new_project.license_url { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the license URL of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET license_url = $1 + WHERE (id = $2) + ", + license_url.as_deref(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(slug) = &new_project.slug { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the slug of this project!" + .to_string(), + )); + } + + let slug_project_id_option: Option = parse_base62(slug).ok(); + if let Some(slug_project_id) = slug_project_id_option { + let results = sqlx::query!( + " + SELECT EXISTS(SELECT 1 FROM mods WHERE id=$1) + ", + slug_project_id as i64 + ) + .fetch_one(&mut *transaction) + .await?; + + if results.exists.unwrap_or(true) { + return Err(ApiError::InvalidInput( + "Slug collides with other project's id!".to_string(), + )); + } + } + + // Make sure the new slug is different from the old one + // We are able to unwrap here because the slug is always set + if !slug.eq(&project_item.inner.slug.clone().unwrap_or_default()) { + let results = sqlx::query!( + " + SELECT EXISTS(SELECT 1 FROM mods WHERE slug = LOWER($1)) + ", + slug + ) + .fetch_one(&mut *transaction) + .await?; + + if results.exists.unwrap_or(true) { + return Err(ApiError::InvalidInput( + "Slug collides with other project's id!".to_string(), + )); + } + } + + sqlx::query!( + " + UPDATE mods + SET slug = LOWER($1) + WHERE (id = $2) + ", + Some(slug), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(license) = &new_project.license_id { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the license of this project!" + .to_string(), + )); + } + + let mut license = license.clone(); + + if license.to_lowercase() == "arr" { + license = models::projects::DEFAULT_LICENSE_ID.to_string(); + } + + spdx::Expression::parse(&license).map_err(|err| { + ApiError::InvalidInput(format!( + "Invalid SPDX license identifier: {err}" + )) + })?; + + sqlx::query!( + " + UPDATE mods + SET license = $1 + WHERE (id = $2) + ", + license, + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(links) = &new_project.link_urls { + if !links.is_empty() { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the links of this project!" + .to_string(), + )); + } + + let ids_to_delete = links.keys().cloned().collect::>(); + // Deletes all links from hashmap- either will be deleted or be replaced + sqlx::query!( + " + DELETE FROM mods_links + WHERE joining_mod_id = $1 AND joining_platform_id IN ( + SELECT id FROM link_platforms WHERE name = ANY($2) + ) + ", + id as db_ids::DBProjectId, + &ids_to_delete + ) + .execute(&mut *transaction) + .await?; + + for (platform, url) in links { + if let Some(url) = url { + let platform_id = + db_models::categories::LinkPlatform::get_id( + platform, + &mut *transaction, + ) + .await? + .ok_or_else(|| { + ApiError::InvalidInput(format!( + "Platform {} does not exist.", + platform.clone() + )) + })?; + sqlx::query!( + " + INSERT INTO mods_links (joining_mod_id, joining_platform_id, url) + VALUES ($1, $2, $3) + ", + id as db_ids::DBProjectId, + platform_id as db_ids::LinkPlatformId, + url + ) + .execute(&mut *transaction) + .await?; + } + } + } + } + if let Some(moderation_message) = &new_project.moderation_message { + if !user.role.is_mod() + && (!project_item.inner.status.is_approved() + || moderation_message.is_some()) + { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the moderation message of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET moderation_message = $1 + WHERE (id = $2) + ", + moderation_message.as_deref(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(moderation_message_body) = &new_project.moderation_message_body + { + if !user.role.is_mod() + && (!project_item.inner.status.is_approved() + || moderation_message_body.is_some()) + { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the moderation message body of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET moderation_message_body = $1 + WHERE (id = $2) + ", + moderation_message_body.as_deref(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(description) = &new_project.description { + if !perms.contains(ProjectPermissions::EDIT_BODY) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the description (body) of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET description = $1 + WHERE (id = $2) + ", + description, + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + if let Some(monetization_status) = &new_project.monetization_status { + if !perms.contains(ProjectPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the monetization status of this project!" + .to_string(), + )); + } + + if (*monetization_status == MonetizationStatus::ForceDemonetized + || project_item.inner.monetization_status + == MonetizationStatus::ForceDemonetized) + && !user.role.is_mod() + { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the monetization status of this project!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE mods + SET monetization_status = $1 + WHERE (id = $2) + ", + monetization_status.as_str(), + id as db_ids::DBProjectId, + ) + .execute(&mut *transaction) + .await?; + } + + // check new description and body for links to associated images + // if they no longer exist in the description or body, delete them + let checkable_strings: Vec<&str> = + vec![&new_project.description, &new_project.summary] + .into_iter() + .filter_map(|x| x.as_ref().map(|y| y.as_str())) + .collect(); + + let context = ImageContext::Project { + project_id: Some(id.into()), + }; + + img::delete_unused_images( + context, + checkable_strings, + &mut transaction, + &redis, + ) + .await?; + + transaction.commit().await?; + + db_models::DBProject::clear_cache( + project_item.inner.id, + project_item.inner.slug, + None, + &redis, + ) + .await?; + + // Remove no longer searchable projects from search index + if let (true, Some(false)) = ( + project_item.inner.status.is_searchable(), + new_project.status.map(|status| status.is_searchable()), + ) { + remove_documents( + &project_item + .versions + .into_iter() + .map(|x| x.into()) + .collect::>(), + &search_config, + ) + .await?; + } + + Ok(HttpResponse::NoContent().body("")) } pub async fn edit_project_categories( diff --git a/apps/labrinth/src/routes/v3/versions.rs b/apps/labrinth/src/routes/v3/versions.rs index 90f44579b..5a921a52f 100644 --- a/apps/labrinth/src/routes/v3/versions.rs +++ b/apps/labrinth/src/routes/v3/versions.rs @@ -958,7 +958,7 @@ pub async fn version_delete( ) .await?; transaction.commit().await?; - remove_documents(&[version.inner.id.into()], &search_config).await?; + database::models::DBProject::clear_cache( version.inner.project_id, None, @@ -966,6 +966,7 @@ pub async fn version_delete( &redis, ) .await?; + remove_documents(&[version.inner.id.into()], &search_config).await?; if result.is_some() { Ok(HttpResponse::NoContent().body("")) diff --git a/apps/labrinth/src/search/indexing/mod.rs b/apps/labrinth/src/search/indexing/mod.rs index 3f4dcdee9..e38864ec5 100644 --- a/apps/labrinth/src/search/indexing/mod.rs +++ b/apps/labrinth/src/search/indexing/mod.rs @@ -1,9 +1,13 @@ /// This module is used for the indexing from any source. pub mod local_import; +use std::time::Duration; + use crate::database::redis::RedisPool; use crate::search::{SearchConfig, UploadSearchProject}; use ariadne::ids::base62_impl::to_base62; +use futures::StreamExt; +use futures::stream::FuturesUnordered; use local_import::index_local; use meilisearch_sdk::client::{Client, SwapIndexes}; use meilisearch_sdk::indexes::Index; @@ -11,6 +15,7 @@ use meilisearch_sdk::settings::{PaginationSetting, Settings}; use sqlx::postgres::PgPool; use thiserror::Error; use tracing::info; + #[derive(Error, Debug)] pub enum IndexingError { #[error("Error while connecting to the MeiliSearch database")] @@ -41,12 +46,30 @@ pub async fn remove_documents( let mut indexes_next = get_indexes_for_indexing(config, true).await?; indexes.append(&mut indexes_next); - for index in indexes { - index - .delete_documents( - &ids.iter().map(|x| to_base62(x.0)).collect::>(), - ) - .await?; + let client = config.make_client()?; + let client = &client; + let mut deletion_tasks = FuturesUnordered::new(); + + for index in &indexes { + deletion_tasks.push(async move { + // After being successfully submitted, Meilisearch tasks are executed + // asynchronously, so wait some time for them to complete + index + .delete_documents( + &ids.iter().map(|x| to_base62(x.0)).collect::>(), + ) + .await? + .wait_for_completion( + client, + None, + Some(Duration::from_secs(15)), + ) + .await + }); + } + + while let Some(result) = deletion_tasks.next().await { + result?; } Ok(()) diff --git a/apps/labrinth/tests/search.rs b/apps/labrinth/tests/search.rs index 33e9d84c3..d8aefc493 100644 --- a/apps/labrinth/tests/search.rs +++ b/apps/labrinth/tests/search.rs @@ -151,22 +151,7 @@ async fn index_swaps() { test_env.api.remove_project("alpha", USER_USER_PAT).await; assert_status!(&resp, StatusCode::NO_CONTENT); - // Deletions should not be indexed immediately - let projects = test_env - .api - .search_deserialized( - None, - Some(json!([["categories:fabric"]])), - USER_USER_PAT, - ) - .await; - assert_eq!(projects.total_hits, 1); - assert!(projects.hits[0].slug.as_ref().unwrap().contains("alpha")); - - // But when we reindex, it should be gone - let resp = test_env.api.reset_search_index().await; - assert_status!(&resp, StatusCode::NO_CONTENT); - + // We should wait for deletions to be indexed let projects = test_env .api .search_deserialized( @@ -177,7 +162,7 @@ async fn index_swaps() { .await; assert_eq!(projects.total_hits, 0); - // Reindex again, should still be gone + // When we reindex, it should be still gone let resp = test_env.api.reset_search_index().await; assert_status!(&resp, StatusCode::NO_CONTENT);