From 4da1871567ff43d86a12136b9afc0443c1a5f24f Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Wed, 7 Dec 2022 09:56:53 -0700 Subject: [PATCH] Public Webhook Fixes (#493) * Public discord webhook * Switch to jsonb for most queries + make gallery featured first * Run fmt + clippy + prepare --- sqlx-data.json | 2346 +++++++++++----------- src/database/models/ids.rs | 12 +- src/database/models/notification_item.rs | 74 +- src/database/models/project_item.rs | 262 +-- src/database/models/version_item.rs | 342 ++-- src/routes/project_creation.rs | 4 +- src/routes/projects.rs | 7 +- src/routes/v1/mods.rs | 2 +- src/search/indexing/local_import.rs | 33 +- src/util/webhook.rs | 40 +- 10 files changed, 1456 insertions(+), 1666 deletions(-) diff --git a/sqlx-data.json b/sqlx-data.json index 7399f92c2..1da2e6185 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -433,74 +433,6 @@ }, "query": "\n UPDATE users\n SET email = $1\n WHERE (id = $2)\n " }, - "16fb3fafaed2fe122b7c5bb5d987b16dc12008441c8e07f76c9515639c801f0d": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "title", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "text", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "link", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamptz" - }, - { - "name": "read", - "ordinal": 6, - "type_info": "Bool" - }, - { - "name": "notification_type", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "actions", - "ordinal": 8, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - null - ], - "parameters": { - "Left": [ - "Int8Array" - ] - } - }, - "query": "\n SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.id = ANY($1)\n GROUP BY n.id, n.user_id\n ORDER BY n.created DESC;\n " - }, "19422e88b1b13318d75e8eb2ba142a562c550358b3136eef9ef73b5a216bbcdb": { "describe": { "columns": [ @@ -1602,6 +1534,128 @@ }, "query": "\n UPDATE users\n SET stripe_customer_id = NULL, midas_expires = NULL, is_overdue = NULL\n WHERE (stripe_customer_id = $1)\n " }, + "417361f7b1be4992b0684c6405c2fd339e3e4fd7afd02e6890f8b1a0ee4858d1": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "mod_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "author_id", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "version_name", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "version_number", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "changelog", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "changelog_url", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "date_published", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "downloads", + "ordinal": 8, + "type_info": "Int4" + }, + { + "name": "version_type", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "featured", + "ordinal": 10, + "type_info": "Bool" + }, + { + "name": "status", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "requested_status", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "game_versions", + "ordinal": 13, + "type_info": "Jsonb" + }, + { + "name": "loaders", + "ordinal": 14, + "type_info": "VarcharArray" + }, + { + "name": "files", + "ordinal": 15, + "type_info": "Jsonb" + }, + { + "name": "hashes", + "ordinal": 16, + "type_info": "Jsonb" + }, + { + "name": "dependencies", + "ordinal": 17, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + true, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "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.changelog_url changelog_url, 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 TO_JSONB(f)) 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 = ANY($1)\n GROUP BY v.id\n ORDER BY v.date_published ASC;\n " + }, "4298552497a48adb9ace61c8dcf989c4d35866866b61c0cc4d45909b1d31c660": { "describe": { "columns": [ @@ -2119,6 +2173,74 @@ }, "query": "\n DELETE FROM notifications\n WHERE id = ANY($1)\n " }, + "5a12149114c3f391e7a2ce23707759a3112454e605e50088312d3cf3088aeca2": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "title", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "text", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "link", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 5, + "type_info": "Timestamptz" + }, + { + "name": "read", + "ordinal": 6, + "type_info": "Bool" + }, + { + "name": "notification_type", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "actions", + "ordinal": 8, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + null + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.id = ANY($1)\n GROUP BY n.id, n.user_id\n ORDER BY n.created DESC;\n " + }, "5a13a79ebb1ab975f88b58e6deaba9685fe16e242c0fa4a5eea54f12f9448e6b": { "describe": { "columns": [], @@ -2245,154 +2367,6 @@ }, "query": "\n UPDATE users\n SET role = $1\n WHERE (id = $2)\n " }, - "5cb877179a4667a5c1d77354f53b010da1cccd4350e47333f16d0b4d22a861ea": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "project_type", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "title", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "description", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "downloads", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "follows", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "icon_url", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "published", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "approved", - "ordinal": 8, - "type_info": "Timestamptz" - }, - { - "name": "updated", - "ordinal": 9, - "type_info": "Timestamptz" - }, - { - "name": "team_id", - "ordinal": 10, - "type_info": "Int8" - }, - { - "name": "license", - "ordinal": 11, - "type_info": "Varchar" - }, - { - "name": "slug", - "ordinal": 12, - "type_info": "Varchar" - }, - { - "name": "status_name", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "client_side_type", - "ordinal": 14, - "type_info": "Varchar" - }, - { - "name": "server_side_type", - "ordinal": 15, - "type_info": "Varchar" - }, - { - "name": "project_type_name", - "ordinal": 16, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 17, - "type_info": "Varchar" - }, - { - "name": "categories", - "ordinal": 18, - "type_info": "TextArray" - }, - { - "name": "loaders", - "ordinal": 19, - "type_info": "VarcharArray" - }, - { - "name": "versions", - "ordinal": 20, - "type_info": "VarcharArray" - }, - { - "name": "gallery", - "ordinal": 21, - "type_info": "VarcharArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - false, - true, - false, - false, - false, - false, - false, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "TextArray", - "TextArray", - "Text" - ] - } - }, - "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.published published, m.approved approved, m.updated updated,\n m.team_id team_id, m.license license, m.slug slug, m.status status_name,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, u.username username,\n ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n ARRAY_AGG(DISTINCT gv.version) filter (where gv.version is not null) versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null) gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($1)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.status = ANY($2)\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " - }, "5d7425cfa91e332bf7cc14aa5c300b997e941c49757606f6b906cb5e060d3179": { "describe": { "columns": [], @@ -2448,74 +2422,6 @@ }, "query": "\n SELECT name FROM project_types\n " }, - "5f3f68b438571369e7fe6dba08935faa71e7f53fcdcb6d5b3c25feb15adc4f23": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "title", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "text", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "link", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 5, - "type_info": "Timestamptz" - }, - { - "name": "read", - "ordinal": 6, - "type_info": "Bool" - }, - { - "name": "notification_type", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "actions", - "ordinal": 8, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - true, - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.user_id = $1\n GROUP BY n.id, n.user_id;\n " - }, "5f94e9e767ec4be7f9136b991b4a29373dbe48feb2f61281e3212721095ed675": { "describe": { "columns": [], @@ -3168,6 +3074,243 @@ }, "query": "\n INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)\n VALUES ($1, $2, FALSE)\n " }, + "8003dd6d5d8a0102d3128753d1a568109f214db06a317abdd15c05200411d887": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "project_type", + "ordinal": 1, + "type_info": "Int4" + }, + { + "name": "title", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "downloads", + "ordinal": 4, + "type_info": "Int4" + }, + { + "name": "follows", + "ordinal": 5, + "type_info": "Int4" + }, + { + "name": "icon_url", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "body", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "body_url", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "published", + "ordinal": 9, + "type_info": "Timestamptz" + }, + { + "name": "updated", + "ordinal": 10, + "type_info": "Timestamptz" + }, + { + "name": "approved", + "ordinal": 11, + "type_info": "Timestamptz" + }, + { + "name": "status", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "requested_status", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "issues_url", + "ordinal": 14, + "type_info": "Varchar" + }, + { + "name": "source_url", + "ordinal": 15, + "type_info": "Varchar" + }, + { + "name": "wiki_url", + "ordinal": 16, + "type_info": "Varchar" + }, + { + "name": "discord_url", + "ordinal": 17, + "type_info": "Varchar" + }, + { + "name": "license_url", + "ordinal": 18, + "type_info": "Varchar" + }, + { + "name": "team_id", + "ordinal": 19, + "type_info": "Int8" + }, + { + "name": "client_side", + "ordinal": 20, + "type_info": "Int4" + }, + { + "name": "server_side", + "ordinal": 21, + "type_info": "Int4" + }, + { + "name": "license", + "ordinal": 22, + "type_info": "Varchar" + }, + { + "name": "slug", + "ordinal": 23, + "type_info": "Varchar" + }, + { + "name": "moderation_message", + "ordinal": 24, + "type_info": "Varchar" + }, + { + "name": "moderation_message_body", + "ordinal": 25, + "type_info": "Varchar" + }, + { + "name": "client_side_type", + "ordinal": 26, + "type_info": "Varchar" + }, + { + "name": "server_side_type", + "ordinal": 27, + "type_info": "Varchar" + }, + { + "name": "project_type_name", + "ordinal": 28, + "type_info": "Varchar" + }, + { + "name": "flame_anvil_project", + "ordinal": 29, + "type_info": "Int4" + }, + { + "name": "flame_anvil_user", + "ordinal": 30, + "type_info": "Int8" + }, + { + "name": "webhook_sent", + "ordinal": 31, + "type_info": "Bool" + }, + { + "name": "categories", + "ordinal": 32, + "type_info": "VarcharArray" + }, + { + "name": "additional_categories", + "ordinal": 33, + "type_info": "VarcharArray" + }, + { + "name": "versions", + "ordinal": 34, + "type_info": "Jsonb" + }, + { + "name": "gallery", + "ordinal": 35, + "type_info": "Jsonb" + }, + { + "name": "donations", + "ordinal": 36, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + true, + false, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "Int8Array", + "TextArray" + ] + } + }, + "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories,\n JSONB_AGG(DISTINCT jsonb_build_object('id', v.id, 'date_published', v.date_published)) filter (where v.id is not null) versions,\n JSONB_AGG(DISTINCT TO_JSONB(mg)) filter (where mg.image_url is not null) gallery,\n JSONB_AGG(DISTINCT jsonb_build_object('platform_id', md.joining_platform_id, 'platform_short', dp.short, 'platform_name', dp.name,'url', md.url)) filter (where md.joining_platform_id is not null) donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id AND v.status = ANY($2)\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = ANY($1)\n GROUP BY pt.id, cs.id, ss.id, m.id;\n " + }, "8129255d25bf0624d83f50558b668ed7b7f9c264e380d276522fc82bc871939b": { "describe": { "columns": [], @@ -3291,359 +3434,6 @@ }, "query": "\n UPDATE users\n SET payout_wallet = $1, payout_wallet_type = $2, payout_address = $3\n WHERE (id = $4)\n " }, - "8e82de58229da984e8414158df148c625ce23fdb41fbe42672837c36eada823f": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "project_type", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "title", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "description", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "downloads", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "follows", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "icon_url", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "body", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "body_url", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "published", - "ordinal": 9, - "type_info": "Timestamptz" - }, - { - "name": "updated", - "ordinal": 10, - "type_info": "Timestamptz" - }, - { - "name": "approved", - "ordinal": 11, - "type_info": "Timestamptz" - }, - { - "name": "status", - "ordinal": 12, - "type_info": "Varchar" - }, - { - "name": "requested_status", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "issues_url", - "ordinal": 14, - "type_info": "Varchar" - }, - { - "name": "source_url", - "ordinal": 15, - "type_info": "Varchar" - }, - { - "name": "wiki_url", - "ordinal": 16, - "type_info": "Varchar" - }, - { - "name": "discord_url", - "ordinal": 17, - "type_info": "Varchar" - }, - { - "name": "license_url", - "ordinal": 18, - "type_info": "Varchar" - }, - { - "name": "team_id", - "ordinal": 19, - "type_info": "Int8" - }, - { - "name": "client_side", - "ordinal": 20, - "type_info": "Int4" - }, - { - "name": "server_side", - "ordinal": 21, - "type_info": "Int4" - }, - { - "name": "license", - "ordinal": 22, - "type_info": "Varchar" - }, - { - "name": "slug", - "ordinal": 23, - "type_info": "Varchar" - }, - { - "name": "moderation_message", - "ordinal": 24, - "type_info": "Varchar" - }, - { - "name": "moderation_message_body", - "ordinal": 25, - "type_info": "Varchar" - }, - { - "name": "client_side_type", - "ordinal": 26, - "type_info": "Varchar" - }, - { - "name": "server_side_type", - "ordinal": 27, - "type_info": "Varchar" - }, - { - "name": "project_type_name", - "ordinal": 28, - "type_info": "Varchar" - }, - { - "name": "flame_anvil_project", - "ordinal": 29, - "type_info": "Int4" - }, - { - "name": "flame_anvil_user", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "webhook_sent", - "ordinal": 31, - "type_info": "Bool" - }, - { - "name": "categories", - "ordinal": 32, - "type_info": "TextArray" - }, - { - "name": "versions", - "ordinal": 33, - "type_info": "TextArray" - }, - { - "name": "gallery", - "ordinal": 34, - "type_info": "TextArray" - }, - { - "name": "donations", - "ordinal": 35, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - true, - false, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "Int8Array", - "TextArray" - ] - } - }, - "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent,\n ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT v.id || ' |||| ' || v.date_published) filter (where v.id is not null) versions,\n ARRAY_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ')) filter (where mg.image_url is not null) gallery,\n ARRAY_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url) filter (where md.joining_platform_id is not null) donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id AND v.status = ANY($2)\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = ANY($1)\n GROUP BY pt.id, cs.id, ss.id, m.id;\n " - }, - "8e9127af96108ec5a1da1a75abcaa1e810625d89232a4e7c0dffec77896c87ba": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "mod_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "author_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "version_name", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "version_number", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "changelog", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "changelog_url", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "date_published", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "downloads", - "ordinal": 8, - "type_info": "Int4" - }, - { - "name": "version_type", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "featured", - "ordinal": 10, - "type_info": "Bool" - }, - { - "name": "status", - "ordinal": 11, - "type_info": "Varchar" - }, - { - "name": "requested_status", - "ordinal": 12, - "type_info": "Varchar" - }, - { - "name": "game_versions", - "ordinal": 13, - "type_info": "TextArray" - }, - { - "name": "loaders", - "ordinal": 14, - "type_info": "VarcharArray" - }, - { - "name": "files", - "ordinal": 15, - "type_info": "TextArray" - }, - { - "name": "hashes", - "ordinal": 16, - "type_info": "TextArray" - }, - { - "name": "dependencies", - "ordinal": 17, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - true, - null, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "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.changelog_url changelog_url, 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 ARRAY_AGG(DISTINCT gv.version || ' |||| ' || gv.created) filter (where gv.version is not null) game_versions, ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,\n ARRAY_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename) filter (where f.id is not null) files,\n ARRAY_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id) filter (where h.hash is not null) hashes,\n ARRAY_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.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 " - }, "8f706d78ac4235ea04c59e2c220a4791e1d08fdf287b783b4aaef36fd2445467": { "describe": { "columns": [], @@ -3726,6 +3516,278 @@ }, "query": "\n UPDATE mods\n SET icon_url = $1\n WHERE (id = $2)\n " }, + "918aefac95fe6bbcadbf836fd94370e16f7379c9d796463fa9a7c4e643c6b190": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "icon_url", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "slug", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "client_side_type", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "server_side_type", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "project_type", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "categories", + "ordinal": 10, + "type_info": "VarcharArray" + }, + { + "name": "loaders", + "ordinal": 11, + "type_info": "VarcharArray" + }, + { + "name": "versions", + "ordinal": 12, + "type_info": "Jsonb" + }, + { + "name": "all_game_versions", + "ordinal": 13, + "type_info": "Jsonb" + }, + { + "name": "gallery", + "ordinal": 14, + "type_info": "VarcharArray" + }, + { + "name": "featured_gallery", + "ordinal": 15, + "type_info": "VarcharArray" + } + ], + "nullable": [ + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + null, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "Int8", + "TextArray", + "Text" + ] + } + }, + "query": "\n SELECT m.id id, m.title title, m.description description,\n m.icon_url icon_url, m.slug slug, cs.name client_side_type, ss.name server_side_type,\n pt.name project_type, u.username username, u.avatar_url avatar_url,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n JSONB_AGG(DISTINCT TO_JSONB(gv)) filter (where gv.version is not null) versions,\n JSONB_AGG(DISTINCT TO_JSONB(agv)) filter (where gv.version is not null) all_game_versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id AND mc.is_additional = FALSE\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($2)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n LEFT OUTER JOIN game_versions agv ON 1=1\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.id = $1\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " + }, + "9225b9e3b3262227b26d8da5aa1423495ca0f9052f992a11440d0333b177c702": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "project_type", + "ordinal": 1, + "type_info": "Int4" + }, + { + "name": "title", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "downloads", + "ordinal": 4, + "type_info": "Int4" + }, + { + "name": "follows", + "ordinal": 5, + "type_info": "Int4" + }, + { + "name": "icon_url", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "published", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "approved", + "ordinal": 8, + "type_info": "Timestamptz" + }, + { + "name": "updated", + "ordinal": 9, + "type_info": "Timestamptz" + }, + { + "name": "team_id", + "ordinal": 10, + "type_info": "Int8" + }, + { + "name": "license", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "slug", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "status_name", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "client_side_type", + "ordinal": 14, + "type_info": "Varchar" + }, + { + "name": "server_side_type", + "ordinal": 15, + "type_info": "Varchar" + }, + { + "name": "project_type_name", + "ordinal": 16, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 17, + "type_info": "Varchar" + }, + { + "name": "categories", + "ordinal": 18, + "type_info": "VarcharArray" + }, + { + "name": "additional_categories", + "ordinal": 19, + "type_info": "VarcharArray" + }, + { + "name": "loaders", + "ordinal": 20, + "type_info": "VarcharArray" + }, + { + "name": "versions", + "ordinal": 21, + "type_info": "VarcharArray" + }, + { + "name": "gallery", + "ordinal": 22, + "type_info": "VarcharArray" + }, + { + "name": "featured_gallery", + "ordinal": 23, + "type_info": "VarcharArray" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + false, + true, + false, + false, + false, + false, + false, + null, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "TextArray", + "TextArray", + "Text" + ] + } + }, + "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.published published, m.approved approved, m.updated updated,\n m.team_id team_id, m.license license, m.slug slug, m.status status_name,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, u.username username,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n ARRAY_AGG(DISTINCT gv.version) filter (where gv.version is not null) versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($1)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.status = ANY($2)\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " + }, "9348309884811e8b22f33786ae7c0f259f37f3c90e545f00761a641570107160": { "describe": { "columns": [ @@ -3778,237 +3840,6 @@ }, "query": "\n SELECT id FROM mods\n WHERE slug = LOWER($1)\n " }, - "955e977dfb7173a55fbda80f070725828870efd42ac01a5cc1ced1f30d8d60fd": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "project_type", - "ordinal": 1, - "type_info": "Int4" - }, - { - "name": "title", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "description", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "downloads", - "ordinal": 4, - "type_info": "Int4" - }, - { - "name": "follows", - "ordinal": 5, - "type_info": "Int4" - }, - { - "name": "icon_url", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "body", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "body_url", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "published", - "ordinal": 9, - "type_info": "Timestamptz" - }, - { - "name": "updated", - "ordinal": 10, - "type_info": "Timestamptz" - }, - { - "name": "approved", - "ordinal": 11, - "type_info": "Timestamptz" - }, - { - "name": "status", - "ordinal": 12, - "type_info": "Varchar" - }, - { - "name": "requested_status", - "ordinal": 13, - "type_info": "Varchar" - }, - { - "name": "issues_url", - "ordinal": 14, - "type_info": "Varchar" - }, - { - "name": "source_url", - "ordinal": 15, - "type_info": "Varchar" - }, - { - "name": "wiki_url", - "ordinal": 16, - "type_info": "Varchar" - }, - { - "name": "discord_url", - "ordinal": 17, - "type_info": "Varchar" - }, - { - "name": "license_url", - "ordinal": 18, - "type_info": "Varchar" - }, - { - "name": "team_id", - "ordinal": 19, - "type_info": "Int8" - }, - { - "name": "client_side", - "ordinal": 20, - "type_info": "Int4" - }, - { - "name": "server_side", - "ordinal": 21, - "type_info": "Int4" - }, - { - "name": "license", - "ordinal": 22, - "type_info": "Varchar" - }, - { - "name": "slug", - "ordinal": 23, - "type_info": "Varchar" - }, - { - "name": "moderation_message", - "ordinal": 24, - "type_info": "Varchar" - }, - { - "name": "moderation_message_body", - "ordinal": 25, - "type_info": "Varchar" - }, - { - "name": "client_side_type", - "ordinal": 26, - "type_info": "Varchar" - }, - { - "name": "server_side_type", - "ordinal": 27, - "type_info": "Varchar" - }, - { - "name": "project_type_name", - "ordinal": 28, - "type_info": "Varchar" - }, - { - "name": "flame_anvil_project", - "ordinal": 29, - "type_info": "Int4" - }, - { - "name": "flame_anvil_user", - "ordinal": 30, - "type_info": "Int8" - }, - { - "name": "webhook_sent", - "ordinal": 31, - "type_info": "Bool" - }, - { - "name": "categories", - "ordinal": 32, - "type_info": "TextArray" - }, - { - "name": "versions", - "ordinal": 33, - "type_info": "TextArray" - }, - { - "name": "gallery", - "ordinal": 34, - "type_info": "TextArray" - }, - { - "name": "donations", - "ordinal": 35, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - true, - false, - false, - true, - false, - true, - true, - true, - true, - true, - true, - false, - false, - false, - false, - true, - true, - true, - false, - false, - false, - true, - true, - false, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "Int8", - "TextArray" - ] - } - }, - "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent webhook_sent,\n ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT v.id || ' |||| ' || v.date_published) filter (where v.id is not null) versions,\n ARRAY_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ')) filter (where mg.image_url is not null) gallery,\n ARRAY_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url) filter (where md.joining_platform_id is not null) donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id AND v.status = ANY($2)\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = $1\n GROUP BY pt.id, cs.id, ss.id, m.id;\n " - }, "96b2f4e0e619e7ed312d191dc90d64113235d72254fbda8f528ce866d1795cb5": { "describe": { "columns": [ @@ -4895,112 +4726,6 @@ }, "query": "\n DELETE FROM notifications_actions\n WHERE notification_id = ANY($1)\n " }, - "ba46da8af8591ac26f173700cdd36bdf63ed8817c58565d49ea1f1a20c7280d2": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "title", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "description", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "icon_url", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "slug", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "client_side_type", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "server_side_type", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "project_type", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "categories", - "ordinal": 10, - "type_info": "VarcharArray" - }, - { - "name": "loaders", - "ordinal": 11, - "type_info": "VarcharArray" - }, - { - "name": "versions", - "ordinal": 12, - "type_info": "Jsonb" - }, - { - "name": "all_game_versions", - "ordinal": 13, - "type_info": "Jsonb" - }, - { - "name": "gallery", - "ordinal": 14, - "type_info": "VarcharArray" - } - ], - "nullable": [ - false, - false, - false, - true, - true, - false, - false, - false, - false, - true, - null, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "Int8", - "TextArray", - "Text" - ] - } - }, - "query": "\n SELECT m.id id, m.title title, m.description description,\n m.icon_url icon_url, m.slug slug, cs.name client_side_type, ss.name server_side_type,\n pt.name project_type, u.username username, u.avatar_url avatar_url,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null) categories,\n ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders,\n JSONB_AGG(DISTINCT TO_JSONB(gv)) filter (where gv.version is not null) versions,\n JSONB_AGG(DISTINCT TO_JSONB(agv)) filter (where gv.version is not null) all_game_versions,\n ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null) gallery\n FROM mods m\n LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id AND mc.is_additional = FALSE\n LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id\n LEFT OUTER JOIN versions v ON v.mod_id = m.id AND v.status != ANY($2)\n LEFT OUTER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id\n LEFT OUTER JOIN game_versions gv ON gvv.game_version_id = gv.id\n LEFT OUTER JOIN loaders_versions lv ON lv.version_id = v.id\n LEFT OUTER JOIN loaders lo ON lo.id = lv.loader_id\n LEFT OUTER JOIN mods_gallery mg ON mg.mod_id = m.id\n LEFT OUTER JOIN game_versions agv ON 1=1\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.role = $3 AND tm.accepted = TRUE\n INNER JOIN users u ON tm.user_id = u.id\n WHERE m.id = $1\n GROUP BY m.id, cs.id, ss.id, pt.id, u.id;\n " - }, "bb30f376f5ea8ddb66371b937812511c1685871c1efccfca0d190bbb5103eaa7": { "describe": { "columns": [ @@ -5401,6 +5126,243 @@ }, "query": "\n UPDATE versions\n SET version_type = $1\n WHERE (id = $2)\n " }, + "c3519adf8e82a0092844f3bc3534598cf3b7b7138e13a200bf64d33b7775a6e6": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "project_type", + "ordinal": 1, + "type_info": "Int4" + }, + { + "name": "title", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "description", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "downloads", + "ordinal": 4, + "type_info": "Int4" + }, + { + "name": "follows", + "ordinal": 5, + "type_info": "Int4" + }, + { + "name": "icon_url", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "body", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "body_url", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "published", + "ordinal": 9, + "type_info": "Timestamptz" + }, + { + "name": "updated", + "ordinal": 10, + "type_info": "Timestamptz" + }, + { + "name": "approved", + "ordinal": 11, + "type_info": "Timestamptz" + }, + { + "name": "status", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "requested_status", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "issues_url", + "ordinal": 14, + "type_info": "Varchar" + }, + { + "name": "source_url", + "ordinal": 15, + "type_info": "Varchar" + }, + { + "name": "wiki_url", + "ordinal": 16, + "type_info": "Varchar" + }, + { + "name": "discord_url", + "ordinal": 17, + "type_info": "Varchar" + }, + { + "name": "license_url", + "ordinal": 18, + "type_info": "Varchar" + }, + { + "name": "team_id", + "ordinal": 19, + "type_info": "Int8" + }, + { + "name": "client_side", + "ordinal": 20, + "type_info": "Int4" + }, + { + "name": "server_side", + "ordinal": 21, + "type_info": "Int4" + }, + { + "name": "license", + "ordinal": 22, + "type_info": "Varchar" + }, + { + "name": "slug", + "ordinal": 23, + "type_info": "Varchar" + }, + { + "name": "moderation_message", + "ordinal": 24, + "type_info": "Varchar" + }, + { + "name": "moderation_message_body", + "ordinal": 25, + "type_info": "Varchar" + }, + { + "name": "client_side_type", + "ordinal": 26, + "type_info": "Varchar" + }, + { + "name": "server_side_type", + "ordinal": 27, + "type_info": "Varchar" + }, + { + "name": "project_type_name", + "ordinal": 28, + "type_info": "Varchar" + }, + { + "name": "flame_anvil_project", + "ordinal": 29, + "type_info": "Int4" + }, + { + "name": "flame_anvil_user", + "ordinal": 30, + "type_info": "Int8" + }, + { + "name": "webhook_sent", + "ordinal": 31, + "type_info": "Bool" + }, + { + "name": "categories", + "ordinal": 32, + "type_info": "VarcharArray" + }, + { + "name": "additional_categories", + "ordinal": 33, + "type_info": "VarcharArray" + }, + { + "name": "versions", + "ordinal": 34, + "type_info": "Jsonb" + }, + { + "name": "gallery", + "ordinal": 35, + "type_info": "Jsonb" + }, + { + "name": "donations", + "ordinal": 36, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + true, + false, + false, + true, + false, + true, + true, + true, + true, + true, + true, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + true, + true, + false, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "Int8", + "TextArray" + ] + } + }, + "query": "\n SELECT m.id id, m.project_type project_type, m.title title, m.description description, m.downloads downloads, m.follows follows,\n m.icon_url icon_url, m.body body, m.body_url body_url, m.published published,\n m.updated updated, m.approved approved, m.status status, m.requested_status requested_status,\n m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url,\n m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body,\n cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent webhook_sent,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories,\n ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories,\n JSONB_AGG(DISTINCT jsonb_build_object('id', v.id, 'date_published', v.date_published)) filter (where v.id is not null) versions,\n JSONB_AGG(DISTINCT TO_JSONB(mg)) filter (where mg.image_url is not null) gallery,\n JSONB_AGG(DISTINCT jsonb_build_object('platform_id', md.joining_platform_id, 'platform_short', dp.short, 'platform_name', dp.name,'url', md.url)) filter (where md.joining_platform_id is not null) donations\n FROM mods m\n INNER JOIN project_types pt ON pt.id = m.project_type\n INNER JOIN side_types cs ON m.client_side = cs.id\n INNER JOIN side_types ss ON m.server_side = ss.id\n LEFT JOIN mods_donations md ON md.joining_mod_id = m.id\n LEFT JOIN donation_platforms dp ON md.joining_platform_id = dp.id\n LEFT JOIN mods_categories mc ON mc.joining_mod_id = m.id\n LEFT JOIN categories c ON mc.joining_category_id = c.id\n LEFT JOIN versions v ON v.mod_id = m.id AND v.status = ANY($2)\n LEFT JOIN mods_gallery mg ON mg.mod_id = m.id\n WHERE m.id = $1\n GROUP BY pt.id, cs.id, ss.id, m.id;\n " + }, "c3f594d8d0ffcf5df1b36759cf3088bfaec496c5dfdbf496d3b05f0b122a5d0c": { "describe": { "columns": [], @@ -5467,6 +5429,74 @@ }, "query": "\n INSERT INTO mods_donations (\n joining_mod_id, joining_platform_id, url\n )\n VALUES (\n $1, $2, $3\n )\n " }, + "c5474cd20474b46ccdba86bc2047fee17e12ab3e8009a0744eed7000250718c3": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "title", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "text", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "link", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 5, + "type_info": "Timestamptz" + }, + { + "name": "read", + "ordinal": 6, + "type_info": "Bool" + }, + { + "name": "notification_type", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "actions", + "ordinal": 8, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + null + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.user_id = $1\n GROUP BY n.id, n.user_id;\n " + }, "c55d2132e3e6e92dd50457affab758623dca175dc27a2d3cd4aace9cfdecf789": { "describe": { "columns": [], @@ -6234,6 +6264,68 @@ }, "query": "\n SELECT loader FROM loaders\n WHERE id = $1\n " }, + "d27137a753abd6dfb152daa39ff9ede13c6aae387f14233961c339ff61e3e6ef": { + "describe": { + "columns": [ + { + "name": "user_id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "title", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "text", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "link", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 4, + "type_info": "Timestamptz" + }, + { + "name": "read", + "ordinal": 5, + "type_info": "Bool" + }, + { + "name": "notification_type", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "actions", + "ordinal": 7, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + null + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.id = $1\n GROUP BY n.id, n.user_id;\n " + }, "d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b": { "describe": { "columns": [], @@ -6435,68 +6527,6 @@ }, "query": "\n UPDATE mods\n SET body = $1\n WHERE (id = $2)\n " }, - "e048740eee3470b822956e3d394e4a2a22aa87078e5377ba6d08d6309bbb6b1d": { - "describe": { - "columns": [ - { - "name": "user_id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "title", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "text", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "link", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 4, - "type_info": "Timestamptz" - }, - { - "name": "read", - "ordinal": 5, - "type_info": "Bool" - }, - { - "name": "notification_type", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "actions", - "ordinal": 7, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - null - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type,\n ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions\n FROM notifications n\n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id\n WHERE n.id = $1\n GROUP BY n.id, n.user_id;\n " - }, "e04e0d7add07dc7ae16496badcadd3789be22c80a04a01fbeda3f8dfca01f4b2": { "describe": { "columns": [ @@ -6811,6 +6841,128 @@ }, "query": "SELECT EXISTS(SELECT 1 FROM team_members WHERE id=$1)" }, + "e8688aea42a9b50f656100d70b36ff138adea7636610a72e724df4bfc625794d": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "mod_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "author_id", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "version_name", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "version_number", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "changelog", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "changelog_url", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "date_published", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "downloads", + "ordinal": 8, + "type_info": "Int4" + }, + { + "name": "version_type", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "featured", + "ordinal": 10, + "type_info": "Bool" + }, + { + "name": "status", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "requested_status", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "game_versions", + "ordinal": 13, + "type_info": "Jsonb" + }, + { + "name": "loaders", + "ordinal": 14, + "type_info": "VarcharArray" + }, + { + "name": "files", + "ordinal": 15, + "type_info": "Jsonb" + }, + { + "name": "hashes", + "ordinal": 16, + "type_info": "Jsonb" + }, + { + "name": "dependencies", + "ordinal": 17, + "type_info": "Jsonb" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + true, + null, + null, + null, + null, + null + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "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.changelog_url changelog_url, 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 TO_JSONB(f)) 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 " + }, "e876f64db82d618dce53b108509d67a1108aa747d16892499481fe9f8b95200b": { "describe": { "columns": [], @@ -7192,128 +7344,6 @@ }, "query": "\n DELETE FROM team_members\n WHERE user_id = $1\n " }, - "f2a342f404e3d0c0bb1af153a5f7a8be244fb16302f089cc77d3852c2ef944af": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "mod_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "author_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "version_name", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "version_number", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "changelog", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "changelog_url", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "date_published", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "downloads", - "ordinal": 8, - "type_info": "Int4" - }, - { - "name": "version_type", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "featured", - "ordinal": 10, - "type_info": "Bool" - }, - { - "name": "status", - "ordinal": 11, - "type_info": "Varchar" - }, - { - "name": "requested_status", - "ordinal": 12, - "type_info": "Varchar" - }, - { - "name": "game_versions", - "ordinal": 13, - "type_info": "TextArray" - }, - { - "name": "loaders", - "ordinal": 14, - "type_info": "VarcharArray" - }, - { - "name": "files", - "ordinal": 15, - "type_info": "TextArray" - }, - { - "name": "hashes", - "ordinal": 16, - "type_info": "TextArray" - }, - { - "name": "dependencies", - "ordinal": 17, - "type_info": "TextArray" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - false, - false, - false, - false, - false, - true, - null, - null, - null, - null, - null - ], - "parameters": { - "Left": [ - "Int8Array" - ] - } - }, - "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.changelog_url changelog_url, 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 ARRAY_AGG(DISTINCT gv.version || ' |||| ' || gv.created) filter (where gv.version is not null) game_versions, ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders,\n ARRAY_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename) filter (where f.id is not null) files,\n ARRAY_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id) filter (where h.hash is not null) hashes,\n ARRAY_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.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 = ANY($1)\n GROUP BY v.id\n ORDER BY v.date_published ASC;\n " - }, "f3a8ad4a802dde0eb9304078e0368066e7d48121dfe73a63b2911b0998840a79": { "describe": { "columns": [ diff --git a/src/database/models/ids.rs b/src/database/models/ids.rs index 5b85ad8c8..d90d7a810 100644 --- a/src/database/models/ids.rs +++ b/src/database/models/ids.rs @@ -117,7 +117,7 @@ pub struct TeamId(pub i64); #[sqlx(transparent)] pub struct TeamMemberId(pub i64); -#[derive(Copy, Clone, Debug, Type, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Deserialize)] #[sqlx(transparent)] pub struct ProjectId(pub i64); #[derive(Copy, Clone, Debug, Type)] @@ -130,11 +130,11 @@ pub struct StatusId(pub i32); #[derive(Copy, Clone, Debug, Type)] #[sqlx(transparent)] pub struct SideTypeId(pub i32); -#[derive(Copy, Clone, Debug, Type)] +#[derive(Copy, Clone, Debug, Type, Deserialize)] #[sqlx(transparent)] pub struct DonationPlatformId(pub i32); -#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Deserialize)] #[sqlx(transparent)] pub struct VersionId(pub i64); #[derive(Copy, Clone, Debug, Type, Deserialize)] @@ -154,7 +154,7 @@ pub struct ReportId(pub i64); #[sqlx(transparent)] pub struct ReportTypeId(pub i32); -#[derive(Copy, Clone, Debug, Type, Hash, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Type, Hash, Eq, PartialEq, Deserialize)] #[sqlx(transparent)] pub struct FileId(pub i64); @@ -162,10 +162,10 @@ pub struct FileId(pub i64); #[sqlx(transparent)] pub struct StateId(pub i64); -#[derive(Copy, Clone, Debug, Type)] +#[derive(Copy, Clone, Debug, Type, Deserialize)] #[sqlx(transparent)] pub struct NotificationId(pub i64); -#[derive(Copy, Clone, Debug, Type)] +#[derive(Copy, Clone, Debug, Type, Deserialize)] #[sqlx(transparent)] pub struct NotificationActionId(pub i32); diff --git a/src/database/models/notification_item.rs b/src/database/models/notification_item.rs index 0ab53aaf0..c4a663c24 100644 --- a/src/database/models/notification_item.rs +++ b/src/database/models/notification_item.rs @@ -1,6 +1,7 @@ use super::ids::*; use crate::database::models::DatabaseError; use chrono::{DateTime, Utc}; +use serde::Deserialize; pub struct NotificationBuilder { pub notification_type: Option, @@ -27,6 +28,7 @@ pub struct Notification { pub actions: Vec, } +#[derive(Deserialize)] pub struct NotificationAction { pub id: NotificationActionId, pub notification_id: NotificationId, @@ -124,7 +126,7 @@ impl Notification { let result = sqlx::query!( " SELECT n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, - ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions + JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions FROM notifications n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id WHERE n.id = $1 @@ -136,24 +138,6 @@ impl Notification { .await?; if let Some(row) = result { - let mut actions: Vec = Vec::new(); - - row.actions.unwrap_or_default().into_iter().for_each(|x| { - let action: Vec<&str> = x.split(" |||| ").collect(); - - if action.len() >= 3 { - actions.push(NotificationAction { - id: NotificationActionId( - action[0].parse().unwrap_or(0), - ), - notification_id: id, - title: action[1].to_string(), - action_route_method: action[3].to_string(), - action_route: action[2].to_string(), - }); - } - }); - Ok(Some(Notification { id, user_id: UserId(row.user_id), @@ -163,7 +147,11 @@ impl Notification { link: row.link, read: row.read, created: row.created, - actions, + actions: serde_json::from_value( + row.actions.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), })) } else { Ok(None) @@ -184,7 +172,7 @@ impl Notification { sqlx::query!( " SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, - ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions + JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions FROM notifications n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id WHERE n.id = ANY($1) @@ -197,21 +185,6 @@ impl Notification { .try_filter_map(|e| async { Ok(e.right().map(|row| { let id = NotificationId(row.id); - let mut actions: Vec = Vec::new(); - - row.actions.unwrap_or_default().into_iter().for_each(|x| { - let action: Vec<&str> = x.split(" |||| ").collect(); - - if action.len() >= 3 { - actions.push(NotificationAction { - id: NotificationActionId(action[0].parse().unwrap_or(0)), - notification_id: id, - title: action[1].to_string(), - action_route_method: action[3].to_string(), - action_route: action[2].to_string(), - }); - } - }); Notification { id, @@ -222,7 +195,11 @@ impl Notification { link: row.link, read: row.read, created: row.created, - actions, + actions: serde_json::from_value( + row.actions.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), } })) }) @@ -242,7 +219,7 @@ impl Notification { sqlx::query!( " SELECT n.id, n.user_id, n.title, n.text, n.link, n.created, n.read, n.type notification_type, - ARRAY_AGG(DISTINCT na.id || ' |||| ' || na.title || ' |||| ' || na.action_route || ' |||| ' || na.action_route_method) filter (where na.id is not null) actions + JSONB_AGG(DISTINCT TO_JSONB(na)) filter (where na.id is not null) actions FROM notifications n LEFT OUTER JOIN notifications_actions na on n.id = na.notification_id WHERE n.user_id = $1 @@ -254,21 +231,6 @@ impl Notification { .try_filter_map(|e| async { Ok(e.right().map(|row| { let id = NotificationId(row.id); - let mut actions: Vec = Vec::new(); - - row.actions.unwrap_or_default().into_iter().for_each(|x| { - let action: Vec<&str> = x.split(" |||| ").collect(); - - if action.len() >= 3 { - actions.push(NotificationAction { - id: NotificationActionId(action[0].parse().unwrap_or(0)), - notification_id: id, - title: action[1].to_string(), - action_route_method: action[3].to_string(), - action_route: action[2].to_string(), - }); - } - }); Notification { id, @@ -279,7 +241,11 @@ impl Notification { link: row.link, read: row.read, created: row.created, - actions, + actions: serde_json::from_value( + row.actions.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), } })) }) diff --git a/src/database/models/project_item.rs b/src/database/models/project_item.rs index 0d2ae5a9e..59356a3a0 100644 --- a/src/database/models/project_item.rs +++ b/src/database/models/project_item.rs @@ -1,11 +1,10 @@ use super::ids::*; -use crate::database::models::convert_postgres_date; use crate::models::projects::ProjectStatus; use chrono::{DateTime, Utc}; +use serde::Deserialize; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize)] pub struct DonationUrl { - pub project_id: ProjectId, pub platform_id: DonationPlatformId, pub platform_short: String, pub platform_name: String, @@ -15,6 +14,7 @@ pub struct DonationUrl { impl DonationUrl { pub async fn insert( &self, + project_id: ProjectId, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result<(), sqlx::error::Error> { sqlx::query!( @@ -26,7 +26,7 @@ impl DonationUrl { $1, $2, $3 ) ", - self.project_id as ProjectId, + project_id as ProjectId, self.platform_id as DonationPlatformId, self.url, ) @@ -37,9 +37,8 @@ impl DonationUrl { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Deserialize)] pub struct GalleryItem { - pub project_id: ProjectId, pub image_url: String, pub featured: bool, pub title: Option, @@ -50,6 +49,7 @@ pub struct GalleryItem { impl GalleryItem { pub async fn insert( &self, + project_id: ProjectId, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result<(), sqlx::error::Error> { sqlx::query!( @@ -61,7 +61,7 @@ impl GalleryItem { $1, $2, $3, $4, $5 ) ", - self.project_id as ProjectId, + project_id as ProjectId, self.image_url, self.featured, self.title, @@ -143,14 +143,12 @@ impl ProjectBuilder { version.insert(&mut *transaction).await?; } - for mut donation in self.donation_urls { - donation.project_id = self.project_id; - donation.insert(&mut *transaction).await?; + for donation in self.donation_urls { + donation.insert(self.project_id, &mut *transaction).await?; } - for mut gallery in self.gallery_items { - gallery.project_id = self.project_id; - gallery.insert(&mut *transaction).await?; + for gallery in self.gallery_items { + gallery.insert(self.project_id, &mut *transaction).await?; } for category in self.categories { @@ -667,10 +665,11 @@ impl Project { m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url, m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body, cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent webhook_sent, - ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories, - ARRAY_AGG(DISTINCT v.id || ' |||| ' || v.date_published) filter (where v.id is not null) versions, - ARRAY_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ')) filter (where mg.image_url is not null) gallery, - ARRAY_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url) filter (where md.joining_platform_id is not null) donations + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories, + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories, + JSONB_AGG(DISTINCT jsonb_build_object('id', v.id, 'date_published', v.date_published)) filter (where v.id is not null) versions, + JSONB_AGG(DISTINCT TO_JSONB(mg)) filter (where mg.image_url is not null) gallery, + JSONB_AGG(DISTINCT jsonb_build_object('platform_id', md.joining_platform_id, 'platform_short', dp.short, 'platform_name', dp.name,'url', md.url)) filter (where md.joining_platform_id is not null) donations FROM mods m INNER JOIN project_types pt ON pt.id = m.project_type INNER JOIN side_types cs ON m.client_side = cs.id @@ -691,23 +690,6 @@ impl Project { .await?; if let Some(m) = result { - let categories_raw = m.categories.unwrap_or_default(); - - let mut categories = Vec::new(); - let mut additional_categories = Vec::new(); - - for category in categories_raw { - let category: Vec<&str> = category.split(" |||| ").collect(); - - if category.len() >= 2 { - if category[1].parse::().ok().unwrap_or_default() { - additional_categories.push(category[0].to_string()); - } else { - categories.push(category[0].to_string()); - } - } - } - Ok(Some(QueryProject { inner: Project { id: ProjectId(m.id), @@ -743,86 +725,38 @@ impl Project { webhook_sent: m.webhook_sent, }, project_type: m.project_type_name, - categories, - additional_categories, + categories: m.categories.unwrap_or_default(), + additional_categories: m + .additional_categories + .unwrap_or_default(), versions: { - let versions = m.versions.unwrap_or_default(); + #[derive(Deserialize)] + struct Version { + pub id: VersionId, + pub date_published: DateTime, + } - let mut v = versions - .into_iter() - .flat_map(|x| { - let version: Vec<&str> = - x.split(" |||| ").collect(); + let mut versions: Vec = + serde_json::from_value(m.versions.unwrap_or_default()) + .ok() + .unwrap_or_default(); - if version.len() >= 2 { - Some(( - VersionId( - version[0].parse().unwrap_or_default(), - ), - convert_postgres_date(version[1]) - .timestamp(), - )) - } else { - None - } - }) - .collect::>(); + versions.sort_by(|a, b| { + a.date_published.cmp(&b.date_published) + }); - v.sort_by(|a, b| a.1.cmp(&b.1)); - - v.into_iter().map(|x| x.0).collect() + versions.into_iter().map(|x| x.id).collect() }, - donation_urls: m - .donations - .unwrap_or_default() - .into_iter() - .flat_map(|d| { - let strings: Vec<&str> = d.split(" |||| ").collect(); - - if strings.len() >= 3 { - Some(DonationUrl { - project_id: id, - platform_id: DonationPlatformId( - strings[0].parse().unwrap_or(0), - ), - platform_short: strings[1].to_string(), - platform_name: strings[2].to_string(), - url: strings[3].to_string(), - }) - } else { - None - } - }) - .collect(), - gallery_items: m - .gallery - .unwrap_or_default() - .into_iter() - .flat_map(|d| { - let strings: Vec<&str> = d.split(" |||| ").collect(); - - if strings.len() >= 5 { - Some(GalleryItem { - project_id: id, - image_url: strings[0].to_string(), - featured: strings[1].parse().unwrap_or(false), - title: if strings[3] == " " { - None - } else { - Some(strings[3].to_string()) - }, - description: if strings[4] == " " { - None - } else { - Some(strings[4].to_string()) - }, - created: convert_postgres_date(strings[2]), - }) - } else { - None - } - }) - .collect(), + gallery_items: serde_json::from_value( + m.gallery.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), + donation_urls: serde_json::from_value( + m.donations.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), client_side: crate::models::projects::SideType::from_str( &m.client_side_type, ), @@ -854,10 +788,11 @@ impl Project { m.issues_url issues_url, m.source_url source_url, m.wiki_url wiki_url, m.discord_url discord_url, m.license_url license_url, m.team_id team_id, m.client_side client_side, m.server_side server_side, m.license license, m.slug slug, m.moderation_message moderation_message, m.moderation_message_body moderation_message_body, cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, m.flame_anvil_project flame_anvil_project, m.flame_anvil_user flame_anvil_user, m.webhook_sent, - ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories, - ARRAY_AGG(DISTINCT v.id || ' |||| ' || v.date_published) filter (where v.id is not null) versions, - ARRAY_AGG(DISTINCT mg.image_url || ' |||| ' || mg.featured || ' |||| ' || mg.created || ' |||| ' || COALESCE(mg.title, ' ') || ' |||| ' || COALESCE(mg.description, ' ')) filter (where mg.image_url is not null) gallery, - ARRAY_AGG(DISTINCT md.joining_platform_id || ' |||| ' || dp.short || ' |||| ' || dp.name || ' |||| ' || md.url) filter (where md.joining_platform_id is not null) donations + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories, + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories, + JSONB_AGG(DISTINCT jsonb_build_object('id', v.id, 'date_published', v.date_published)) filter (where v.id is not null) versions, + JSONB_AGG(DISTINCT TO_JSONB(mg)) filter (where mg.image_url is not null) gallery, + JSONB_AGG(DISTINCT jsonb_build_object('platform_id', md.joining_platform_id, 'platform_short', dp.short, 'platform_name', dp.name,'url', md.url)) filter (where md.joining_platform_id is not null) donations FROM mods m INNER JOIN project_types pt ON pt.id = m.project_type INNER JOIN side_types cs ON m.client_side = cs.id @@ -879,24 +814,6 @@ impl Project { Ok(e.right().map(|m| { let id = m.id; - let categories_raw = m.categories.unwrap_or_default(); - - let mut categories = Vec::new(); - let mut additional_categories = Vec::new(); - - for category in categories_raw { - let category: Vec<&str> = - category.split(" |||| ").collect(); - - if category.len() >= 2 { - if category[1].parse::().ok().unwrap_or_default() { - additional_categories.push(category[0].to_string()); - } else { - categories.push(category[0].to_string()); - } - } - } - QueryProject { inner: Project { id: ProjectId(id), @@ -934,74 +851,31 @@ impl Project { webhook_sent: m.webhook_sent, }, project_type: m.project_type_name, - categories, - additional_categories, + categories: m.categories.unwrap_or_default(), + additional_categories: m.additional_categories.unwrap_or_default(), versions: { - let versions = m.versions.unwrap_or_default(); + #[derive(Deserialize)] + struct Version { + pub id: VersionId, + pub date_published: DateTime, + } - let mut v = versions - .into_iter() - .flat_map(|x| { - let version: Vec<&str> = - x.split(" |||| ").collect(); + let mut versions: Vec = serde_json::from_value( + m.versions.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(); - if version.len() >= 2 { - Some(( - VersionId(version[0].parse().unwrap_or_default()), - convert_postgres_date(version[1]) - .timestamp(), - )) - } else { - None - } - }) - .collect::>(); + versions.sort_by(|a, b| a.date_published.cmp(&b.date_published)); - v.sort_by(|a, b| a.1.cmp(&b.1)); - - v.into_iter().map(|x| x.0).collect() + versions.into_iter().map(|x| x.id).collect() }, - gallery_items: m - .gallery - .unwrap_or_default() - .into_iter() - .flat_map(|d| { - let strings: Vec<&str> = d.split(" |||| ").collect(); - - if strings.len() >= 5 { - Some(GalleryItem { - project_id: ProjectId(id), - image_url: strings[0].to_string(), - featured: strings[1].parse().unwrap_or(false), - title: if strings[3] == " " { None } else { Some(strings[3].to_string()) }, - description: if strings[4] == " " { None } else { Some(strings[4].to_string()) }, - created: convert_postgres_date(strings[2]) - }) - } else { - None - } - }) - .collect(), - donation_urls: m - .donations - .unwrap_or_default() - .into_iter() - .flat_map(|d| { - let strings: Vec<&str> = d.split(" |||| ").collect(); - - if strings.len() >= 3 { - Some(DonationUrl { - project_id: ProjectId(id), - platform_id: DonationPlatformId(strings[0].parse().unwrap_or(0)), - platform_short: strings[1].to_string(), - platform_name: strings[2].to_string(), - url: strings[3].to_string(), - }) - } else { - None - } - }) - .collect(), + gallery_items: serde_json::from_value( + m.gallery.unwrap_or_default(), + ).ok().unwrap_or_default(), + donation_urls: serde_json::from_value( + m.donations.unwrap_or_default(), + ).ok().unwrap_or_default(), client_side: crate::models::projects::SideType::from_str(&m.client_side_type), server_side: crate::models::projects::SideType::from_str(&m.server_side_type), }})) diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index 0819e46b2..d885c46cc 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -1,8 +1,8 @@ use super::ids::*; use super::DatabaseError; -use crate::database::models::convert_postgres_date; use crate::models::projects::VersionStatus; use chrono::{DateTime, Utc}; +use serde::Deserialize; use std::cmp::Ordering; use std::collections::HashMap; @@ -601,10 +601,11 @@ impl Version { SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number, v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads, v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status, - ARRAY_AGG(DISTINCT gv.version || ' |||| ' || gv.created) filter (where gv.version is not null) game_versions, ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders, - ARRAY_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename) filter (where f.id is not null) files, - ARRAY_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id) filter (where h.hash is not null) hashes, - ARRAY_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' ')) filter (where d.dependency_type is not null) dependencies + JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions, + ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders, + JSONB_AGG(DISTINCT TO_JSONB(f)) filter (where f.id is not null) files, + 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, + 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 FROM versions v LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id @@ -641,59 +642,57 @@ impl Version { .map(|x| VersionStatus::from_str(&x)), }, files: { - let hashes: Vec<(FileId, String, Vec)> = v - .hashes - .unwrap_or_default() + #[derive(Deserialize)] + struct Hash { + pub file_id: FileId, + pub algorithm: String, + pub hash: Vec, + } + + #[derive(Deserialize)] + struct File { + pub id: FileId, + pub url: String, + pub filename: String, + pub primary: bool, + pub size: u32, + } + + let hashes: Vec = + serde_json::from_value(v.hashes.unwrap_or_default()) + .ok() + .unwrap_or_default(); + + let files: Vec = + serde_json::from_value(v.files.unwrap_or_default()) + .ok() + .unwrap_or_default(); + + let mut files = files .into_iter() - .flat_map(|f| { - let hash: Vec<&str> = f.split(" |||| ").collect(); + .map(|x| { + let mut file_hashes = HashMap::new(); - if hash.len() >= 3 { - Some(( - FileId(hash[2].parse().unwrap_or(0)), - hash[0].to_string(), - hash[1].to_string().into_bytes(), - )) - } else { - None - } - }) - .collect(); - - let mut files: Vec = v - .files - .unwrap_or_default() - .into_iter() - .flat_map(|f| { - let file: Vec<&str> = f.split(" |||| ").collect(); - - if file.len() >= 5 { - let file_id = - FileId(file[0].parse().unwrap_or(0)); - let mut file_hashes = HashMap::new(); - - for hash in &hashes { - if (hash.0).0 == file_id.0 { - file_hashes.insert( - hash.1.clone(), - hash.2.clone(), - ); - } + for hash in &hashes { + if hash.file_id == x.id { + file_hashes.insert( + hash.algorithm.clone(), + hash.hash.clone(), + ); } + } - Some(QueryFile { - id: file_id, - url: file[3].to_string(), - filename: file[4].to_string(), - hashes: file_hashes, - primary: file[1].parse().unwrap_or(false), - size: file[2].parse().unwrap_or(0), - }) - } else { - None + QueryFile { + id: x.id, + url: x.url, + filename: x.filename, + hashes: file_hashes, + primary: x.primary, + size: x.size, } }) - .collect(); + .collect::>(); + files.sort_by(|a, b| { if a.primary { Ordering::Less @@ -703,69 +702,33 @@ impl Version { a.filename.cmp(&b.filename) } }); + files }, game_versions: { - let game_versions = v.game_versions.unwrap_or_default(); + #[derive(Deserialize)] + struct GameVersion { + pub version: String, + pub created: DateTime, + } - let mut gv = game_versions - .into_iter() - .flat_map(|x| { - let version: Vec<&str> = - x.split(" |||| ").collect(); + let mut game_versions: Vec = + serde_json::from_value( + v.game_versions.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(); - if version.len() >= 2 { - Some(( - version[0].to_string(), - convert_postgres_date(version[1]) - .timestamp(), - )) - } else { - None - } - }) - .collect::>(); + game_versions.sort_by(|a, b| a.created.cmp(&b.created)); - gv.sort_by(|a, b| a.1.cmp(&b.1)); - - gv.into_iter().map(|x| x.0).collect() + game_versions.into_iter().map(|x| x.version).collect() }, loaders: v.loaders.unwrap_or_default(), - dependencies: v - .dependencies - .unwrap_or_default() - .into_iter() - .flat_map(|f| { - let dependency: Vec<&str> = f.split(" |||| ").collect(); - - if dependency.len() >= 4 { - Some(QueryDependency { - project_id: match dependency[1] { - "0" => None, - _ => match dependency[1].parse() { - Ok(x) => Some(ProjectId(x)), - Err(_) => None, - }, - }, - version_id: match dependency[0] { - "0" => None, - _ => match dependency[0].parse() { - Ok(x) => Some(VersionId(x)), - Err(_) => None, - }, - }, - file_name: if dependency[3] == " " { - None - } else { - Some(dependency[3].to_string()) - }, - dependency_type: dependency[2].to_string(), - }) - } else { - None - } - }) - .collect(), + dependencies: serde_json::from_value( + v.dependencies.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), })) } else { Ok(None) @@ -788,10 +751,11 @@ impl Version { SELECT v.id id, v.mod_id mod_id, v.author_id author_id, v.name version_name, v.version_number version_number, v.changelog changelog, v.changelog_url changelog_url, v.date_published date_published, v.downloads downloads, v.version_type version_type, v.featured featured, v.status status, v.requested_status requested_status, - ARRAY_AGG(DISTINCT gv.version || ' |||| ' || gv.created) filter (where gv.version is not null) game_versions, ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders, - ARRAY_AGG(DISTINCT f.id || ' |||| ' || f.is_primary || ' |||| ' || f.size || ' |||| ' || f.url || ' |||| ' || f.filename) filter (where f.id is not null) files, - ARRAY_AGG(DISTINCT h.algorithm || ' |||| ' || encode(h.hash, 'escape') || ' |||| ' || h.file_id) filter (where h.hash is not null) hashes, - ARRAY_AGG(DISTINCT COALESCE(d.dependency_id, 0) || ' |||| ' || COALESCE(d.mod_dependency_id, 0) || ' |||| ' || d.dependency_type || ' |||| ' || COALESCE(d.dependency_file_name, ' ')) filter (where d.dependency_type is not null) dependencies + JSONB_AGG(DISTINCT jsonb_build_object('version', gv.version, 'created', gv.created)) filter (where gv.version is not null) game_versions, + ARRAY_AGG(DISTINCT l.loader) filter (where l.loader is not null) loaders, + JSONB_AGG(DISTINCT TO_JSONB(f)) filter (where f.id is not null) files, + 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, + 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 FROM versions v LEFT OUTER JOIN game_versions_versions gvv on v.id = gvv.joining_version_id LEFT OUTER JOIN game_versions gv on gvv.game_version_id = gv.id @@ -827,50 +791,56 @@ impl Version { .map(|x| VersionStatus::from_str(&x)), }, files: { - let hashes: Vec<(FileId, String, Vec)> = v.hashes.unwrap_or_default() - .into_iter() - .flat_map(|f| { - let hash: Vec<&str> = f.split(" |||| ").collect(); + #[derive(Deserialize)] + struct Hash { + pub file_id: FileId, + pub algorithm: String, + pub hash: Vec, + } - if hash.len() >= 3 { - Some(( - FileId(hash[2].parse().unwrap_or(0)), - hash[0].to_string(), - hash[1].to_string().into_bytes(), - )) - } else { - None - } - }).collect(); + #[derive(Deserialize)] + struct File { + pub id: FileId, + pub url: String, + pub filename: String, + pub primary: bool, + pub size: u32, + } - let mut files: Vec = v.files.unwrap_or_default() - .into_iter() - .flat_map(|f| { - let file: Vec<&str> = f.split(" |||| ").collect(); + let hashes: Vec = serde_json::from_value( + v.hashes.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(); - if file.len() >= 5 { - let file_id = FileId(file[0].parse().unwrap_or(0)); - let mut file_hashes = HashMap::new(); + let files: Vec = serde_json::from_value( + v.files.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(); - for hash in &hashes { - if (hash.0).0 == file_id.0 { - file_hashes.insert(hash.1.clone(), hash.2.clone()); - } + let mut files = files.into_iter().map(|x| { + let mut file_hashes = HashMap::new(); + + for hash in &hashes { + if hash.file_id == x.id { + file_hashes.insert( + hash.algorithm.clone(), + hash.hash.clone(), + ); } - - Some(QueryFile { - id: file_id, - url: file[3].to_string(), - filename: file[4].to_string(), - hashes: file_hashes, - primary: file[1].parse().unwrap_or(false), - size: file[2].parse().unwrap_or(0), - }) - } else { - None } - }) - .collect(); + + QueryFile { + id: x.id, + url: x.url, + filename: x.filename, + hashes: file_hashes, + primary: x.primary, + size: x.size, + } + }).collect::>(); + files.sort_by(|a, b| { if a.primary { Ordering::Less @@ -880,68 +850,32 @@ impl Version { a.filename.cmp(&b.filename) } }); + files }, game_versions: { - let game_versions = v - .game_versions + #[derive(Deserialize)] + struct GameVersion { + pub version: String, + pub created: DateTime, + } + + let mut game_versions: Vec = serde_json::from_value( + v.game_versions.unwrap_or_default(), + ) + .ok() .unwrap_or_default(); - let mut gv = game_versions - .into_iter() + game_versions.sort_by(|a, b| a.created.cmp(&b.created)); - .flat_map(|x| { - let version: Vec<&str> = x.split(" |||| ").collect(); - - if version.len() >= 2 { - Some((version[0].to_string(), convert_postgres_date(version[1]).timestamp())) - } else { - None - } - }) - .collect::>(); - - gv.sort_by(|a, b| a.1.cmp(&b.1)); - - gv.into_iter() - .map(|x| x.0) - .collect() + game_versions.into_iter().map(|x| x.version).collect() }, loaders: v.loaders.unwrap_or_default(), - dependencies: v.dependencies - .unwrap_or_default() - .into_iter() - - .flat_map(|f| { - let dependency: Vec<&str> = f.split(" |||| ").collect(); - - if dependency.len() >= 4 { - Some(QueryDependency { - project_id: match dependency[1] { - "0" => None, - _ => match dependency[1].parse() { - Ok(x) => Some(ProjectId(x)), - Err(_) => None, - }, - }, - version_id: match dependency[0] { - "0" => None, - _ => match dependency[0].parse() { - Ok(x) => Some(VersionId(x)), - Err(_) => None, - }, - }, - file_name: if dependency[3] == " " { - None - } else { - Some(dependency[3].to_string()) - }, - dependency_type: dependency[2].to_string(), - }) - } else { - None - } - }).collect(), + dependencies: serde_json::from_value( + v.dependencies.unwrap_or_default(), + ) + .ok() + .unwrap_or_default(), } )) }) @@ -960,7 +894,7 @@ pub struct QueryVersion { pub dependencies: Vec, } -#[derive(Clone)] +#[derive(Clone, Deserialize)] pub struct QueryDependency { pub project_id: Option, pub version_id: Option, diff --git a/src/routes/project_creation.rs b/src/routes/project_creation.rs index 21ad7ed3e..323297ad8 100644 --- a/src/routes/project_creation.rs +++ b/src/routes/project_creation.rs @@ -277,7 +277,7 @@ pub async fn project_create( &***file_host, &flame_anvil_queue, &mut uploaded_files, - &*client, + &client, ) .await; @@ -723,7 +723,6 @@ pub async fn project_create_inner( })?; donation_urls.push(models::project_item::DonationUrl { - project_id: project_id.into(), platform_id, platform_short: "".to_string(), platform_name: "".to_string(), @@ -759,7 +758,6 @@ pub async fn project_create_inner( gallery_items: gallery_urls .iter() .map(|x| models::project_item::GalleryItem { - project_id: project_id.into(), image_url: x.url.clone(), featured: x.featured, title: x.title.clone(), diff --git a/src/routes/projects.rs b/src/routes/projects.rs index a8db6ad81..68da0106c 100644 --- a/src/routes/projects.rs +++ b/src/routes/projects.rs @@ -500,7 +500,7 @@ pub async fn project_edit( { crate::util::webhook::send_discord_webhook( project_item.inner.id.into(), - &*pool, + &pool, webhook_url, ) .await @@ -529,7 +529,7 @@ pub async fn project_edit( { crate::util::webhook::send_discord_webhook( project_item.inner.id.into(), - &*pool, + &pool, webhook_url, ) .await @@ -1483,14 +1483,13 @@ pub async fn add_gallery_item( } database::models::project_item::GalleryItem { - project_id: project_item.id, image_url: format!("{}/{}", cdn_url, url), featured: item.featured, title: item.title, description: item.description, created: Utc::now(), } - .insert(&mut transaction) + .insert(project_item.id, &mut transaction) .await?; transaction.commit().await?; diff --git a/src/routes/v1/mods.rs b/src/routes/v1/mods.rs index 596c32abf..8d470060d 100644 --- a/src/routes/v1/mods.rs +++ b/src/routes/v1/mods.rs @@ -133,7 +133,7 @@ pub async fn mod_create( &***file_host, &flame_anvil_queue, &mut uploaded_files, - &*client, + &client, ) .await; diff --git a/src/search/indexing/local_import.rs b/src/search/indexing/local_import.rs index c79f91cb3..3b47db4ec 100644 --- a/src/search/indexing/local_import.rs +++ b/src/search/indexing/local_import.rs @@ -18,10 +18,12 @@ pub async fn index_local( m.icon_url icon_url, m.published published, m.approved approved, m.updated updated, m.team_id team_id, m.license license, m.slug slug, m.status status_name, cs.name client_side_type, ss.name server_side_type, pt.name project_type_name, u.username username, - ARRAY_AGG(DISTINCT c.category || ' |||| ' || mc.is_additional) filter (where c.category is not null) categories, + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is false) categories, + ARRAY_AGG(DISTINCT c.category) filter (where c.category is not null and mc.is_additional is true) additional_categories, ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders, ARRAY_AGG(DISTINCT gv.version) filter (where gv.version is not null) versions, - ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null) gallery + ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery, + ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery FROM mods m LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id @@ -46,27 +48,13 @@ pub async fn index_local( .fetch_many(&pool) .try_filter_map(|e| async { Ok(e.right().map(|m| { - let categories_raw = m.categories.unwrap_or_default(); - - let mut additional_categories = Vec::new(); - let mut categories = Vec::new(); - - for category in categories_raw { - let category: Vec<&str> = category.split(" |||| ").collect(); - - if category.len() >= 2 { - if category[1].parse::().ok().unwrap_or_default() { - additional_categories.push(category[0].to_string()); - } else { - categories.push(category[0].to_string()); - } - } - } + let mut additional_categories = m.additional_categories.unwrap_or_default(); + let mut categories = m.categories.unwrap_or_default(); categories.append(&mut m.loaders.unwrap_or_default()); let display_categories = categories.clone(); - categories.append(&mut additional_categories.clone()); + categories.append(&mut additional_categories); let versions = m.versions.unwrap_or_default(); @@ -82,8 +70,11 @@ pub async fn index_local( _ => false, }; + let mut gallery = m.featured_gallery.unwrap_or_default(); + gallery.append(&mut m.gallery.unwrap_or_default()); + UploadSearchProject { - project_id: format!("{}", project_id), + project_id: project_id.to_string(), title: m.title, description: m.description, categories, @@ -102,7 +93,7 @@ pub async fn index_local( server_side: m.server_side_type, slug: m.slug, project_type: m.project_type_name, - gallery: m.gallery.unwrap_or_default(), + gallery, display_categories, open_source, } diff --git a/src/util/webhook.rs b/src/util/webhook.rs index f72731346..43a709239 100644 --- a/src/util/webhook.rs +++ b/src/util/webhook.rs @@ -72,7 +72,8 @@ pub async fn send_discord_webhook( ARRAY_AGG(DISTINCT lo.loader) filter (where lo.loader is not null) loaders, JSONB_AGG(DISTINCT TO_JSONB(gv)) filter (where gv.version is not null) versions, JSONB_AGG(DISTINCT TO_JSONB(agv)) filter (where gv.version is not null) all_game_versions, - ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null) gallery + ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is false) gallery, + ARRAY_AGG(DISTINCT mg.image_url) filter (where mg.image_url is not null and mg.featured is true) featured_gallery FROM mods m LEFT OUTER JOIN mods_categories mc ON joining_mod_id = m.id AND mc.is_additional = FALSE LEFT OUTER JOIN categories c ON mc.joining_category_id = c.id @@ -95,7 +96,7 @@ pub async fn send_discord_webhook( &*crate::models::projects::VersionStatus::iterator().filter(|x| x.is_hidden()).map(|x| x.to_string()).collect::>(), crate::models::teams::OWNER_ROLE, ) - .fetch_optional(&*pool) + .fetch_optional(pool) .await?; if let Some(project) = row { @@ -106,19 +107,13 @@ pub async fn send_discord_webhook( let versions: Vec = serde_json::from_value(project.versions.unwrap_or_default()) - .map_err(|err| { - ApiError::DiscordError( - "Error while sending projects webhook".to_string(), - ) - })?; + .ok() + .unwrap_or_default(); let all_game_versions: Vec = serde_json::from_value( project.all_game_versions.unwrap_or_default(), ) - .map_err(|err| { - ApiError::DiscordError( - "Error while sending projects webhook".to_string(), - ) - })?; + .ok() + .unwrap_or_default(); if !categories.is_empty() { fields.push(DiscordEmbedField { @@ -170,7 +165,7 @@ pub async fn send_discord_webhook( } if !versions.is_empty() { - let mut formatted_game_versions: String = + let formatted_game_versions: String = get_gv_range(versions, all_game_versions); fields.push(DiscordEmbedField { @@ -204,11 +199,14 @@ pub async fn send_discord_webhook( thumbnail: DiscordEmbedThumbnail { url: project.icon_url, }, - image: project.gallery.unwrap_or_default().first().map(|x| { - DiscordEmbedImage { - url: Some(x.to_string()), - } - }), + image: if let Some(first) = + project.featured_gallery.unwrap_or_default().first() + { + Some(first.clone()) + } else { + project.gallery.unwrap_or_default().first().cloned() + } + .map(|x| DiscordEmbedImage { url: Some(x) }), footer: Some(DiscordEmbedFooter { text: "Modrinth".to_string(), icon_url: Some( @@ -231,7 +229,7 @@ pub async fn send_discord_webhook( }) .send() .await - .map_err(|err| { + .map_err(|_| { ApiError::DiscordError( "Error while sending projects webhook".to_string(), ) @@ -261,8 +259,8 @@ fn get_gv_range( const MAX_VALUE: usize = 1000000; - for i in 0..game_versions.len() { - let current_version = &*game_versions[i].version; + for (i, current_version) in game_versions.iter().enumerate() { + let current_version = ¤t_version.version; let index = all_game_versions .iter()