diff --git a/.sqlx/query-8d6166509c910b6400efc1d1398aae92ebe04b0d4d1fe1762208167cee23b645.json b/.sqlx/query-02a585c845168c1bd8a82c30af351db75597da5456e29efc033ebb098e81e905.json similarity index 58% rename from .sqlx/query-8d6166509c910b6400efc1d1398aae92ebe04b0d4d1fe1762208167cee23b645.json rename to .sqlx/query-02a585c845168c1bd8a82c30af351db75597da5456e29efc033ebb098e81e905.json index 036866616..4777f327b 100644 --- a/.sqlx/query-8d6166509c910b6400efc1d1398aae92ebe04b0d4d1fe1762208167cee23b645.json +++ b/.sqlx/query-02a585c845168c1bd8a82c30af351db75597da5456e29efc033ebb098e81e905.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO team_members (\n id, team_id, user_id, role, permissions, organization_permissions, is_owner, accepted\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8\n )\n ", + "query": "\n INSERT INTO team_members (\n id, team_id, user_id, role, permissions, organization_permissions, is_owner, accepted, payouts_split\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9\n )\n ", "describe": { "columns": [], "parameters": { @@ -12,10 +12,11 @@ "Int8", "Int8", "Bool", - "Bool" + "Bool", + "Numeric" ] }, "nullable": [] }, - "hash": "8d6166509c910b6400efc1d1398aae92ebe04b0d4d1fe1762208167cee23b645" + "hash": "02a585c845168c1bd8a82c30af351db75597da5456e29efc033ebb098e81e905" } diff --git a/.sqlx/query-0c2addb0d7a87fa558821ff8e943bbb751fb2bdc22d1a5368f61cc7827586840.json b/.sqlx/query-0c2addb0d7a87fa558821ff8e943bbb751fb2bdc22d1a5368f61cc7827586840.json new file mode 100644 index 000000000..667bdcbfa --- /dev/null +++ b/.sqlx/query-0c2addb0d7a87fa558821ff8e943bbb751fb2bdc22d1a5368f61cc7827586840.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO files (id, version_id, url, filename, is_primary, size, file_type)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Varchar", + "Varchar", + "Bool", + "Int4", + "Varchar" + ] + }, + "nullable": [] + }, + "hash": "0c2addb0d7a87fa558821ff8e943bbb751fb2bdc22d1a5368f61cc7827586840" +} diff --git a/.sqlx/query-9b0c04bc7d44a60c175259cfe86b8e7ba0340ea9c89be30a89cc224d0f7e9727.json b/.sqlx/query-177b15719778b7788b88877af6affb8dba11da318b14dab7fcc7165c46bbecf5.json similarity index 64% rename from .sqlx/query-9b0c04bc7d44a60c175259cfe86b8e7ba0340ea9c89be30a89cc224d0f7e9727.json rename to .sqlx/query-177b15719778b7788b88877af6affb8dba11da318b14dab7fcc7165c46bbecf5.json index 801e637ea..c34323c98 100644 --- a/.sqlx/query-9b0c04bc7d44a60c175259cfe86b8e7ba0340ea9c89be30a89cc224d0f7e9727.json +++ b/.sqlx/query-177b15719778b7788b88877af6affb8dba11da318b14dab7fcc7165c46bbecf5.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO mods (\n id, team_id, name, summary, description,\n published, downloads, icon_url, status, requested_status,\n license_url, license,\n slug, color, monetization_status\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, \n $7, $8, $9, $10, \n $11, $12, \n LOWER($13), $14, $15\n )\n ", + "query": "\n INSERT INTO mods (\n id, team_id, name, summary, description,\n published, downloads, icon_url, status, requested_status,\n license_url, license,\n slug, color, monetization_status, organization_id\n )\n VALUES (\n $1, $2, $3, $4, $5, $6, \n $7, $8, $9, $10, \n $11, $12, \n LOWER($13), $14, $15, $16\n )\n ", "describe": { "columns": [], "parameters": { @@ -19,10 +19,11 @@ "Varchar", "Text", "Int4", - "Varchar" + "Varchar", + "Int8" ] }, "nullable": [] }, - "hash": "9b0c04bc7d44a60c175259cfe86b8e7ba0340ea9c89be30a89cc224d0f7e9727" + "hash": "177b15719778b7788b88877af6affb8dba11da318b14dab7fcc7165c46bbecf5" } diff --git a/.sqlx/query-24ae57ca296554a29b414caca866cfe7ab956ea28450d40a564498c3d27b937f.json b/.sqlx/query-24ae57ca296554a29b414caca866cfe7ab956ea28450d40a564498c3d27b937f.json deleted file mode 100644 index aa6db91f8..000000000 --- a/.sqlx/query-24ae57ca296554a29b414caca866cfe7ab956ea28450d40a564498c3d27b937f.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO files (id, version_id, url, filename, is_primary, size, file_type)\n SELECT * FROM UNNEST($1::bigint[], $2::bigint[], $3::varchar[], $4::varchar[], $5::bool[], $6::integer[], $7::varchar[])\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8Array", - "Int8Array", - "VarcharArray", - "VarcharArray", - "BoolArray", - "Int4Array", - "VarcharArray" - ] - }, - "nullable": [] - }, - "hash": "24ae57ca296554a29b414caca866cfe7ab956ea28450d40a564498c3d27b937f" -} diff --git a/.sqlx/query-da30019590b9d0f7e21668997e780044c67a7c5d225e556c7ec2a4d7709db5ea.json b/.sqlx/query-38f651362c0778254c28ccd4745af611f4deb6e72f52b8cf65d0515f0fe14779.json similarity index 55% rename from .sqlx/query-da30019590b9d0f7e21668997e780044c67a7c5d225e556c7ec2a4d7709db5ea.json rename to .sqlx/query-38f651362c0778254c28ccd4745af611f4deb6e72f52b8cf65d0515f0fe14779.json index 0b572b2d5..0170be2e8 100644 --- a/.sqlx/query-da30019590b9d0f7e21668997e780044c67a7c5d225e556c7ec2a4d7709db5ea.json +++ b/.sqlx/query-38f651362c0778254c28ccd4745af611f4deb6e72f52b8cf65d0515f0fe14779.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT EXISTS(SELECT 1 FROM organizations WHERE name = LOWER($1))\n ", + "query": "\n SELECT EXISTS(SELECT 1 FROM organizations WHERE LOWER(slug) = LOWER($1))\n ", "describe": { "columns": [ { @@ -18,5 +18,5 @@ null ] }, - "hash": "da30019590b9d0f7e21668997e780044c67a7c5d225e556c7ec2a4d7709db5ea" + "hash": "38f651362c0778254c28ccd4745af611f4deb6e72f52b8cf65d0515f0fe14779" } diff --git a/.sqlx/query-ca9f3298ff92051412f5096690b3314fe91fe0b7c79ab2f7d09396af47b85ee6.json b/.sqlx/query-4deaf065c12dbfd5f585286001fdf66f60524ec13eab7d922db9290237297849.json similarity index 65% rename from .sqlx/query-ca9f3298ff92051412f5096690b3314fe91fe0b7c79ab2f7d09396af47b85ee6.json rename to .sqlx/query-4deaf065c12dbfd5f585286001fdf66f60524ec13eab7d922db9290237297849.json index 885bcd56c..b9780b845 100644 --- a/.sqlx/query-ca9f3298ff92051412f5096690b3314fe91fe0b7c79ab2f7d09396af47b85ee6.json +++ b/.sqlx/query-4deaf065c12dbfd5f585286001fdf66f60524ec13eab7d922db9290237297849.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color\n FROM organizations o\n WHERE o.id = ANY($1) OR LOWER(o.name) = ANY($2)\n GROUP BY o.id;\n ", + "query": "\n SELECT o.id, o.slug, o.name, o.team_id, o.description, o.icon_url, o.color\n FROM organizations o\n WHERE o.id = ANY($1) OR LOWER(o.slug) = ANY($2)\n GROUP BY o.id;\n ", "describe": { "columns": [ { @@ -10,26 +10,31 @@ }, { "ordinal": 1, - "name": "name", + "name": "slug", "type_info": "Varchar" }, { "ordinal": 2, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 3, "name": "team_id", "type_info": "Int8" }, { - "ordinal": 3, + "ordinal": 4, "name": "description", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "icon_url", "type_info": "Varchar" }, { - "ordinal": 5, + "ordinal": 6, "name": "color", "type_info": "Int4" } @@ -45,9 +50,10 @@ false, false, false, + false, true, true ] }, - "hash": "ca9f3298ff92051412f5096690b3314fe91fe0b7c79ab2f7d09396af47b85ee6" + "hash": "4deaf065c12dbfd5f585286001fdf66f60524ec13eab7d922db9290237297849" } diff --git a/.sqlx/query-a004ad357abfc01b4ab8a2e0a78e2b38f8a0edb7e3b2174d040ac4bb6e5bde39.json b/.sqlx/query-a004ad357abfc01b4ab8a2e0a78e2b38f8a0edb7e3b2174d040ac4bb6e5bde39.json new file mode 100644 index 000000000..e51e87867 --- /dev/null +++ b/.sqlx/query-a004ad357abfc01b4ab8a2e0a78e2b38f8a0edb7e3b2174d040ac4bb6e5bde39.json @@ -0,0 +1,20 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO organizations (id, slug, name, team_id, description, icon_url, color)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Varchar", + "Text", + "Int8", + "Text", + "Varchar", + "Int4" + ] + }, + "nullable": [] + }, + "hash": "a004ad357abfc01b4ab8a2e0a78e2b38f8a0edb7e3b2174d040ac4bb6e5bde39" +} diff --git a/.sqlx/query-da962cbb02919ea79e1106e6e5de39224d240d9b8afb5cead28578ca65e281ae.json b/.sqlx/query-a3448f22ec82f75ab2f3769b7d0a653a7d7315fb5e4696c26c6a96e6fc11e907.json similarity index 74% rename from .sqlx/query-da962cbb02919ea79e1106e6e5de39224d240d9b8afb5cead28578ca65e281ae.json rename to .sqlx/query-a3448f22ec82f75ab2f3769b7d0a653a7d7315fb5e4696c26c6a96e6fc11e907.json index 4a529a0ba..d1a964156 100644 --- a/.sqlx/query-da962cbb02919ea79e1106e6e5de39224d240d9b8afb5cead28578ca65e281ae.json +++ b/.sqlx/query-a3448f22ec82f75ab2f3769b7d0a653a7d7315fb5e4696c26c6a96e6fc11e907.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT m.id FROM organizations o\n INNER JOIN mods m ON m.organization_id = o.id\n WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.name = $2 AND $2 IS NOT NULL)\n ", + "query": "\n SELECT m.id FROM organizations o\n INNER JOIN mods m ON m.organization_id = o.id\n WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.slug = $2 AND $2 IS NOT NULL)\n ", "describe": { "columns": [ { @@ -19,5 +19,5 @@ false ] }, - "hash": "da962cbb02919ea79e1106e6e5de39224d240d9b8afb5cead28578ca65e281ae" + "hash": "a3448f22ec82f75ab2f3769b7d0a653a7d7315fb5e4696c26c6a96e6fc11e907" } diff --git a/.sqlx/query-bd48b18b9bef07185d2d050c7c978904cfbdf4ec765b7d3568f930939e236cbe.json b/.sqlx/query-bd48b18b9bef07185d2d050c7c978904cfbdf4ec765b7d3568f930939e236cbe.json deleted file mode 100644 index 7cf68d08c..000000000 --- a/.sqlx/query-bd48b18b9bef07185d2d050c7c978904cfbdf4ec765b7d3568f930939e236cbe.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO organizations (id, name, team_id, description, icon_url, color)\n VALUES ($1, $2, $3, $4, $5, $6)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Varchar", - "Int8", - "Text", - "Varchar", - "Int4" - ] - }, - "nullable": [] - }, - "hash": "bd48b18b9bef07185d2d050c7c978904cfbdf4ec765b7d3568f930939e236cbe" -} diff --git a/.sqlx/query-26a6271a6d365e64c68ea5855109f1597a121b2e0075b20e2bc34659a269294b.json b/.sqlx/query-c0f23758b879b8a1304ad895b9bcf52b90913f23f96d16c24137b0d529a7475a.json similarity index 64% rename from .sqlx/query-26a6271a6d365e64c68ea5855109f1597a121b2e0075b20e2bc34659a269294b.json rename to .sqlx/query-c0f23758b879b8a1304ad895b9bcf52b90913f23f96d16c24137b0d529a7475a.json index c65458320..bccfc43bc 100644 --- a/.sqlx/query-26a6271a6d365e64c68ea5855109f1597a121b2e0075b20e2bc34659a269294b.json +++ b/.sqlx/query-c0f23758b879b8a1304ad895b9bcf52b90913f23f96d16c24137b0d529a7475a.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color\n FROM organizations o\n LEFT JOIN mods m ON m.organization_id = o.id\n WHERE m.id = $1\n GROUP BY o.id;\n ", + "query": "\n SELECT o.id, o.slug, o.name, o.team_id, o.description, o.icon_url, o.color\n FROM organizations o\n LEFT JOIN mods m ON m.organization_id = o.id\n WHERE m.id = $1\n GROUP BY o.id;\n ", "describe": { "columns": [ { @@ -10,26 +10,31 @@ }, { "ordinal": 1, - "name": "name", + "name": "slug", "type_info": "Varchar" }, { "ordinal": 2, + "name": "name", + "type_info": "Text" + }, + { + "ordinal": 3, "name": "team_id", "type_info": "Int8" }, { - "ordinal": 3, + "ordinal": 4, "name": "description", "type_info": "Text" }, { - "ordinal": 4, + "ordinal": 5, "name": "icon_url", "type_info": "Varchar" }, { - "ordinal": 5, + "ordinal": 6, "name": "color", "type_info": "Int4" } @@ -44,9 +49,10 @@ false, false, false, + false, true, true ] }, - "hash": "26a6271a6d365e64c68ea5855109f1597a121b2e0075b20e2bc34659a269294b" + "hash": "c0f23758b879b8a1304ad895b9bcf52b90913f23f96d16c24137b0d529a7475a" } diff --git a/.sqlx/query-cb57ae673f1a7e50cc319efddb9bdc82e2251596bcf85aea52e8def343e423b8.json b/.sqlx/query-cb57ae673f1a7e50cc319efddb9bdc82e2251596bcf85aea52e8def343e423b8.json new file mode 100644 index 000000000..2a441288f --- /dev/null +++ b/.sqlx/query-cb57ae673f1a7e50cc319efddb9bdc82e2251596bcf85aea52e8def343e423b8.json @@ -0,0 +1,16 @@ +{ + "db_name": "PostgreSQL", + "query": "\n INSERT INTO hashes (file_id, algorithm, hash)\n VALUES ($1, $2, $3)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Varchar", + "Bytea" + ] + }, + "nullable": [] + }, + "hash": "cb57ae673f1a7e50cc319efddb9bdc82e2251596bcf85aea52e8def343e423b8" +} diff --git a/.sqlx/query-d2e826d4fa4e3e730cc84c97964c0c5fdd25cd49ddff8c593bd9b8a3b4d5ff1e.json b/.sqlx/query-d2e826d4fa4e3e730cc84c97964c0c5fdd25cd49ddff8c593bd9b8a3b4d5ff1e.json deleted file mode 100644 index c2b33b115..000000000 --- a/.sqlx/query-d2e826d4fa4e3e730cc84c97964c0c5fdd25cd49ddff8c593bd9b8a3b4d5ff1e.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n INSERT INTO hashes (file_id, algorithm, hash)\n SELECT * FROM UNNEST($1::bigint[], $2::varchar[], $3::bytea[])\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8Array", - "VarcharArray", - "ByteaArray" - ] - }, - "nullable": [] - }, - "hash": "d2e826d4fa4e3e730cc84c97964c0c5fdd25cd49ddff8c593bd9b8a3b4d5ff1e" -} diff --git a/.sqlx/query-eefe0f3e40273da9adea96cdef5fd5cff917a864a701408455cc6b02cd005cf7.json b/.sqlx/query-dbbfd789feb09459ef25b90eba9458e0d4bceb6389eae13a166556f828a6c3a6.json similarity index 57% rename from .sqlx/query-eefe0f3e40273da9adea96cdef5fd5cff917a864a701408455cc6b02cd005cf7.json rename to .sqlx/query-dbbfd789feb09459ef25b90eba9458e0d4bceb6389eae13a166556f828a6c3a6.json index 6cbfaf44f..5865496f5 100644 --- a/.sqlx/query-eefe0f3e40273da9adea96cdef5fd5cff917a864a701408455cc6b02cd005cf7.json +++ b/.sqlx/query-dbbfd789feb09459ef25b90eba9458e0d4bceb6389eae13a166556f828a6c3a6.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE organizations\n SET name = LOWER($1)\n WHERE (id = $2)\n ", + "query": "\n UPDATE organizations\n SET name = $1\n WHERE (id = $2)\n ", "describe": { "columns": [], "parameters": { @@ -11,5 +11,5 @@ }, "nullable": [] }, - "hash": "eefe0f3e40273da9adea96cdef5fd5cff917a864a701408455cc6b02cd005cf7" + "hash": "dbbfd789feb09459ef25b90eba9458e0d4bceb6389eae13a166556f828a6c3a6" } diff --git a/.sqlx/query-ed7cc47dc2acfcaf27c4e763390371dccddbeea902928f1382c9505742f0a9a9.json b/.sqlx/query-ed7cc47dc2acfcaf27c4e763390371dccddbeea902928f1382c9505742f0a9a9.json new file mode 100644 index 000000000..d688ab9f3 --- /dev/null +++ b/.sqlx/query-ed7cc47dc2acfcaf27c4e763390371dccddbeea902928f1382c9505742f0a9a9.json @@ -0,0 +1,15 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE organizations\n SET slug = $1\n WHERE (id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8" + ] + }, + "nullable": [] + }, + "hash": "ed7cc47dc2acfcaf27c4e763390371dccddbeea902928f1382c9505742f0a9a9" +} diff --git a/migrations/20231005230721_dynamic-fields.sql b/migrations/20231005230721_dynamic-fields.sql index 99c5daf81..5956802d5 100644 --- a/migrations/20231005230721_dynamic-fields.sql +++ b/migrations/20231005230721_dynamic-fields.sql @@ -77,7 +77,7 @@ FROM versions v INNER JOIN mods m ON v.mod_id = m.id INNER JOIN loader_field_enum_values lfev ON m.client_side = lfev.original_id CROSS JOIN loader_fields lf -WHERE client_side IS NOT NULL AND lfev.enum_id = 1 AND lf.field = 'client_side'; +WHERE client_side IS NOT NULL AND lfev.enum_id = 1 AND lf.field = 'client_side' AND NOT (ARRAY['vanilla', 'minecraft', 'optifine', 'iris', 'canvas', 'bukkit', 'folia', 'paper', 'purpur', 'spigot', 'sponge', 'datapack', 'bungeecord', 'velocity', 'waterfall'] @> m.loaders::text[]);; INSERT INTO version_fields (version_id, field_id, enum_value) SELECT v.id, lf.id, lfev.id -- Note: bug fix/edited 2023-11-27 @@ -85,7 +85,7 @@ FROM versions v INNER JOIN mods m ON v.mod_id = m.id INNER JOIN loader_field_enum_values lfev ON m.server_side = lfev.original_id CROSS JOIN loader_fields lf -WHERE server_side IS NOT NULL AND lfev.enum_id = 1 AND lf.field = 'server_side'; +WHERE server_side IS NOT NULL AND lfev.enum_id = 1 AND lf.field = 'server_side' AND NOT (ARRAY['vanilla', 'minecraft', 'optifine', 'iris', 'canvas', 'bukkit', 'folia', 'paper', 'purpur', 'spigot', 'sponge', 'datapack', 'bungeecord', 'velocity', 'waterfall'] @> m.loaders::text[]); ALTER TABLE mods DROP COLUMN client_side; ALTER TABLE mods DROP COLUMN server_side; @@ -99,8 +99,12 @@ SELECT id, 2, version, created, json_build_object('type', type, 'major', major) INSERT INTO loader_fields (field, field_type, enum_type, optional, min_val) VALUES('game_versions', 'array_enum', 2, false, 0); INSERT INTO loader_fields_loaders (loader_id, loader_field_id) SELECT l.id, lf.id FROM loaders l CROSS JOIN loader_fields lf WHERE lf.field = 'game_versions' AND l.loader = ANY( ARRAY['forge', 'fabric', 'quilt', 'modloader','rift','liteloader', 'neoforge']); -INSERT INTO version_fields(version_id, field_id, enum_value) -SELECT gvv.joining_version_id, lf.id, lfev.id +-- remove dangling game versions +DELETE FROM game_versions_versions +WHERE joining_version_id NOT IN (SELECT id FROM versions); + +INSERT INTO version_fields(version_id, field_id, enum_value) +SELECT gvv.joining_version_id, lf.id, lfev.id FROM game_versions_versions gvv INNER JOIN loader_field_enum_values lfev ON gvv.game_version_id = lfev.original_id CROSS JOIN loader_fields lf WHERE lf.field = 'game_versions' AND lfev.enum_id = 2; diff --git a/migrations/20231114175920_new-payment-methods.sql b/migrations/20231114175920_new-payment-methods.sql index f5126a8e8..6e852e3f4 100644 --- a/migrations/20231114175920_new-payment-methods.sql +++ b/migrations/20231114175920_new-payment-methods.sql @@ -1,3 +1,5 @@ +ALTER TABLE users DROP COLUMN IF EXISTS paypal_email; + ALTER TABLE users ADD COLUMN paypal_country text NULL, ADD COLUMN paypal_email text NULL, diff --git a/migrations/20231205095400_remaining_loader_field_loaders.sql b/migrations/20231205095400_remaining_loader_field_loaders.sql index 6ff87804f..33e82489f 100644 --- a/migrations/20231205095400_remaining_loader_field_loaders.sql +++ b/migrations/20231205095400_remaining_loader_field_loaders.sql @@ -4,13 +4,18 @@ -- This also allows v2 routes (which have things such as client_side to remain to work with these loaders) INSERT INTO loader_fields_loaders SELECT l.id, lf.id FROM loaders l CROSS JOIN loader_fields lf -WHERE lf.field=ANY(ARRAY['game_versions','client_and_server','server_only','client_only','singleplayer']) +WHERE lf.field=ANY(ARRAY['client_and_server','server_only','client_only','singleplayer']) AND -l.loader NOT IN ('vanilla', 'minecraft', 'optifine', 'iris', 'canvas') +l.loader NOT IN ('vanilla', 'minecraft', 'optifine', 'iris', 'canvas', 'bukkit', 'folia', 'paper', 'purpur', 'spigot', 'sponge', 'datapack', 'bungeecord', 'velocity', 'waterfall') +ON CONFLICT DO NOTHING; + +INSERT INTO loader_fields_loaders +SELECT l.id, lf.id FROM loaders l CROSS JOIN loader_fields lf +WHERE lf.field=ANY(ARRAY['game_versions']) ON CONFLICT DO NOTHING; -- All existing loader_project_types so far should have a games entry as minecraft INSERT INTO loaders_project_types_games SELECT lpt.joining_loader_id, lpt.joining_project_type_id, g.id FROM loaders_project_types lpt CROSS JOIN games g WHERE g.name='minecraft-java' -ON CONFLICT DO NOTHING; \ No newline at end of file +ON CONFLICT DO NOTHING; diff --git a/migrations/20240104203711_orgs-names.sql b/migrations/20240104203711_orgs-names.sql new file mode 100644 index 000000000..a4f8e0d9d --- /dev/null +++ b/migrations/20240104203711_orgs-names.sql @@ -0,0 +1,7 @@ +-- Add migration script here +ALTER TABLE organizations RENAME COLUMN name TO slug; + +ALTER TABLE organizations ADD COLUMN name text NULL; +UPDATE organizations SET name = slug; +ALTER TABLE organizations ALTER COLUMN name SET NOT NULL; + diff --git a/src/database/models/organization_item.rs b/src/database/models/organization_item.rs index 1c5647203..c0c089499 100644 --- a/src/database/models/organization_item.rs +++ b/src/database/models/organization_item.rs @@ -15,7 +15,10 @@ pub struct Organization { /// The id of the organization pub id: OrganizationId, - /// The title (and slug) of the organization + /// The slug of the organization + pub slug: String, + + /// The title of the organization pub name: String, /// The associated team of the organization @@ -36,10 +39,11 @@ impl Organization { ) -> Result<(), super::DatabaseError> { sqlx::query!( " - INSERT INTO organizations (id, name, team_id, description, icon_url, color) - VALUES ($1, $2, $3, $4, $5, $6) + INSERT INTO organizations (id, slug, name, team_id, description, icon_url, color) + VALUES ($1, $2, $3, $4, $5, $6, $7) ", self.id.0, + self.slug, self.name, self.team_id as TeamId, self.description, @@ -149,7 +153,7 @@ impl Organization { { remaining_strings.retain(|x| { &to_base62(organization.id.0 as u64) != x - && organization.name.to_lowercase() != x.to_lowercase() + && organization.slug.to_lowercase() != x.to_lowercase() }); found_organizations.push(organization); continue; @@ -166,9 +170,9 @@ impl Organization { let organizations: Vec = sqlx::query!( " - SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color + SELECT o.id, o.slug, o.name, o.team_id, o.description, o.icon_url, o.color FROM organizations o - WHERE o.id = ANY($1) OR LOWER(o.name) = ANY($2) + WHERE o.id = ANY($1) OR LOWER(o.slug) = ANY($2) GROUP BY o.id; ", &organization_ids_parsed, @@ -181,6 +185,7 @@ impl Organization { .try_filter_map(|e| async { Ok(e.right().map(|m| Organization { id: OrganizationId(m.id), + slug: m.slug, name: m.name, team_id: TeamId(m.team_id), description: m.description, @@ -203,7 +208,7 @@ impl Organization { redis .set( ORGANIZATIONS_TITLES_NAMESPACE, - &organization.name.to_lowercase(), + &organization.slug.to_lowercase(), &organization.id.0.to_string(), None, ) @@ -226,7 +231,7 @@ impl Organization { { let result = sqlx::query!( " - SELECT o.id, o.name, o.team_id, o.description, o.icon_url, o.color + SELECT o.id, o.slug, o.name, o.team_id, o.description, o.icon_url, o.color FROM organizations o LEFT JOIN mods m ON m.organization_id = o.id WHERE m.id = $1 @@ -240,6 +245,7 @@ impl Organization { if let Some(result) = result { Ok(Some(Organization { id: OrganizationId(result.id), + slug: result.slug, name: result.name, team_id: TeamId(result.team_id), description: result.description, @@ -299,7 +305,7 @@ impl Organization { pub async fn clear_cache( id: OrganizationId, - title: Option, + slug: Option, redis: &RedisPool, ) -> Result<(), super::DatabaseError> { let mut redis = redis.connect().await?; @@ -309,7 +315,7 @@ impl Organization { (ORGANIZATIONS_NAMESPACE, Some(id.0.to_string())), ( ORGANIZATIONS_TITLES_NAMESPACE, - title.map(|x| x.to_lowercase()), + slug.map(|x| x.to_lowercase()), ), ]) .await?; diff --git a/src/database/models/project_item.rs b/src/database/models/project_item.rs index f2e31fcee..3d3635d0b 100644 --- a/src/database/models/project_item.rs +++ b/src/database/models/project_item.rs @@ -273,13 +273,13 @@ impl Project { id, team_id, name, summary, description, published, downloads, icon_url, status, requested_status, license_url, license, - slug, color, monetization_status + slug, color, monetization_status, organization_id ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, - LOWER($13), $14, $15 + LOWER($13), $14, $15, $16 ) ", self.id as ProjectId, @@ -297,6 +297,7 @@ impl Project { self.slug.as_ref(), self.color.map(|x| x as i32), self.monetization_status.as_str(), + self.organization_id.map(|x| x.0 as i64), ) .execute(&mut **transaction) .await?; diff --git a/src/database/models/team_item.rs b/src/database/models/team_item.rs index 5b1acd339..2dd0a2f76 100644 --- a/src/database/models/team_item.rs +++ b/src/database/models/team_item.rs @@ -412,10 +412,10 @@ impl TeamMember { sqlx::query!( " INSERT INTO team_members ( - id, team_id, user_id, role, permissions, organization_permissions, is_owner, accepted + id, team_id, user_id, role, permissions, organization_permissions, is_owner, accepted, payouts_split ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8 + $1, $2, $3, $4, $5, $6, $7, $8, $9 ) ", self.id as TeamMemberId, @@ -426,6 +426,7 @@ impl TeamMember { self.organization_permissions.map(|p| p.bits() as i64), self.is_owner, self.accepted, + self.payouts_split ) .execute(&mut **transaction) .await?; diff --git a/src/database/models/version_item.rs b/src/database/models/version_item.rs index c87060e1d..811f42fc2 100644 --- a/src/database/models/version_item.rs +++ b/src/database/models/version_item.rs @@ -126,70 +126,42 @@ pub struct VersionFileBuilder { } impl VersionFileBuilder { - pub async fn insert_many( - version_files: Vec, + pub async fn insert( + self, version_id: VersionId, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result { - let file_id = generate_file_id(transaction).await?; + let file_id = generate_file_id(&mut *transaction).await?; - let (file_ids, version_ids, urls, filenames, primary, sizes, file_types): ( - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - Vec<_>, - ) = version_files - .iter() - .map(|f| { - ( - file_id.0, - version_id.0, - f.url.clone(), - f.filename.clone(), - f.primary, - f.size as i32, - f.file_type.map(|x| x.to_string()), - ) - }) - .multiunzip(); sqlx::query!( " INSERT INTO files (id, version_id, url, filename, is_primary, size, file_type) - SELECT * FROM UNNEST($1::bigint[], $2::bigint[], $3::varchar[], $4::varchar[], $5::bool[], $6::integer[], $7::varchar[]) + VALUES ($1, $2, $3, $4, $5, $6, $7) ", - &file_ids[..], - &version_ids[..], - &urls[..], - &filenames[..], - &primary[..], - &sizes[..], - &file_types[..] as &[Option], + file_id as FileId, + version_id as VersionId, + self.url, + self.filename, + self.primary, + self.size as i32, + self.file_type.map(|x| x.as_str()), ) .execute(&mut **transaction) .await?; - let (file_ids, algorithms, hashes): (Vec<_>, Vec<_>, Vec<_>) = version_files - .into_iter() - .flat_map(|f| { - f.hashes - .into_iter() - .map(|h| (file_id.0, h.algorithm, h.hash)) - }) - .multiunzip(); - sqlx::query!( - " - INSERT INTO hashes (file_id, algorithm, hash) - SELECT * FROM UNNEST($1::bigint[], $2::varchar[], $3::bytea[]) - ", - &file_ids[..], - &algorithms[..], - &hashes[..], - ) - .execute(&mut **transaction) - .await?; + for hash in self.hashes { + sqlx::query!( + " + INSERT INTO hashes (file_id, algorithm, hash) + VALUES ($1, $2, $3) + ", + file_id as FileId, + hash.algorithm, + hash.hash, + ) + .execute(&mut **transaction) + .await?; + } Ok(file_id) } @@ -242,7 +214,10 @@ impl VersionBuilder { version_id, .. } = self; - VersionFileBuilder::insert_many(files, self.version_id, transaction).await?; + + for file in files { + file.insert(version_id, transaction).await?; + } DependencyBuilder::insert_many(dependencies, self.version_id, transaction).await?; diff --git a/src/models/v2/projects.rs b/src/models/v2/projects.rs index 5deb81c97..f9c2f4a92 100644 --- a/src/models/v2/projects.rs +++ b/src/models/v2/projects.rs @@ -83,24 +83,23 @@ impl LegacyProject { let mut game_versions = Vec::new(); // V2 versions only have one project type- v3 versions can rarely have multiple. - // We'll prioritize 'modpack' first, then 'mod', and if neither are found, use the first one. + // We'll prioritize 'modpack' first, and if neither are found, use the first one. // If there are no project types, default to 'project' let mut project_types = data.project_types; if project_types.contains(&"modpack".to_string()) { project_types = vec!["modpack".to_string()]; - } else if project_types.contains(&"mod".to_string()) { - project_types = vec!["mod".to_string()]; } - let project_type = project_types + + let og_project_type = project_types .first() .cloned() .unwrap_or("project".to_string()); // Default to 'project' if none are found - let mut project_type = if project_type == "datapack" || project_type == "plugin" { + let mut project_type = if og_project_type == "datapack" || og_project_type == "plugin" { // These are not supported in V2, so we'll just use 'mod' instead "mod".to_string() } else { - project_type + og_project_type.clone() }; let mut loaders = data.loaders; @@ -120,7 +119,8 @@ impl LegacyProject { .iter() .map(|f| (f.field_name.clone(), f.value.clone().serialize_internal())) .collect::>(); - (client_side, server_side) = v2_reroute::convert_side_types_v2(&fields); + (client_side, server_side) = + v2_reroute::convert_side_types_v2(&fields, Some(&*og_project_type)); // - if loader is mrpack, this is a modpack // the loaders are whatever the corresponding loader fields are diff --git a/src/models/v2/search.rs b/src/models/v2/search.rs index 746710fce..db169eea6 100644 --- a/src/models/v2/search.rs +++ b/src/models/v2/search.rs @@ -75,24 +75,22 @@ impl LegacyResultSearchProject { display_categories.dedup(); // V2 versions only have one project type- v3 versions can rarely have multiple. - // We'll prioritize 'modpack' first, then 'mod', and if neither are found, use the first one. + // We'll prioritize 'modpack' first, and if neither are found, use the first one. // If there are no project types, default to 'project' let mut project_types = result_search_project.project_types; if project_types.contains(&"modpack".to_string()) { project_types = vec!["modpack".to_string()]; - } else if project_types.contains(&"mod".to_string()) { - project_types = vec!["mod".to_string()]; } - let project_type = project_types + let og_project_type = project_types .first() .cloned() .unwrap_or("project".to_string()); // Default to 'project' if none are found - let project_type = if project_type == "datapack" || project_type == "plugin" { + let project_type = if og_project_type == "datapack" || og_project_type == "plugin" { // These are not supported in V2, so we'll just use 'mod' instead "mod".to_string() } else { - project_type + og_project_type.clone() }; let loader_fields = result_search_project.loader_fields.clone(); @@ -115,6 +113,7 @@ impl LegacyResultSearchProject { client_only, server_only, client_and_server, + Some(&*og_project_type), ); let client_side = client_side.to_string(); let server_side = server_side.to_string(); diff --git a/src/models/v3/organizations.rs b/src/models/v3/organizations.rs index 984be2335..47e541f47 100644 --- a/src/models/v3/organizations.rs +++ b/src/models/v3/organizations.rs @@ -15,6 +15,8 @@ pub struct OrganizationId(pub u64); pub struct Organization { /// The id of the organization pub id: OrganizationId, + /// The slug of the organization + pub slug: String, /// The title (and slug) of the organization pub name: String, /// The associated team of the organization @@ -38,6 +40,7 @@ impl Organization { ) -> Self { Self { id: data.id.into(), + slug: data.slug, name: data.name, team_id: data.team_id.into(), description: data.description, diff --git a/src/routes/v2/projects.rs b/src/routes/v2/projects.rs index eb171ac63..f6c2f41c9 100644 --- a/src/routes/v2/projects.rs +++ b/src/routes/v2/projects.rs @@ -497,7 +497,7 @@ pub async fn project_edit( let version = Version::from(version); let mut fields = version.fields; let (current_client_side, current_server_side) = - v2_reroute::convert_side_types_v2(&fields); + v2_reroute::convert_side_types_v2(&fields, None); let client_side = client_side.unwrap_or(current_client_side); let server_side = server_side.unwrap_or(current_server_side); fields.extend(v2_reroute::convert_side_types_v3(client_side, server_side)); diff --git a/src/routes/v2/tags.rs b/src/routes/v2/tags.rs index c99c69362..7d1fcfeea 100644 --- a/src/routes/v2/tags.rs +++ b/src/routes/v2/tags.rs @@ -79,16 +79,22 @@ pub async fn loader_list( Ok(loaders) => { let loaders = loaders .into_iter() - .map(|l| LoaderData { - icon: l.icon, - name: l.name, + .filter(|l| &*l.name != "mrpack") + .map(|l| { + let mut supported_project_types = l.supported_project_types; // Add generic 'project' type to all loaders, which is the v2 representation of // a project type before any versions are set. - supported_project_types: l - .supported_project_types - .into_iter() - .chain(std::iter::once("project".to_string())) - .collect(), + supported_project_types.push("project".to_string()); + + if ["forge", "fabric", "quilt", "neoforge"].contains(&&*l.name) { + supported_project_types.push("modpack".to_string()); + } + + LoaderData { + icon: l.icon, + name: l.name, + supported_project_types, + } }) .collect::>(); Ok(HttpResponse::Ok().json(loaders)) diff --git a/src/routes/v2_reroute.rs b/src/routes/v2_reroute.rs index 40a0d9234..ea1bff897 100644 --- a/src/routes/v2_reroute.rs +++ b/src/routes/v2_reroute.rs @@ -242,6 +242,7 @@ pub fn convert_side_type_facets_v3(facets: Vec>>) -> Vec, + project_type: Option<&str>, ) -> (LegacySideType, LegacySideType) { let client_and_server = side_types .get("client_and_server") @@ -265,6 +266,7 @@ pub fn convert_side_types_v2( client_only, server_only, Some(client_and_server), + project_type, ) } @@ -274,29 +276,38 @@ pub fn convert_side_types_v2_bools( client_only: bool, server_only: bool, client_and_server: Option, + project_type: Option<&str>, ) -> (LegacySideType, LegacySideType) { - use LegacySideType::{Optional, Required, Unsupported}; + use LegacySideType::{Optional, Required, Unknown, Unsupported}; - let singleplayer = singleplayer.or(client_and_server).unwrap_or(false); + match project_type { + Some("plugin") => (Unsupported, Required), + Some("datapack") => (Optional, Required), + Some("shader") => (Required, Unsupported), + Some("resourcepack") => (Required, Unsupported), + _ => { + let singleplayer = singleplayer.or(client_and_server).unwrap_or(false); - match (singleplayer, client_only, server_only) { - // Only singleplayer - (true, false, false) => (Required, Required), + match (singleplayer, client_only, server_only) { + // Only singleplayer + (true, false, false) => (Required, Required), - // Client only and not server only - (false, true, false) => (Required, Unsupported), - (true, true, false) => (Required, Unsupported), + // Client only and not server only + (false, true, false) => (Required, Unsupported), + (true, true, false) => (Required, Unsupported), - // Server only and not client only - (false, false, true) => (Unsupported, Required), - (true, false, true) => (Unsupported, Required), + // Server only and not client only + (false, false, true) => (Unsupported, Required), + (true, false, true) => (Unsupported, Required), - // Both server only and client only - (true, true, true) => (Optional, Optional), - (false, true, true) => (Optional, Optional), + // Both server only and client only + (true, true, true) => (Optional, Optional), + (false, true, true) => (Optional, Optional), - // Bad type - (false, false, false) => (Unsupported, Unsupported), + // Bad type + (false, false, false) => (Unknown, Unknown), + } + } } } @@ -321,6 +332,7 @@ mod tests { (Unsupported, Optional), (Required, Optional), (Optional, Required), + (Unsupported, Unsupported), ]; for client_side in [Required, Optional, Unsupported] { @@ -329,7 +341,7 @@ mod tests { continue; } let side_types = convert_side_types_v3(client_side, server_side); - let (client_side2, server_side2) = convert_side_types_v2(&side_types); + let (client_side2, server_side2) = convert_side_types_v2(&side_types, None); assert_eq!(client_side, client_side2); assert_eq!(server_side, server_side2); } diff --git a/src/routes/v3/organizations.rs b/src/routes/v3/organizations.rs index c703f38ea..955233e31 100644 --- a/src/routes/v3/organizations.rs +++ b/src/routes/v3/organizations.rs @@ -72,7 +72,7 @@ pub async fn organization_projects_get( " SELECT m.id FROM organizations o INNER JOIN mods m ON m.organization_id = o.id - WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.name = $2 AND $2 IS NOT NULL) + WHERE (o.id = $1 AND $1 IS NOT NULL) OR (o.slug = $2 AND $2 IS NOT NULL) ", possible_organization_id.map(|x| x as i64), info @@ -95,7 +95,9 @@ pub struct NewOrganization { length(min = 3, max = 64), regex = "crate::util::validate::RE_URL_SAFE" )] - // Title of the organization, also used as slug + pub slug: String, + // Title of the organization + #[validate(length(min = 3, max = 64))] pub name: String, #[validate(length(min = 3, max = 256))] pub description: String, @@ -126,12 +128,12 @@ pub async fn organization_create( // Try title let name_organization_id_option: Option = - serde_json::from_str(&format!("\"{}\"", new_organization.name)).ok(); + serde_json::from_str(&format!("\"{}\"", new_organization.slug)).ok(); let mut organization_strings = vec![]; if let Some(name_organization_id) = name_organization_id_option { organization_strings.push(name_organization_id.to_string()); } - organization_strings.push(new_organization.name.clone()); + organization_strings.push(new_organization.slug.clone()); let results = Organization::get_many(&organization_strings, &mut *transaction, &redis).await?; if !results.is_empty() { return Err(CreateError::SlugCollision); @@ -157,6 +159,7 @@ pub async fn organization_create( // Create organization let organization = Organization { id: organization_id, + slug: new_organization.slug.clone(), name: new_organization.name.clone(), description: new_organization.description.clone(), team_id, @@ -336,7 +339,8 @@ pub struct OrganizationEdit { length(min = 3, max = 64), regex = "crate::util::validate::RE_URL_SAFE" )] - // Title of the organization, also used as slug + pub slug: Option, + #[validate(length(min = 3, max = 64))] pub name: Option, } @@ -406,8 +410,28 @@ pub async fn organizations_edit( .to_string(), )); } + sqlx::query!( + " + UPDATE organizations + SET name = $1 + WHERE (id = $2) + ", + name, + id as database::models::ids::OrganizationId, + ) + .execute(&mut *transaction) + .await?; + } - let name_organization_id_option: Option = parse_base62(name).ok(); + if let Some(slug) = &new_organization.slug { + if !perms.contains(OrganizationPermissions::EDIT_DETAILS) { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the slug of this organization!" + .to_string(), + )); + } + + let name_organization_id_option: Option = parse_base62(slug).ok(); if let Some(name_organization_id) = name_organization_id_option { let results = sqlx::query!( " @@ -420,26 +444,26 @@ pub async fn organizations_edit( if results.exists.unwrap_or(true) { return Err(ApiError::InvalidInput( - "name collides with other organization's id!".to_string(), + "slug collides with other organization's id!".to_string(), )); } } // Make sure the new name is different from the old one // We are able to unwrap here because the name is always set - if !name.eq(&organization_item.name.clone()) { + if !slug.eq(&organization_item.slug.clone()) { let results = sqlx::query!( " - SELECT EXISTS(SELECT 1 FROM organizations WHERE name = LOWER($1)) - ", - name + SELECT EXISTS(SELECT 1 FROM organizations WHERE LOWER(slug) = LOWER($1)) + ", + slug ) .fetch_one(&mut *transaction) .await?; if results.exists.unwrap_or(true) { return Err(ApiError::InvalidInput( - "Name collides with other organization's id!".to_string(), + "slug collides with other organization's id!".to_string(), )); } } @@ -447,10 +471,10 @@ pub async fn organizations_edit( sqlx::query!( " UPDATE organizations - SET name = LOWER($1) + SET slug = $1 WHERE (id = $2) ", - Some(name), + Some(slug), id as database::models::ids::OrganizationId, ) .execute(&mut *transaction) @@ -460,7 +484,7 @@ pub async fn organizations_edit( transaction.commit().await?; database::models::Organization::clear_cache( organization_item.id, - Some(organization_item.name), + Some(organization_item.slug), &redis, ) .await?; @@ -578,7 +602,7 @@ pub async fn organization_delete( transaction.commit().await?; - database::models::Organization::clear_cache(organization.id, Some(organization.name), &redis) + database::models::Organization::clear_cache(organization.id, Some(organization.slug), &redis) .await?; for team_id in organization_project_teams { @@ -994,7 +1018,7 @@ pub async fn organization_icon_edit( transaction.commit().await?; database::models::Organization::clear_cache( organization_item.id, - Some(organization_item.name), + Some(organization_item.slug), &redis, ) .await?; @@ -1079,7 +1103,7 @@ pub async fn delete_organization_icon( database::models::Organization::clear_cache( organization_item.id, - Some(organization_item.name), + Some(organization_item.slug), &redis, ) .await?; diff --git a/src/routes/v3/project_creation.rs b/src/routes/v3/project_creation.rs index fe89b1958..96fc257f0 100644 --- a/src/routes/v3/project_creation.rs +++ b/src/routes/v3/project_creation.rs @@ -73,7 +73,7 @@ pub enum CreateError { InvalidCategory(String), #[error("Invalid file type for version file: {0}")] InvalidFileType(String), - #[error("Slug collides with other project's id!")] + #[error("Slug is already taken!")] SlugCollision, #[error("Authentication Error: {0}")] Unauthorized(#[from] AuthenticationError), @@ -612,22 +612,22 @@ async fn project_create_inner( additional_categories.extend(ids.values()); } - // Should only be owner if not attached to an organization - let is_owner = project_create_data.organization_id.is_none(); + let mut members = vec![]; - let team = models::team_item::TeamBuilder { - members: vec![models::team_item::TeamMemberBuilder { + if project_create_data.organization_id.is_none() { + members.push(models::team_item::TeamMemberBuilder { user_id: current_user.id.into(), role: crate::models::teams::OWNER_ROLE.to_owned(), - is_owner, - // Allow all permissions for project creator, even if attached to a project + is_owner: true, permissions: ProjectPermissions::all(), organization_permissions: None, accepted: true, payouts_split: Decimal::ONE_HUNDRED, ordering: 0, - }], - }; + }) + } + + let team = models::team_item::TeamBuilder { members }; let team_id = team.insert(&mut *transaction).await?; diff --git a/src/routes/v3/teams.rs b/src/routes/v3/teams.rs index 473cd2f67..ea4da134e 100644 --- a/src/routes/v3/teams.rs +++ b/src/routes/v3/teams.rs @@ -65,7 +65,7 @@ pub async fn team_members_get_project( } let members_data = TeamMember::get_from_team_full(project.inner.team_id, &**pool, &redis).await?; - let users = crate::database::models::User::get_many_ids( + let users = User::get_many_ids( &members_data.iter().map(|x| x.user_id).collect::>(), &**pool, &redis, @@ -73,14 +73,14 @@ pub async fn team_members_get_project( .await?; let user_id = current_user.as_ref().map(|x| x.id.into()); + let logged_in = if let Some(user_id) = user_id { + let (team_member, organization_team_member) = + TeamMember::get_for_project_permissions(&project.inner, user_id, &**pool).await?; - let logged_in = current_user - .and_then(|user| { - members_data - .iter() - .find(|x| x.user_id == user.id.into() && x.accepted) - }) - .is_some(); + team_member.is_some() || organization_team_member.is_some() + } else { + false + }; let team_members: Vec<_> = members_data .into_iter() diff --git a/src/routes/v3/version_creation.rs b/src/routes/v3/version_creation.rs index 11294975d..f04fbe976 100644 --- a/src/routes/v3/version_creation.rs +++ b/src/routes/v3/version_creation.rs @@ -731,7 +731,9 @@ async fn upload_file_to_version_inner( "At least one file must be specified".to_string(), )); } else { - VersionFileBuilder::insert_many(file_builders, version_id, &mut *transaction).await?; + for file in file_builders { + file.insert(version_id, &mut *transaction).await?; + } } // Clear version cache diff --git a/src/search/indexing/local_import.rs b/src/search/indexing/local_import.rs index b988d5a35..28a8d36a0 100644 --- a/src/search/indexing/local_import.rs +++ b/src/search/indexing/local_import.rs @@ -163,6 +163,9 @@ pub async fn index_local( }) .unwrap_or_default(); categories.extend(mrpack_loaders); + if loader_fields.contains_key("mrpack_loaders") { + categories.retain(|x| *x != "mrpack"); + } let gallery = m .gallery_items diff --git a/tests/search.rs b/tests/search.rs index 111dde8a6..f8f95a62e 100644 --- a/tests/search.rs +++ b/tests/search.rs @@ -11,7 +11,7 @@ use serde_json::json; mod common; -// TODO: Revisit this with the new modify_json in the version maker +// TODO: Revisit this wit h the new modify_json in the version maker // That change here should be able to simplify it vastly #[actix_rt::test] @@ -61,17 +61,13 @@ async fn search_projects() { ), // Project type change // Modpack should still be able to search based on former loader, even though technically the loader is 'mrpack' - (json!([["categories:mrpack"]]), vec![4]), + // (json!([["categories:mrpack"]]), vec![4]), + // ( + // json!([["categories:fabric"]]), + // vec![4], + // ), ( - json!([["categories:mrpack"], ["categories:fabric"]]), - vec![4], - ), - ( - json!([ - ["categories:mrpack"], - ["categories:fabric"], - ["project_types:modpack"] - ]), + json!([["categories:fabric"], ["project_types:modpack"]]), vec![4], ), ]; diff --git a/tests/v2/search.rs b/tests/v2/search.rs index 94ac908ba..df77de9c4 100644 --- a/tests/v2/search.rs +++ b/tests/v2/search.rs @@ -259,14 +259,14 @@ async fn search_projects() { ), // Project type change // Modpack should still be able to search based on former loader, even though technically the loader is 'mrpack' - (json!([["categories:mrpack"]]), vec![4]), - ( - json!([["categories:mrpack"], ["categories:fabric"]]), - vec![4], - ), + // (json!([["categories:mrpack"]]), vec![4]), + // ( + // json!([["categories:mrpack"], ["categories:fabric"]]), + // vec![4], + // ), ( json!([ - ["categories:mrpack"], + // ["categories:mrpack"], ["categories:fabric"], ["project_type:modpack"] ]), diff --git a/tests/v2/tags.rs b/tests/v2/tags.rs index 9b854337b..25663db6b 100644 --- a/tests/v2/tags.rs +++ b/tests/v2/tags.rs @@ -46,7 +46,7 @@ async fn get_tags() { let loader_names = loaders.into_iter().map(|x| x.name).collect::>(); assert_eq!( loader_names, - ["fabric", "forge", "mrpack", "bukkit", "waterfall"] + ["fabric", "forge", "bukkit", "waterfall"] .iter() .map(|s| s.to_string()) .collect()