You've already forked AstralRinth
forked from didirus/AstralRinth
Bulk Editing + Random Projects Route (#517)
* Bulk Editing + Random Projects Route * Run fmt + clippy + prepare * Remove license_url
This commit is contained in:
6
.idea/sqldialects.xml
generated
Normal file
6
.idea/sqldialects.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="SqlDialectMappings">
|
||||||
|
<file url="file://$PROJECT_DIR$/migrations/20230104214503_random-projects.sql" dialect="PostgreSQL" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
4
migrations/20230104214503_random-projects.sql
Normal file
4
migrations/20230104214503_random-projects.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- Add migration script here
|
||||||
|
DROP EXTENSION IF EXISTS tsm_system_rows;
|
||||||
|
|
||||||
|
CREATE EXTENSION tsm_system_rows;
|
||||||
183
sqlx-data.json
183
sqlx-data.json
@@ -992,6 +992,27 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM donation_platforms\n WHERE short = $1\n "
|
"query": "\n DELETE FROM donation_platforms\n WHERE short = $1\n "
|
||||||
},
|
},
|
||||||
|
"1cefe4924d3c1f491739858ce844a22903d2dbe26f255219299f1833a10ce3d7": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"name": "id",
|
||||||
|
"ordinal": 0,
|
||||||
|
"type_info": "Int8"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nullable": [
|
||||||
|
false
|
||||||
|
],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"TextArray"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n SELECT id FROM mods TABLESAMPLE SYSTEM_ROWS($1) WHERE status = ANY($2)\n "
|
||||||
|
},
|
||||||
"1d1fe6f0c03a63b1c6bd5ffbddfd82aa7d24e1db3f3137ed046724cb78929f88": {
|
"1d1fe6f0c03a63b1c6bd5ffbddfd82aa7d24e1db3f3137ed046724cb78929f88": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -1085,19 +1106,6 @@
|
|||||||
},
|
},
|
||||||
"query": "SELECT EXISTS(SELECT 1 FROM versions WHERE id=$1)"
|
"query": "SELECT EXISTS(SELECT 1 FROM versions WHERE id=$1)"
|
||||||
},
|
},
|
||||||
"20061dd085656ec83b63d893c60bdd3dcbf5b8c78a725358aa8e3312a7571e5c": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8",
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n UPDATE mods\n SET flame_anvil_user = $1\n WHERE (id = $2)\n "
|
|
||||||
},
|
|
||||||
"20413fce27fe9c1dec71900f9563e787acc11e7789b5294786e0ea6f20d7d958": {
|
"20413fce27fe9c1dec71900f9563e787acc11e7789b5294786e0ea6f20d7d958": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -1416,6 +1424,18 @@
|
|||||||
},
|
},
|
||||||
"query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.date_published date_published, v.downloads downloads,\n v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status,\n JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions,\n ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,\n JSONB_AGG(DISTINCT jsonb_build_object('id', f.id, 'url', f.url, 'filename', f.filename, 'primary', f.is_primary, 'size', f.size, 'file_type', f.file_type)) filter (where f.id is not null) files,\n JSONB_AGG(DISTINCT jsonb_build_object('algorithm', h.algorithm, 'hash', encode(h.hash, 'escape'), 'file_id', h.file_id)) filter (where h.hash is not null) hashes,\n JSONB_AGG(DISTINCT jsonb_build_object('project_id', d.mod_dependency_id, 'version_id', d.dependency_id, 'dependency_type', d.dependency_type,'file_name', dependency_file_name)) filter (where d.dependency_type is not null) dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = $1\n GROUP BY v.id;\n "
|
"query": "\n SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number,\n v.changelog changelog, v.date_published date_published, v.downloads downloads,\n v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status,\n JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions,\n ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,\n JSONB_AGG(DISTINCT jsonb_build_object('id', f.id, 'url', f.url, 'filename', f.filename, 'primary', f.is_primary, 'size', f.size, 'file_type', f.file_type)) filter (where f.id is not null) files,\n JSONB_AGG(DISTINCT jsonb_build_object('algorithm', h.algorithm, 'hash', encode(h.hash, 'escape'), 'file_id', h.file_id)) filter (where h.hash is not null) hashes,\n JSONB_AGG(DISTINCT jsonb_build_object('project_id', d.mod_dependency_id, 'version_id', d.dependency_id, 'dependency_type', d.dependency_type,'file_name', dependency_file_name)) filter (where d.dependency_type is not null) dependencies\n FROM versions v\n LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id\n LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv on v.id = lv.version_id\n LEFT OUTER JOIN loaders l on lv.loader_id = l.id\n LEFT OUTER JOIN files f on v.id = f.version_id\n LEFT OUTER JOIN hashes h on f.id = h.file_id\n LEFT OUTER JOIN dependencies d on v.id = d.dependent_id\n WHERE v.id = $1\n GROUP BY v.id;\n "
|
||||||
},
|
},
|
||||||
|
"299b8ea6e7a0048fa389cc4432715dc2a09e227d2f08e91167a43372a7ac6e35": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = FALSE\n "
|
||||||
|
},
|
||||||
"29e657d26f0fb24a766f5b5eb6a94d01d1616884d8ca10e91536e974d5b585a6": {
|
"29e657d26f0fb24a766f5b5eb6a94d01d1616884d8ca10e91536e974d5b585a6": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -1887,6 +1907,18 @@
|
|||||||
},
|
},
|
||||||
"query": "\n INSERT INTO game_versions_versions (game_version_id, joining_version_id)\n VALUES ($1, $2)\n "
|
"query": "\n INSERT INTO game_versions_versions (game_version_id, joining_version_id)\n VALUES ($1, $2)\n "
|
||||||
},
|
},
|
||||||
|
"3fcfed18cbfb37866e0fa57a4e95efb326864f8219941d1b696add39ed333ad1": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = TRUE\n "
|
||||||
|
},
|
||||||
"40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08": {
|
"40f7c5bec98fe3503d6bd6db2eae5a4edb8d5d6efda9b9dc124f344ae5c60e08": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -2151,6 +2183,18 @@
|
|||||||
},
|
},
|
||||||
"query": "\n INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id)\n VALUES ($1, $2)\n "
|
"query": "\n INSERT INTO loaders_project_types (joining_loader_id, joining_project_type_id)\n VALUES ($1, $2)\n "
|
||||||
},
|
},
|
||||||
|
"4567790f0dc98ff20b596a33161d1f6ac8af73da67fe8c54192724626c6bf670": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n DELETE FROM mods_donations\n WHERE joining_mod_id = $1\n "
|
||||||
|
},
|
||||||
"4778d2f5994fda2f978fa53e0840c1a9a2582ef0434a5ff7f21706f1dc4edcf4": {
|
"4778d2f5994fda2f978fa53e0840c1a9a2582ef0434a5ff7f21706f1dc4edcf4": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -3751,6 +3795,19 @@
|
|||||||
},
|
},
|
||||||
"query": "\n INSERT INTO notifications_actions (\n notification_id, title, action_route, action_route_method\n )\n VALUES (\n $1, $2, $3, $4\n )\n "
|
"query": "\n INSERT INTO notifications_actions (\n notification_id, title, action_route, action_route_method\n )\n VALUES (\n $1, $2, $3, $4\n )\n "
|
||||||
},
|
},
|
||||||
|
"83d428e1c07d16e356ef26bdf1d707940b1683b5f631ded1f6674a081453d67b": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n UPDATE mods\n SET source_url = $1\n WHERE (id = $2)\n "
|
||||||
|
},
|
||||||
"85b40877c48fc4f23039c1b556007f92056a015f160fe1059b0d3b13615af0fb": {
|
"85b40877c48fc4f23039c1b556007f92056a015f160fe1059b0d3b13615af0fb": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -3974,6 +4031,19 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM payouts_values\n WHERE user_id = $1\n "
|
"query": "\n DELETE FROM payouts_values\n WHERE user_id = $1\n "
|
||||||
},
|
},
|
||||||
|
"8abb317c85f48c7dd9ccf4a7b8fbc0b58ac73f7ae87ff2dfe67009a51089f784": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n UPDATE mods\n SET wiki_url = $1\n WHERE (id = $2)\n "
|
||||||
|
},
|
||||||
"8ba2b2c38958f1c542e514fc62ab4682f58b0b442ac1842d20625420698e34ec": {
|
"8ba2b2c38958f1c542e514fc62ab4682f58b0b442ac1842d20625420698e34ec": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -4138,6 +4208,20 @@
|
|||||||
},
|
},
|
||||||
"query": "\n UPDATE mods\n SET wiki_url = $1\n WHERE (id = $2)\n "
|
"query": "\n UPDATE mods\n SET wiki_url = $1\n WHERE (id = $2)\n "
|
||||||
},
|
},
|
||||||
|
"9aab2350d576fd934b0541d1f71f320ac939b44a179fee3d1638113cdb3ddfe7": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"Int4",
|
||||||
|
"Varchar"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n INSERT INTO mods_donations (joining_mod_id, joining_platform_id, url)\n VALUES ($1, $2, $3)\n "
|
||||||
|
},
|
||||||
"9c8f3f9503b5bb52e05bbc8a8eee7f640ab7d6b04a59ec111ce8b23e886911de": {
|
"9c8f3f9503b5bb52e05bbc8a8eee7f640ab7d6b04a59ec111ce8b23e886911de": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -4965,19 +5049,6 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM users\n WHERE id = $1\n "
|
"query": "\n DELETE FROM users\n WHERE id = $1\n "
|
||||||
},
|
},
|
||||||
"b69b18b3451762fc24a1390dd537f612ed066bd285e8237a99fb998ff9d066e9": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [],
|
|
||||||
"nullable": [],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int4",
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n UPDATE mods\n SET flame_anvil_project = $1\n WHERE (id = $2)\n "
|
|
||||||
},
|
|
||||||
"b7b2b5b99340c7601de53cc33dc56af054b50b2fe4d1d212901c958115a42baa": {
|
"b7b2b5b99340c7601de53cc33dc56af054b50b2fe4d1d212901c958115a42baa": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -5076,6 +5147,19 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM notifications_actions\n WHERE notification_id = ANY($1)\n "
|
"query": "\n DELETE FROM notifications_actions\n WHERE notification_id = ANY($1)\n "
|
||||||
},
|
},
|
||||||
|
"bad7cae347771e801976c26f2afaf33bda371051923b8f74a2f32a0ef5c65e57": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n UPDATE mods\n SET discord_url = $1\n WHERE (id = $2)\n "
|
||||||
|
},
|
||||||
"bbfb47ae2c972734785df6b7c3e62077dc544ef4ccf8bb89e9c22c2f50a933c1": {
|
"bbfb47ae2c972734785df6b7c3e62077dc544ef4ccf8bb89e9c22c2f50a933c1": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -5825,6 +5909,19 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM hashes\n WHERE file_id = $1\n "
|
"query": "\n DELETE FROM hashes\n WHERE file_id = $1\n "
|
||||||
},
|
},
|
||||||
|
"cdf20036b29b61da40bf990c9ab04c509297a4d65bc9b136c9fb20f1e97e1149": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Int8",
|
||||||
|
"Int4"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)\n VALUES ($1, $2, FALSE)\n "
|
||||||
|
},
|
||||||
"ce46915d4ce10f3fc2d4328157b06016da838672c8336b3b8d27e09eeec979d3": {
|
"ce46915d4ce10f3fc2d4328157b06016da838672c8336b3b8d27e09eeec979d3": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -6796,6 +6893,19 @@
|
|||||||
},
|
},
|
||||||
"query": "\n DELETE FROM files\n WHERE files.id = $1\n "
|
"query": "\n DELETE FROM files\n WHERE files.id = $1\n "
|
||||||
},
|
},
|
||||||
|
"e3fb74a94a6a78b1007dd99ad11bdcfaa0957ed7d1683997aef7301e0f15baba": {
|
||||||
|
"describe": {
|
||||||
|
"columns": [],
|
||||||
|
"nullable": [],
|
||||||
|
"parameters": {
|
||||||
|
"Left": [
|
||||||
|
"Varchar",
|
||||||
|
"Int8"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"query": "\n UPDATE mods\n SET issues_url = $1\n WHERE (id = $2)\n "
|
||||||
|
},
|
||||||
"e42d3a64ae4d88b73136a319fe79a8b070c193707e3560d18deca478662d8d90": {
|
"e42d3a64ae4d88b73136a319fe79a8b070c193707e3560d18deca478662d8d90": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
@@ -6967,27 +7077,6 @@
|
|||||||
},
|
},
|
||||||
"query": "\n SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id AND v.status != ANY($1)\n INNER JOIN mods m on v.mod_id = m.id\n WHERE h.algorithm = $3 AND h.hash = ANY($2::bytea[]) AND m.status != ANY($4)\n "
|
"query": "\n SELECT f.url url, h.hash hash, h.algorithm algorithm, f.version_id version_id, v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id AND v.status != ANY($1)\n INNER JOIN mods m on v.mod_id = m.id\n WHERE h.algorithm = $3 AND h.hash = ANY($2::bytea[]) AND m.status != ANY($4)\n "
|
||||||
},
|
},
|
||||||
"e5de3b33893b6b48a7fee0e3f20e371e56fdfd71640662aacc15fe3bf747b3a1": {
|
|
||||||
"describe": {
|
|
||||||
"columns": [
|
|
||||||
{
|
|
||||||
"name": "exists",
|
|
||||||
"ordinal": 0,
|
|
||||||
"type_info": "Bool"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nullable": [
|
|
||||||
null
|
|
||||||
],
|
|
||||||
"parameters": {
|
|
||||||
"Left": [
|
|
||||||
"Int8",
|
|
||||||
"Int8"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"query": "\n SELECT EXISTS(\n SELECT 1 FROM team_members\n INNER JOIN users u on team_members.user_id = u.id AND u.flame_anvil_key IS NOT NULL\n WHERE team_id = $1 AND user_id = $2 AND accepted = TRUE\n )\n "
|
|
||||||
},
|
|
||||||
"e673006d1355fa91ba5739d7cf569eec5e1ec501f7b1dc2b431f0b1c25ac07d5": {
|
"e673006d1355fa91ba5739d7cf569eec5e1ec501f7b1dc2b431f0b1c25ac07d5": {
|
||||||
"describe": {
|
"describe": {
|
||||||
"columns": [],
|
"columns": [],
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ generate_ids!(
|
|||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
pub struct UserId(pub i64);
|
pub struct UserId(pub i64);
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Type)]
|
#[derive(Copy, Clone, Debug, Type, Eq, PartialEq)]
|
||||||
#[sqlx(transparent)]
|
#[sqlx(transparent)]
|
||||||
pub struct TeamId(pub i64);
|
pub struct TeamId(pub i64);
|
||||||
#[derive(Copy, Clone, Debug, Type)]
|
#[derive(Copy, Clone, Debug, Type)]
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ impl Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_many_full<'a, E>(
|
pub async fn get_many_full<'a, E>(
|
||||||
project_ids: Vec<ProjectId>,
|
project_ids: &[ProjectId],
|
||||||
exec: E,
|
exec: E,
|
||||||
) -> Result<Vec<QueryProject>, sqlx::Error>
|
) -> Result<Vec<QueryProject>, sqlx::Error>
|
||||||
where
|
where
|
||||||
@@ -793,7 +793,7 @@ impl Project {
|
|||||||
use futures::TryStreamExt;
|
use futures::TryStreamExt;
|
||||||
|
|
||||||
let project_ids_parsed: Vec<i64> =
|
let project_ids_parsed: Vec<i64> =
|
||||||
project_ids.into_iter().map(|x| x.0).collect();
|
project_ids.iter().map(|x| x.0).collect();
|
||||||
sqlx::query!(
|
sqlx::query!(
|
||||||
"
|
"
|
||||||
SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,
|
SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ pub struct License {
|
|||||||
pub url: Option<String>,
|
pub url: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Validate, Clone)]
|
#[derive(Serialize, Deserialize, Validate, Clone, Eq, PartialEq)]
|
||||||
pub struct DonationLink {
|
pub struct DonationLink {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub platform: String,
|
pub platform: String,
|
||||||
|
|||||||
@@ -53,6 +53,8 @@ pub fn v2_config(cfg: &mut web::ServiceConfig) {
|
|||||||
pub fn projects_config(cfg: &mut web::ServiceConfig) {
|
pub fn projects_config(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(projects::project_search);
|
cfg.service(projects::project_search);
|
||||||
cfg.service(projects::projects_get);
|
cfg.service(projects::projects_get);
|
||||||
|
cfg.service(projects::projects_edit);
|
||||||
|
cfg.service(projects::random_projects_get);
|
||||||
cfg.service(project_creation::project_create);
|
cfg.service(project_creation::project_create);
|
||||||
|
|
||||||
cfg.service(
|
cfg.service(
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ pub async fn get_projects(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let projects: Vec<_> =
|
let projects: Vec<_> =
|
||||||
database::Project::get_many_full(project_ids, &**pool)
|
database::Project::get_many_full(&project_ids, &**pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(crate::models::projects::Project::from)
|
.map(crate::models::projects::Project::from)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use crate::database;
|
|||||||
use crate::database::models::notification_item::NotificationBuilder;
|
use crate::database::models::notification_item::NotificationBuilder;
|
||||||
use crate::file_hosting::FileHost;
|
use crate::file_hosting::FileHost;
|
||||||
use crate::models;
|
use crate::models;
|
||||||
use crate::models::ids::UserId;
|
|
||||||
use crate::models::projects::{
|
use crate::models::projects::{
|
||||||
DonationLink, Project, ProjectId, ProjectStatus, SearchRequest, SideType,
|
DonationLink, Project, ProjectId, ProjectStatus, SearchRequest, SideType,
|
||||||
};
|
};
|
||||||
@@ -30,6 +29,45 @@ pub async fn project_search(
|
|||||||
Ok(HttpResponse::Ok().json(results))
|
Ok(HttpResponse::Ok().json(results))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Validate)]
|
||||||
|
pub struct RandomProjects {
|
||||||
|
#[validate(range(min = 1, max = 100))]
|
||||||
|
pub count: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[get("projects_random")]
|
||||||
|
pub async fn random_projects_get(
|
||||||
|
web::Query(count): web::Query<RandomProjects>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
|
count.validate().map_err(|err| {
|
||||||
|
ApiError::Validation(validation_errors_to_string(err, None))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let project_ids = sqlx::query!(
|
||||||
|
"
|
||||||
|
SELECT id FROM mods TABLESAMPLE SYSTEM_ROWS($1) WHERE status = ANY($2)
|
||||||
|
",
|
||||||
|
count.count as i32,
|
||||||
|
&*crate::models::projects::ProjectStatus::iterator().filter(|x| x.is_searchable()).map(|x| x.to_string()).collect::<Vec<String>>(),
|
||||||
|
)
|
||||||
|
.fetch_many(&**pool)
|
||||||
|
.try_filter_map(|e| async {
|
||||||
|
Ok(e.right().map(|m| database::models::ids::ProjectId(m.id)))
|
||||||
|
})
|
||||||
|
.try_collect::<Vec<_>>()
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let projects_data =
|
||||||
|
database::models::Project::get_many_full(&project_ids, &**pool)
|
||||||
|
.await?
|
||||||
|
.into_iter()
|
||||||
|
.map(Project::from)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(projects_data))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ProjectIds {
|
pub struct ProjectIds {
|
||||||
pub ids: String,
|
pub ids: String,
|
||||||
@@ -41,13 +79,14 @@ pub async fn projects_get(
|
|||||||
web::Query(ids): web::Query<ProjectIds>,
|
web::Query(ids): web::Query<ProjectIds>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
) -> Result<HttpResponse, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let project_ids = serde_json::from_str::<Vec<ProjectId>>(&ids.ids)?
|
let project_ids: Vec<database::models::ids::ProjectId> =
|
||||||
.into_iter()
|
serde_json::from_str::<Vec<ProjectId>>(&ids.ids)?
|
||||||
.map(|x| x.into())
|
.into_iter()
|
||||||
.collect();
|
.map(|x| x.into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let projects_data =
|
let projects_data =
|
||||||
database::models::Project::get_many_full(project_ids, &**pool).await?;
|
database::models::Project::get_many_full(&project_ids, &**pool).await?;
|
||||||
|
|
||||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
@@ -207,22 +246,23 @@ pub async fn dependency_list(
|
|||||||
)>>()
|
)>>()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let (projects_result, versions_result) = futures::join!(
|
let project_ids = dependencies
|
||||||
database::Project::get_many_full(
|
.iter()
|
||||||
dependencies
|
.filter_map(|x| {
|
||||||
.iter()
|
if x.0.is_none() {
|
||||||
.filter_map(|x| if x.0.is_none() {
|
if let Some(mod_dependency_id) = x.2 {
|
||||||
if let Some(mod_dependency_id) = x.2 {
|
Some(mod_dependency_id)
|
||||||
Some(mod_dependency_id)
|
|
||||||
} else {
|
|
||||||
x.1
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
x.1
|
x.1
|
||||||
})
|
}
|
||||||
.collect(),
|
} else {
|
||||||
&**pool,
|
x.1
|
||||||
),
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let (projects_result, versions_result) = futures::join!(
|
||||||
|
database::Project::get_many_full(&project_ids, &**pool,),
|
||||||
database::Version::get_many_full(
|
database::Version::get_many_full(
|
||||||
dependencies.iter().filter_map(|x| x.0).collect(),
|
dependencies.iter().filter_map(|x| x.0).collect(),
|
||||||
&**pool,
|
&**pool,
|
||||||
@@ -344,18 +384,6 @@ pub struct EditProject {
|
|||||||
)]
|
)]
|
||||||
#[validate(length(max = 65536))]
|
#[validate(length(max = 65536))]
|
||||||
pub moderation_message_body: Option<Option<String>>,
|
pub moderation_message_body: Option<Option<String>>,
|
||||||
#[serde(
|
|
||||||
default,
|
|
||||||
skip_serializing_if = "Option::is_none",
|
|
||||||
with = "::serde_with::rust::double_option"
|
|
||||||
)]
|
|
||||||
pub flame_anvil_user: Option<Option<UserId>>,
|
|
||||||
#[serde(
|
|
||||||
default,
|
|
||||||
skip_serializing_if = "Option::is_none",
|
|
||||||
with = "::serde_with::rust::double_option"
|
|
||||||
)]
|
|
||||||
pub flame_anvil_project: Option<Option<i32>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[patch("{id}")]
|
#[patch("{id}")]
|
||||||
@@ -1085,92 +1113,6 @@ pub async fn project_edit(
|
|||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(project) = &new_project.flame_anvil_project {
|
|
||||||
if !perms.contains(Permissions::EDIT_DETAILS) {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have the permissions to edit the external syncing project!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if project_item.project_type == "modpack" {
|
|
||||||
return Err(ApiError::InvalidInput(
|
|
||||||
"This project syncing feature is not available for modpacks!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
UPDATE mods
|
|
||||||
SET flame_anvil_project = $1
|
|
||||||
WHERE (id = $2)
|
|
||||||
",
|
|
||||||
*project,
|
|
||||||
id as database::models::ids::ProjectId,
|
|
||||||
)
|
|
||||||
.execute(&mut *transaction)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(user_id) = &new_project.flame_anvil_user {
|
|
||||||
if !perms.contains(Permissions::EDIT_DETAILS) {
|
|
||||||
return Err(ApiError::CustomAuthentication(
|
|
||||||
"You do not have the permissions to edit the syncing user for this project!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if project_item.project_type == "modpack" {
|
|
||||||
return Err(ApiError::InvalidInput(
|
|
||||||
"This project syncing feature is not available for modpacks!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(user_id) = user_id {
|
|
||||||
if user_id != &user.id && !user.role.is_admin() {
|
|
||||||
return Err(ApiError::InvalidInput(
|
|
||||||
"You may only set yourself as the syncing user!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let results = sqlx::query!(
|
|
||||||
"
|
|
||||||
SELECT EXISTS(
|
|
||||||
SELECT 1 FROM team_members
|
|
||||||
INNER JOIN users u on team_members.user_id = u.id AND u.flame_anvil_key IS NOT NULL
|
|
||||||
WHERE team_id = $1 AND user_id = $2 AND accepted = TRUE
|
|
||||||
)
|
|
||||||
",
|
|
||||||
project_item.inner.team_id as database::models::ids::TeamId,
|
|
||||||
database::models::ids::UserId::from(*user_id) as database::models::ids::UserId,
|
|
||||||
)
|
|
||||||
.fetch_one(&mut *transaction)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if !results.exists.unwrap_or(true) {
|
|
||||||
return Err(ApiError::InvalidInput(
|
|
||||||
"The given user is not part of your team or does not have a syncing key added to their account!"
|
|
||||||
.to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sqlx::query!(
|
|
||||||
"
|
|
||||||
UPDATE mods
|
|
||||||
SET flame_anvil_user = $1
|
|
||||||
WHERE (id = $2)
|
|
||||||
",
|
|
||||||
user_id.map(|x| x.0 as i64),
|
|
||||||
id as database::models::ids::ProjectId,
|
|
||||||
)
|
|
||||||
.execute(&mut *transaction)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction.commit().await?;
|
transaction.commit().await?;
|
||||||
Ok(HttpResponse::NoContent().body(""))
|
Ok(HttpResponse::NoContent().body(""))
|
||||||
} else {
|
} else {
|
||||||
@@ -1183,6 +1125,398 @@ pub async fn project_edit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Validate)]
|
||||||
|
pub struct BulkEditProject {
|
||||||
|
#[validate(length(max = 3))]
|
||||||
|
pub categories: Option<Vec<String>>,
|
||||||
|
#[validate(length(max = 3))]
|
||||||
|
pub add_categories: Option<Vec<String>>,
|
||||||
|
pub remove_categories: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[validate(length(max = 256))]
|
||||||
|
pub additional_categories: Option<Vec<String>>,
|
||||||
|
#[validate(length(max = 3))]
|
||||||
|
pub add_additional_categories: Option<Vec<String>>,
|
||||||
|
pub remove_additional_categories: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[validate]
|
||||||
|
pub donation_urls: Option<Vec<DonationLink>>,
|
||||||
|
#[validate]
|
||||||
|
pub add_donation_urls: Option<Vec<DonationLink>>,
|
||||||
|
#[validate]
|
||||||
|
pub remove_donation_urls: Option<Vec<DonationLink>>,
|
||||||
|
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
with = "::serde_with::rust::double_option"
|
||||||
|
)]
|
||||||
|
#[validate(
|
||||||
|
custom(function = "crate::util::validate::validate_url"),
|
||||||
|
length(max = 2048)
|
||||||
|
)]
|
||||||
|
pub issues_url: Option<Option<String>>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
with = "::serde_with::rust::double_option"
|
||||||
|
)]
|
||||||
|
#[validate(
|
||||||
|
custom(function = "crate::util::validate::validate_url"),
|
||||||
|
length(max = 2048)
|
||||||
|
)]
|
||||||
|
pub source_url: Option<Option<String>>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
with = "::serde_with::rust::double_option"
|
||||||
|
)]
|
||||||
|
#[validate(
|
||||||
|
custom(function = "crate::util::validate::validate_url"),
|
||||||
|
length(max = 2048)
|
||||||
|
)]
|
||||||
|
pub wiki_url: Option<Option<String>>,
|
||||||
|
#[serde(
|
||||||
|
default,
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
with = "::serde_with::rust::double_option"
|
||||||
|
)]
|
||||||
|
#[validate(
|
||||||
|
custom(function = "crate::util::validate::validate_url"),
|
||||||
|
length(max = 2048)
|
||||||
|
)]
|
||||||
|
pub discord_url: Option<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[patch("projects")]
|
||||||
|
pub async fn projects_edit(
|
||||||
|
req: HttpRequest,
|
||||||
|
web::Query(ids): web::Query<ProjectIds>,
|
||||||
|
pool: web::Data<PgPool>,
|
||||||
|
bulk_edit_project: web::Json<BulkEditProject>,
|
||||||
|
) -> Result<HttpResponse, ApiError> {
|
||||||
|
let user = get_user_from_headers(req.headers(), &**pool).await?;
|
||||||
|
|
||||||
|
bulk_edit_project.validate().map_err(|err| {
|
||||||
|
ApiError::Validation(validation_errors_to_string(err, None))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let project_ids: Vec<database::models::ids::ProjectId> =
|
||||||
|
serde_json::from_str::<Vec<ProjectId>>(&ids.ids)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|x| x.into())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let projects_data =
|
||||||
|
database::models::Project::get_many_full(&project_ids, &**pool).await?;
|
||||||
|
|
||||||
|
if let Some(id) = project_ids
|
||||||
|
.iter()
|
||||||
|
.find(|x| !projects_data.iter().any(|y| x == &&y.inner.id))
|
||||||
|
{
|
||||||
|
return Err(ApiError::InvalidInput(format!(
|
||||||
|
"Project {} not found",
|
||||||
|
ProjectId(id.0 as u64)
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let team_members = database::models::TeamMember::get_from_team_full_many(
|
||||||
|
projects_data.iter().map(|x| x.inner.team_id).collect(),
|
||||||
|
&**pool,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let categories =
|
||||||
|
database::models::categories::Category::list(&**pool).await?;
|
||||||
|
let donation_platforms =
|
||||||
|
database::models::categories::DonationPlatform::list(&**pool).await?;
|
||||||
|
|
||||||
|
let mut transaction = pool.begin().await?;
|
||||||
|
|
||||||
|
for project in projects_data {
|
||||||
|
if !user.role.is_mod() {
|
||||||
|
if let Some(member) = team_members
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.team_id == project.inner.team_id)
|
||||||
|
{
|
||||||
|
if !member.permissions.contains(Permissions::EDIT_DETAILS) {
|
||||||
|
return Err(ApiError::CustomAuthentication(
|
||||||
|
format!("You do not have the permissions to bulk edit project {}!", project.inner.title),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if project.inner.status.is_hidden() {
|
||||||
|
return Ok(HttpResponse::NotFound().body(""));
|
||||||
|
} else {
|
||||||
|
return Err(ApiError::CustomAuthentication(format!(
|
||||||
|
"You are not a member of project {}!",
|
||||||
|
project.inner.title
|
||||||
|
)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut set_categories =
|
||||||
|
if let Some(categories) = bulk_edit_project.categories.clone() {
|
||||||
|
categories
|
||||||
|
} else {
|
||||||
|
project.categories.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(delete_categories) = &bulk_edit_project.remove_categories {
|
||||||
|
for category in delete_categories {
|
||||||
|
if let Some(pos) =
|
||||||
|
set_categories.iter().position(|x| x == category)
|
||||||
|
{
|
||||||
|
set_categories.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(add_categories) = &bulk_edit_project.add_categories {
|
||||||
|
for category in add_categories {
|
||||||
|
if set_categories.len() < 3 {
|
||||||
|
set_categories.push(category.clone());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if set_categories != project.categories {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
DELETE FROM mods_categories
|
||||||
|
WHERE joining_mod_id = $1 AND is_additional = FALSE
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
for category in set_categories {
|
||||||
|
let category_id = categories
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.category == category)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ApiError::InvalidInput(format!(
|
||||||
|
"Category {} does not exist.",
|
||||||
|
category.clone()
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.id;
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)
|
||||||
|
VALUES ($1, $2, FALSE)
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
category_id as database::models::ids::CategoryId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut set_additional_categories = if let Some(categories) =
|
||||||
|
bulk_edit_project.additional_categories.clone()
|
||||||
|
{
|
||||||
|
categories
|
||||||
|
} else {
|
||||||
|
project.additional_categories.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(delete_categories) =
|
||||||
|
&bulk_edit_project.remove_additional_categories
|
||||||
|
{
|
||||||
|
for category in delete_categories {
|
||||||
|
if let Some(pos) =
|
||||||
|
set_additional_categories.iter().position(|x| x == category)
|
||||||
|
{
|
||||||
|
set_additional_categories.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(add_categories) =
|
||||||
|
&bulk_edit_project.add_additional_categories
|
||||||
|
{
|
||||||
|
for category in add_categories {
|
||||||
|
if set_additional_categories.len() < 256 {
|
||||||
|
set_additional_categories.push(category.clone());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if set_additional_categories != project.additional_categories {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
DELETE FROM mods_categories
|
||||||
|
WHERE joining_mod_id = $1 AND is_additional = TRUE
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
for category in set_additional_categories {
|
||||||
|
let category_id = categories
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.category == category)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ApiError::InvalidInput(format!(
|
||||||
|
"Category {} does not exist.",
|
||||||
|
category.clone()
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.id;
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)
|
||||||
|
VALUES ($1, $2, TRUE)
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
category_id as database::models::ids::CategoryId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let project_donations: Vec<DonationLink> = project
|
||||||
|
.donation_urls
|
||||||
|
.into_iter()
|
||||||
|
.map(|d| DonationLink {
|
||||||
|
id: d.platform_short,
|
||||||
|
platform: d.platform_name,
|
||||||
|
url: d.url,
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let mut set_donation_links = if let Some(donation_links) =
|
||||||
|
bulk_edit_project.donation_urls.clone()
|
||||||
|
{
|
||||||
|
donation_links
|
||||||
|
} else {
|
||||||
|
project_donations.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(delete_donations) = &bulk_edit_project.remove_donation_urls
|
||||||
|
{
|
||||||
|
for donation in delete_donations {
|
||||||
|
if let Some(pos) = set_donation_links
|
||||||
|
.iter()
|
||||||
|
.position(|x| donation.url == x.url && donation.id == x.id)
|
||||||
|
{
|
||||||
|
set_donation_links.remove(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(add_donations) = &bulk_edit_project.add_donation_urls {
|
||||||
|
set_donation_links.append(&mut add_donations.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
if set_donation_links != project_donations {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
DELETE FROM mods_donations
|
||||||
|
WHERE joining_mod_id = $1
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
for donation in set_donation_links {
|
||||||
|
let platform_id = donation_platforms
|
||||||
|
.iter()
|
||||||
|
.find(|x| x.short == donation.id)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
ApiError::InvalidInput(format!(
|
||||||
|
"Platform {} does not exist.",
|
||||||
|
donation.id.clone()
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.id;
|
||||||
|
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
INSERT INTO mods_donations (joining_mod_id, joining_platform_id, url)
|
||||||
|
VALUES ($1, $2, $3)
|
||||||
|
",
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
platform_id as database::models::ids::DonationPlatformId,
|
||||||
|
donation.url
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(issues_url) = &bulk_edit_project.issues_url {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
UPDATE mods
|
||||||
|
SET issues_url = $1
|
||||||
|
WHERE (id = $2)
|
||||||
|
",
|
||||||
|
issues_url.as_deref(),
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(source_url) = &bulk_edit_project.source_url {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
UPDATE mods
|
||||||
|
SET source_url = $1
|
||||||
|
WHERE (id = $2)
|
||||||
|
",
|
||||||
|
source_url.as_deref(),
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(wiki_url) = &bulk_edit_project.wiki_url {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
UPDATE mods
|
||||||
|
SET wiki_url = $1
|
||||||
|
WHERE (id = $2)
|
||||||
|
",
|
||||||
|
wiki_url.as_deref(),
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(discord_url) = &bulk_edit_project.discord_url {
|
||||||
|
sqlx::query!(
|
||||||
|
"
|
||||||
|
UPDATE mods
|
||||||
|
SET discord_url = $1
|
||||||
|
WHERE (id = $2)
|
||||||
|
",
|
||||||
|
discord_url.as_deref(),
|
||||||
|
project.inner.id as database::models::ids::ProjectId,
|
||||||
|
)
|
||||||
|
.execute(&mut *transaction)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transaction.commit().await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::NoContent().body(""))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct SchedulingData {
|
pub struct SchedulingData {
|
||||||
pub time: DateTime<Utc>,
|
pub time: DateTime<Utc>,
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ pub async fn projects_list(
|
|||||||
let project_data = User::get_projects(id, &**pool).await?;
|
let project_data = User::get_projects(id, &**pool).await?;
|
||||||
|
|
||||||
let response: Vec<_> =
|
let response: Vec<_> =
|
||||||
crate::database::Project::get_many_full(project_data, &**pool)
|
crate::database::Project::get_many_full(&project_data, &**pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|x| can_view_private || x.inner.status.is_approved())
|
.filter(|x| can_view_private || x.inner.status.is_approved())
|
||||||
@@ -600,7 +600,7 @@ pub async fn user_follows(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let projects: Vec<_> =
|
let projects: Vec<_> =
|
||||||
crate::database::Project::get_many_full(project_ids, &**pool)
|
crate::database::Project::get_many_full(&project_ids, &**pool)
|
||||||
.await?
|
.await?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Project::from)
|
.map(Project::from)
|
||||||
|
|||||||
@@ -91,14 +91,14 @@ pub async fn mods_get(
|
|||||||
ids: web::Query<ProjectIds>,
|
ids: web::Query<ProjectIds>,
|
||||||
pool: web::Data<PgPool>,
|
pool: web::Data<PgPool>,
|
||||||
) -> Result<HttpResponse, ApiError> {
|
) -> Result<HttpResponse, ApiError> {
|
||||||
let project_ids =
|
let project_ids: Vec<database::models::ids::ProjectId> =
|
||||||
serde_json::from_str::<Vec<models::ids::ProjectId>>(&ids.ids)?
|
serde_json::from_str::<Vec<models::ids::ProjectId>>(&ids.ids)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| x.into())
|
.map(|x| x.into())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let projects_data =
|
let projects_data =
|
||||||
database::models::Project::get_many_full(project_ids, &**pool).await?;
|
database::models::Project::get_many_full(&project_ids, &**pool).await?;
|
||||||
|
|
||||||
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
let user_option = get_user_from_headers(req.headers(), &**pool).await.ok();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user