From e7c3f8bf474195be36e0e27681f6913dc2a294a3 Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Fri, 2 Sep 2022 12:38:58 -0700 Subject: [PATCH] Initial work on payouts (badges, perms, splits) (#440) * Initial work on payouts (badges, perms, splits) * Fix clippy error, bitflag consistency --- migrations/20220902025606_initial-payouts.sql | 7 + sqlx-data.json | 1559 +++++++++-------- src/database/models/mod.rs | 2 - src/database/models/team_item.rs | 154 +- src/database/models/user_item.rs | 18 +- src/models/teams.rs | 12 +- src/models/users.rs | 25 + src/routes/auth.rs | 3 +- src/routes/project_creation.rs | 1 + src/routes/teams.rs | 23 + src/routes/users.rs | 24 +- src/util/auth.rs | 1 + src/validate/liteloader.rs | 2 +- 13 files changed, 1030 insertions(+), 801 deletions(-) create mode 100644 migrations/20220902025606_initial-payouts.sql diff --git a/migrations/20220902025606_initial-payouts.sql b/migrations/20220902025606_initial-payouts.sql new file mode 100644 index 000000000..9048c2740 --- /dev/null +++ b/migrations/20220902025606_initial-payouts.sql @@ -0,0 +1,7 @@ +ALTER TABLE team_members ADD COLUMN payouts_split REAL NOT NULL DEFAULT 0; + +UPDATE team_members +SET permissions = 1023, payouts_split = 100 +WHERE role = 'Owner'; + +ALTER TABLE users ADD COLUMN badges bigint default 0 NOT NULL; diff --git a/sqlx-data.json b/sqlx-data.json index 2d94c2569..81d36a0a4 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -1,49 +1,5 @@ { "db": "PostgreSQL", - "017c9fd0c8103c590489453a25b3317e6790a21f388bcf7ec8c93cd26255f368": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "team_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 4, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT id, team_id, role, permissions, accepted\n FROM team_members\n WHERE (user_id = $1 AND accepted = TRUE)\n " - }, "0267d1ea5387d4acfc132aeb4776004a1ebb048e7789e686bfaba3357d392f62": { "describe": { "columns": [], @@ -112,6 +68,56 @@ }, "query": "\n UPDATE mods\n SET moderation_message_body = NULL\n WHERE (id = $1)\n " }, + "059d6aedca1ccafde301f9966925b1bf6137909bc8fda56ddea73d9425186354": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT id, user_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE team_id = $1\n " + }, "05baeb26d9856218e5c6f8856a96788b2a7ac3536ff9412a50552cef1d561a1e": { "describe": { "columns": [], @@ -451,6 +457,80 @@ }, "query": "\n INSERT INTO report_types (name)\n VALUES ($1)\n ON CONFLICT (name) DO NOTHING\n RETURNING id\n " }, + "0dc684e5ef32880e360e0a624ccb80a2cc9c0ea7791f3cc3e07c1e280f9d2a18": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 9, + "type_info": "Int8" + } + ], + "nullable": [ + false, + true, + true, + true, + true, + false, + true, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.id = ANY($1)\n " + }, "0f29bb5ba767ebd0669c860994e48e3cb2674f0d53f6c4ab85c79d46b04cbb40": { "describe": { "columns": [ @@ -648,74 +728,6 @@ }, "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 " }, - "191a613898e0bedc6f7bc15e6a2b986f1c75012780db8d96caba476c81692520": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 8, - "type_info": "Varchar" - } - ], - "nullable": [ - false, - true, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8Array" - ] - } - }, - "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role FROM users u\n WHERE u.id = ANY($1)\n " - }, "19422e88b1b13318d75e8eb2ba142a562c550358b3136eef9ef73b5a216bbcdb": { "describe": { "columns": [ @@ -1029,6 +1041,56 @@ }, "query": "\n DELETE FROM notifications_actions\n WHERE notification_id = ANY($1)\n " }, + "27ad9c2f4ea8a6ada993944c158310dfbe0913c2916b182fd7864177efd04e46": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT id, team_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE (user_id = $1 AND accepted = TRUE)\n " + }, "28be156dc8d8c394dd7c8de33a8e45be9c2d9033de461c0b7365cd8e7585aa8d": { "describe": { "columns": [], @@ -1197,50 +1259,6 @@ }, "query": "\n UPDATE mods\n SET follows = follows - 1\n WHERE id = $1\n " }, - "3831c1b321e47690f1f54597506a0d43362eda9540c56acb19c06532bba50b01": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 4, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT id, user_id, role, permissions, accepted\n FROM team_members\n WHERE team_id = $1\n " - }, "391f734b23be4346960ea82bc3d0cefe7de025fe0e400634e3dfc136486e7fc9": { "describe": { "columns": [ @@ -1675,6 +1693,63 @@ }, "query": "\n SELECT follower_id FROM mod_follows\n WHERE mod_id = $1\n " }, + "496a710e45c1d0603667e5b7117c02162e27c3ce7b905b2691fda8e046c5373b": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 4, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 5, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 6, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "\n SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM versions v\n INNER JOIN mods m ON m.id = v.mod_id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.user_id = $2 AND tm.accepted = TRUE\n WHERE v.id = $1\n " + }, "49a5d21a1454afc6383b78e468fd0decc75b9163e7286f34ceab22d563a0d3f7": { "describe": { "columns": [], @@ -1741,50 +1816,73 @@ }, "query": "\n INSERT INTO project_types (name)\n VALUES ($1)\n ON CONFLICT (name) DO NOTHING\n RETURNING id\n " }, - "4b305fba5341b183cc07048aef48dc593c7a2fdf7abb82f7440e5a63786ebe7b": { + "4b734b2afeaee2025f489dbce25df3ef80eae17576e49d321cb8357b0327e4b7": { "describe": { "columns": [ { - "name": "id", + "name": "github_id", "ordinal": 0, "type_info": "Int8" }, { - "name": "user_id", + "name": "name", "ordinal": 1, - "type_info": "Int8" + "type_info": "Varchar" }, { - "name": "role", + "name": "email", "ordinal": 2, "type_info": "Varchar" }, { - "name": "permissions", + "name": "avatar_url", "ordinal": 3, - "type_info": "Int8" + "type_info": "Varchar" }, { - "name": "accepted", + "name": "username", "ordinal": 4, - "type_info": "Bool" + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 6, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 8, + "type_info": "Int8" } ], "nullable": [ + true, + true, + true, + true, false, - false, + true, false, false, false ], "parameters": { "Left": [ - "Int8", "Int8" ] } }, - "query": "\n SELECT id, user_id, role, permissions, accepted\n FROM team_members\n WHERE (team_id = $1 AND user_id = $2 AND accepted = TRUE)\n " + "query": "\n SELECT u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.id = $1\n " }, "4cfafb61d38608152743c38cb8fb9a9c35e788fcbefe6f7f81476a3f144af3f8": { "describe": { @@ -2016,7 +2114,7 @@ }, "query": "\n SELECT v.mod_id, v.author_id, v.name, v.version_number,\n v.changelog, v.changelog_url, v.date_published, v.downloads,\n v.version_type, v.featured\n FROM versions v\n WHERE v.id = $1\n " }, - "5564434408e4b88ff1bdd14e0d32a35136e5ee0c837655fbde7d3ca9182dc25b": { + "56b099001ed5799d71d8a5a7ffcdb826dd8185b03781445c4d63d59072f6bed1": { "describe": { "columns": [ { @@ -2025,29 +2123,74 @@ "type_info": "Int8" }, { - "name": "team_id", + "name": "member_role", "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 3, "type_info": "Varchar" }, { "name": "permissions", - "ordinal": 4, + "ordinal": 2, "type_info": "Int8" }, { "name": "accepted", - "ordinal": 5, + "ordinal": 3, "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 4, + "type_info": "Float4" + }, + { + "name": "user_id", + "ordinal": 5, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "user_name", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 10, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 12, + "type_info": "Timestamptz" + }, + { + "name": "user_role", + "ordinal": 13, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 14, + "type_info": "Int8" } ], "nullable": [ @@ -2056,16 +2199,24 @@ false, false, false, + false, + true, + true, + true, + true, + false, + true, + false, + false, false ], "parameters": { "Left": [ - "Int8", "Int8" ] } }, - "query": "\n SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM mods m\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND user_id = $2 AND accepted = TRUE\n WHERE m.id = $1\n " + "query": "\n SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = $1\n " }, "57a38641fe5bdb273190e8d586f46284340b9ff11b6ae3177923631a37bb11eb": { "describe": { @@ -2401,6 +2552,80 @@ }, "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 " }, + "5f4a3899e55b67ed096c6e0efd1f95ac27be7c81f1e4c5b2145c28fc8b28397a": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 6, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 7, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 9, + "type_info": "Int8" + } + ], + "nullable": [ + false, + true, + true, + true, + true, + false, + true, + false, + false, + false + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE LOWER(u.username) = LOWER($1)\n " + }, "5f94e9e767ec4be7f9136b991b4a29373dbe48feb2f61281e3212721095ed675": { "describe": { "columns": [], @@ -2481,57 +2706,6 @@ }, "query": "\n SELECT version.id id FROM (\n SELECT DISTINCT ON(v.id) v.id, v.date_published FROM versions v\n INNER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id AND gvv.game_version_id IN (SELECT game_version_id FROM game_versions_versions WHERE joining_version_id = $2)\n INNER JOIN loaders_versions lv ON lv.version_id = v.id AND lv.loader_id IN (SELECT loader_id FROM loaders_versions WHERE version_id = $2)\n WHERE v.mod_id = $1\n ) AS version\n ORDER BY version.date_published DESC\n LIMIT 1\n " }, - "64570e9cadd7391ad45a1029a0e5212e17720c4f65682384d7493fc350114228": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "team_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 5, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8Array", - "Int8" - ] - } - }, - "query": "\n SELECT id, team_id, user_id, role, permissions, accepted\n FROM team_members\n WHERE (team_id = ANY($1) AND user_id = $2 AND accepted = TRUE)\n " - }, "67d021f0776276081d3c50ca97afa6b78b98860bf929009e845e9c00a192e3b5": { "describe": { "columns": [ @@ -2795,6 +2969,19 @@ }, "query": "\n SELECT v.mod_id project_id FROM hashes h\n INNER JOIN files f ON h.file_id = f.id\n INNER JOIN versions v ON v.id = f.version_id\n INNER JOIN mods m on v.mod_id = m.id\n INNER JOIN statuses s on m.status = s.id\n WHERE h.algorithm = $2 AND h.hash = $1 AND s.status != $3\n " }, + "742f20f422361971c21b72c629c57a6c3870d8d6c41577496907290db5994f12": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "\n UPDATE users\n SET badges = $1\n WHERE (id = $2)\n " + }, "75a860ca8087536a9fcf932846341c8bd322d314231bb8acac124d1cea93270b": { "describe": { "columns": [ @@ -3026,74 +3213,6 @@ }, "query": "\n INSERT INTO mods_categories (joining_mod_id, joining_category_id, is_additional)\n VALUES ($1, $2, FALSE)\n " }, - "7ecf1bdb78a03dbdee2e4a57d0914409751c13bdc8f01fa82c8001c2255e31a5": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 7, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 8, - "type_info": "Varchar" - } - ], - "nullable": [ - false, - true, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Text" - ] - } - }, - "query": "\n SELECT u.id, u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role\n FROM users u\n WHERE LOWER(u.username) = LOWER($1)\n " - }, "7f4fef104bdff9036c83499268c6b22406f8d7e5502607ed6ff47d5a0979ede2": { "describe": { "columns": [ @@ -3162,57 +3281,6 @@ }, "query": "\n INSERT INTO licenses (short, name)\n VALUES ($1, $2)\n ON CONFLICT (short) DO NOTHING\n RETURNING id\n " }, - "82cc64ff6fc37cd52a6dee033d1d571a3e570abe0aa10aea9860cdb8d1ea8cdc": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "team_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "user_id", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 5, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8", - "Int8" - ] - } - }, - "query": "\n SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM versions v\n INNER JOIN mods m ON m.id = v.mod_id\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.user_id = $2 AND tm.accepted = TRUE\n WHERE v.id = $1\n " - }, "844735a1ffd4b17c96e0cc441c85b3d05325523b415c509bbf2860b7e1ca0de3": { "describe": { "columns": [ @@ -3246,50 +3314,6 @@ }, "query": "\n DELETE FROM project_types\n WHERE name = $1\n " }, - "89310b2bc5f020744a9a42dae6f15dfebc1544cdd754939f0d09714353f2aa7c": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "team_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "role", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 4, - "type_info": "Bool" - } - ], - "nullable": [ - false, - false, - false, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT id, team_id, role, permissions, accepted\n FROM team_members\n WHERE user_id = $1\n " - }, "8b2e65cec164bb84de6929b1c2afeee28b36d0e36edea75baceaf97d7574bdd7": { "describe": { "columns": [ @@ -3468,6 +3492,63 @@ }, "query": "\n DELETE FROM loaders\n WHERE loader = $1\n " }, + "8fb70608e39d98cca4f800960baa3de0fce97268a96cae4ba653f86bff166126": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 4, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 5, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 6, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8Array", + "Int8" + ] + } + }, + "query": "\n SELECT id, team_id, user_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE (team_id = ANY($1) AND user_id = $2 AND accepted = TRUE)\n " + }, "8fd5d332e9cd2f760f956bf4936350f29df414552643bcfb352ca8a8a0b98439": { "describe": { "columns": [], @@ -3637,6 +3718,116 @@ }, "query": "\n DELETE FROM mods_categories\n WHERE joining_mod_id = $1 AND is_additional = FALSE\n " }, + "a1e3ac170e45196e5fcca154c96a206f35be68a3219a0d493e1e149206590043": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "member_role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + }, + { + "name": "user_id", + "ordinal": 6, + "type_info": "Int8" + }, + { + "name": "github_id", + "ordinal": 7, + "type_info": "Int8" + }, + { + "name": "user_name", + "ordinal": 8, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 9, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 10, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 11, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 12, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 13, + "type_info": "Timestamptz" + }, + { + "name": "user_role", + "ordinal": 14, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 15, + "type_info": "Int8" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + true, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8Array" + ] + } + }, + "query": "\n SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role, u.badges badges\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = ANY($1)\n ORDER BY tm.team_id\n " + }, "a39ce28b656032f862b205cffa393a76b989f4803654a615477a94fda5f57354": { "describe": { "columns": [], @@ -3777,68 +3968,6 @@ }, "query": "\n SELECT files.id, files.url, files.filename, files.is_primary FROM files\n WHERE files.version_id = $1\n " }, - "a94eb4862ba30ca21f15198d9b7b9fd80ce01d45457e0b4d68270b5e3f9be8c6": { - "describe": { - "columns": [ - { - "name": "github_id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 6, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 7, - "type_info": "Varchar" - } - ], - "nullable": [ - true, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT u.github_id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role\n FROM users u\n WHERE u.id = $1\n " - }, "aaec67a66b58dec36339c14000b319aed1b0ebb1324fc85e34d14c6430c26657": { "describe": { "columns": [ @@ -3860,6 +3989,56 @@ }, "query": "\n SELECT id FROM categories\n WHERE category = $1 AND project_type = $2\n " }, + "ab1212cc2fc9d61d8ef4c44791f73f405eb985218030307248970c6782aa7236": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "team_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT id, team_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE user_id = $1\n " + }, "ac2d17b7d7147b14f072c15ffa214c14f32f27ffa6a3c2b2a5f80f3ad49ca5e9": { "describe": { "columns": [ @@ -3968,6 +4147,74 @@ }, "query": "\n DELETE FROM dependencies WHERE mod_dependency_id = NULL AND dependency_id = NULL AND dependency_file_name = NULL\n " }, + "af0d1c0b8a52cef5af2627e321e4f0d52f472d278fc52fb7f7fed3ab37d52608": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Varchar" + }, + { + "name": "email", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "avatar_url", + "ordinal": 3, + "type_info": "Varchar" + }, + { + "name": "username", + "ordinal": 4, + "type_info": "Varchar" + }, + { + "name": "bio", + "ordinal": 5, + "type_info": "Varchar" + }, + { + "name": "created", + "ordinal": 6, + "type_info": "Timestamptz" + }, + { + "name": "role", + "ordinal": 7, + "type_info": "Varchar" + }, + { + "name": "badges", + "ordinal": 8, + "type_info": "Int8" + } + ], + "nullable": [ + false, + true, + true, + true, + false, + true, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8" + ] + } + }, + "query": "\n SELECT u.id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role, u.badges\n FROM users u\n WHERE u.github_id = $1\n " + }, "b030a9e0fdb75eee8ee50aafdcb6063a073e2aa53cc70d40ed46437c1d0dfe80": { "describe": { "columns": [], @@ -4306,7 +4553,7 @@ }, "query": "\n DELETE FROM dependencies WHERE dependent_id = $1\n " }, - "bdaab7da16d07169c29d96330fcc17ef2fb87fdfbadca23b7289c64420ac3a04": { + "bd84e130a977d363f12a165c49c42082db20f813456ff94541e009b69dfe0130": { "describe": { "columns": [ { @@ -4315,24 +4562,34 @@ "type_info": "Int8" }, { - "name": "user_id", + "name": "team_id", "ordinal": 1, "type_info": "Int8" }, { - "name": "role", + "name": "user_id", "ordinal": 2, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 3, "type_info": "Varchar" }, { "name": "permissions", - "ordinal": 3, + "ordinal": 4, "type_info": "Int8" }, { "name": "accepted", - "ordinal": 4, + "ordinal": 5, "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 6, + "type_info": "Float4" } ], "nullable": [ @@ -4340,6 +4597,8 @@ false, false, false, + false, + false, false ], "parameters": { @@ -4349,7 +4608,7 @@ ] } }, - "query": "\n SELECT id, user_id, role, permissions, accepted\n FROM team_members\n WHERE (team_id = $1 AND user_id = $2)\n " + "query": "\n SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM mods m\n INNER JOIN team_members tm ON tm.team_id = m.team_id AND user_id = $2 AND accepted = TRUE\n WHERE m.id = $1\n " }, "bdde6a7e476933c109c5b0d7236e033ccb7bf242266f77815a387a370365a10e": { "describe": { @@ -4428,6 +4687,57 @@ }, "query": "\n UPDATE mods\n SET license_url = $1\n WHERE (id = $2)\n " }, + "c15534b7259e2b138c6f041bf2a9f4c77bea060a9bce6f2a829a2d7594dddd3a": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "\n SELECT id, user_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE (team_id = $1 AND user_id = $2)\n " + }, "c1a3f6dcef6110d6ea884670fb82bac14b98e922bb5673c048ccce7b7300539b": { "describe": { "columns": [ @@ -4594,6 +4904,57 @@ }, "query": "\n UPDATE mods\n SET client_side = $1\n WHERE (id = $2)\n " }, + "c64b45669c915cbf22b1518800d92f5a153528396e47ffe7a03b552925530ca8": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int8" + }, + { + "name": "user_id", + "ordinal": 1, + "type_info": "Int8" + }, + { + "name": "role", + "ordinal": 2, + "type_info": "Varchar" + }, + { + "name": "permissions", + "ordinal": 3, + "type_info": "Int8" + }, + { + "name": "accepted", + "ordinal": 4, + "type_info": "Bool" + }, + { + "name": "payouts_split", + "ordinal": 5, + "type_info": "Float4" + } + ], + "nullable": [ + false, + false, + false, + false, + false, + false + ], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + } + }, + "query": "\n SELECT id, user_id, role, permissions, accepted, payouts_split\n FROM team_members\n WHERE (team_id = $1 AND user_id = $2 AND accepted = TRUE)\n " + }, "c64c487b56a25b252ff070fe03a7416e84260df8a6f938a018cc768598e9435b": { "describe": { "columns": [ @@ -4834,98 +5195,6 @@ }, "query": "\n SELECT loader FROM loaders\n WHERE id = $1\n " }, - "d2bba2670ef992df166a5e1e4d90f14f1d6b19c5fe77eb7139a5e1a0e660f6db": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "member_role", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 2, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 3, - "type_info": "Bool" - }, - { - "name": "user_id", - "ordinal": 4, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "user_name", - "ordinal": 6, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 10, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 11, - "type_info": "Timestamptz" - }, - { - "name": "user_role", - "ordinal": 12, - "type_info": "Varchar" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = $1\n " - }, "d331ca8f22da418cf654985c822ce4466824beaa00dea64cde90dc651a03024b": { "describe": { "columns": [], @@ -4952,104 +5221,6 @@ }, "query": "\n UPDATE team_members\n SET accepted = TRUE\n WHERE (team_id = $1 AND user_id = $2)\n " }, - "d553bb44ac600047656962bd1c44378fb32e74f0e7f07d1c26336dc80dffe78a": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "team_id", - "ordinal": 1, - "type_info": "Int8" - }, - { - "name": "member_role", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "permissions", - "ordinal": 3, - "type_info": "Int8" - }, - { - "name": "accepted", - "ordinal": 4, - "type_info": "Bool" - }, - { - "name": "user_id", - "ordinal": 5, - "type_info": "Int8" - }, - { - "name": "github_id", - "ordinal": 6, - "type_info": "Int8" - }, - { - "name": "user_name", - "ordinal": 7, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 8, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 9, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 10, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 11, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 12, - "type_info": "Timestamptz" - }, - { - "name": "user_role", - "ordinal": 13, - "type_info": "Varchar" - } - ], - "nullable": [ - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8Array" - ] - } - }, - "query": "\n SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted,\n u.id user_id, u.github_id github_id, u.name user_name, u.email email,\n u.avatar_url avatar_url, u.username username, u.bio bio,\n u.created created, u.role user_role\n FROM team_members tm\n INNER JOIN users u ON u.id = tm.user_id\n WHERE tm.team_id = ANY($1)\n ORDER BY tm.team_id\n " - }, "d59a0ca4725d40232eae8bf5735787e1b76282c390d2a8d07fb34e237a0b2132": { "describe": { "columns": [], @@ -5246,6 +5417,20 @@ }, "query": "\n SELECT r.id, rt.name, r.mod_id, r.version_id, r.user_id, r.body, r.reporter, r.created\n FROM reports r\n INNER JOIN report_types rt ON rt.id = r.report_type_id\n WHERE r.id = ANY($1)\n ORDER BY r.created DESC\n " }, + "d7c65c30898110d801a5bdf092564e5726e35c1033c69dba69008989a087357c": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Float4", + "Int8", + "Int8" + ] + } + }, + "query": "\n UPDATE team_members\n SET payouts_split = $1\n WHERE (team_id = $2 AND user_id = $3)\n " + }, "d8020ed838c032c2c287dc0f08989b3ab7156f2571bc75505e6f57b0caeef9c7": { "describe": { "columns": [ @@ -5627,68 +5812,6 @@ }, "query": "\n UPDATE mods\n SET status = $1\n WHERE (id = $2)\n " }, - "ea877d50ba461eae97ba3a35c3da71e7cdb7a92de1bb877d6b5dd766aca4e4ef": { - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Int8" - }, - { - "name": "name", - "ordinal": 1, - "type_info": "Varchar" - }, - { - "name": "email", - "ordinal": 2, - "type_info": "Varchar" - }, - { - "name": "avatar_url", - "ordinal": 3, - "type_info": "Varchar" - }, - { - "name": "username", - "ordinal": 4, - "type_info": "Varchar" - }, - { - "name": "bio", - "ordinal": 5, - "type_info": "Varchar" - }, - { - "name": "created", - "ordinal": 6, - "type_info": "Timestamptz" - }, - { - "name": "role", - "ordinal": 7, - "type_info": "Varchar" - } - ], - "nullable": [ - false, - true, - true, - true, - false, - true, - false, - false - ], - "parameters": { - "Left": [ - "Int8" - ] - } - }, - "query": "\n SELECT u.id, u.name, u.email,\n u.avatar_url, u.username, u.bio,\n u.created, u.role\n FROM users u\n WHERE u.github_id = $1\n " - }, "ebef881a0dae70e990814e567ed3de9565bb29b772782bc974c953af195fd6d7": { "describe": { "columns": [ diff --git a/src/database/models/mod.rs b/src/database/models/mod.rs index b6c3739e0..627da5e10 100644 --- a/src/database/models/mod.rs +++ b/src/database/models/mod.rs @@ -28,8 +28,6 @@ pub enum DatabaseError { Database(#[from] sqlx::error::Error), #[error("Error while trying to generate random ID")] RandomId, - #[error("Invalid permissions bitflag!")] - Bitflag, #[error("A database request failed")] Other(String), } diff --git a/src/database/models/team_item.rs b/src/database/models/team_item.rs index 9e4661c98..edd3a07e0 100644 --- a/src/database/models/team_item.rs +++ b/src/database/models/team_item.rs @@ -1,6 +1,7 @@ use super::ids::*; use crate::database::models::User; use crate::models::teams::Permissions; +use crate::models::users::Badges; pub struct TeamBuilder { pub members: Vec, @@ -10,6 +11,7 @@ pub struct TeamMemberBuilder { pub role: String, pub permissions: Permissions, pub accepted: bool, + pub payouts_split: f32, } impl TeamBuilder { @@ -41,6 +43,7 @@ impl TeamBuilder { role: member.role, permissions: member.permissions, accepted: member.accepted, + payouts_split: member.payouts_split, }; sqlx::query!( @@ -78,6 +81,7 @@ pub struct TeamMember { pub role: String, pub permissions: Permissions, pub accepted: bool, + pub payouts_split: f32, } /// A member of a team @@ -89,6 +93,7 @@ pub struct QueryTeamMember { pub role: String, pub permissions: Permissions, pub accepted: bool, + pub payouts_split: f32, } impl TeamMember { @@ -104,7 +109,7 @@ impl TeamMember { let team_members = sqlx::query!( " - SELECT id, user_id, role, permissions, accepted + SELECT id, user_id, role, permissions, accepted, payouts_split FROM team_members WHERE team_id = $1 ", @@ -113,19 +118,16 @@ impl TeamMember { .fetch_many(executor) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { - Ok(Some(Ok(TeamMember { - id: TeamMemberId(m.id), - team_id: id, - user_id: UserId(m.user_id), - role: m.role, - permissions: perms, - accepted: m.accepted, - }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } + Ok(Some(Ok(TeamMember { + id: TeamMemberId(m.id), + team_id: id, + user_id: UserId(m.user_id), + role: m.role, + permissions: Permissions::from_bits(m.permissions as u64) + .unwrap_or_default(), + accepted: m.accepted, + payouts_split: m.payouts_split, + }))) } else { Ok(None) } @@ -152,10 +154,10 @@ impl TeamMember { let team_members = sqlx::query!( " - SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, + SELECT tm.id id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split, u.id user_id, u.github_id github_id, u.name user_name, u.email email, u.avatar_url avatar_url, u.username username, u.bio bio, - u.created created, u.role user_role + u.created created, u.role user_role, u.badges badges FROM team_members tm INNER JOIN users u ON u.id = tm.user_id WHERE tm.team_id = $1 @@ -165,13 +167,12 @@ impl TeamMember { .fetch_many(executor) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { + Ok(Some(Ok(QueryTeamMember { id: TeamMemberId(m.id), team_id: id, role: m.member_role, - permissions: perms, + permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(), accepted: m.accepted, user: User { id: UserId(m.user_id), @@ -183,11 +184,10 @@ impl TeamMember { bio: m.bio, created: m.created, role: m.user_role, + badges: Badges::from_bits(m.badges as u64).unwrap_or_default(), }, + payouts_split: m.payouts_split }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } } else { Ok(None) } @@ -216,10 +216,10 @@ impl TeamMember { let teams = sqlx::query!( " - SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, + SELECT tm.id id, tm.team_id team_id, tm.role member_role, tm.permissions permissions, tm.accepted accepted, tm.payouts_split payouts_split, u.id user_id, u.github_id github_id, u.name user_name, u.email email, u.avatar_url avatar_url, u.username username, u.bio bio, - u.created created, u.role user_role + u.created created, u.role user_role, u.badges badges FROM team_members tm INNER JOIN users u ON u.id = tm.user_id WHERE tm.team_id = ANY($1) @@ -230,13 +230,12 @@ impl TeamMember { .fetch_many(exec) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { + Ok(Some(Ok(QueryTeamMember { id: TeamMemberId(m.id), team_id: TeamId(m.team_id), role: m.member_role, - permissions: perms, + permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(), accepted: m.accepted, user: User { id: UserId(m.user_id), @@ -248,11 +247,10 @@ impl TeamMember { bio: m.bio, created: m.created, role: m.user_role, + badges: Badges::from_bits(m.badges as u64).unwrap_or_default(), }, + payouts_split: m.payouts_split }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } } else { Ok(None) } @@ -279,7 +277,7 @@ impl TeamMember { let team_members = sqlx::query!( " - SELECT id, team_id, role, permissions, accepted + SELECT id, team_id, role, permissions, accepted, payouts_split FROM team_members WHERE (user_id = $1 AND accepted = TRUE) ", @@ -288,19 +286,16 @@ impl TeamMember { .fetch_many(executor) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { - Ok(Some(Ok(TeamMember { - id: TeamMemberId(m.id), - team_id: TeamId(m.team_id), - user_id: id, - role: m.role, - permissions: perms, - accepted: m.accepted, - }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } + Ok(Some(Ok(TeamMember { + id: TeamMemberId(m.id), + team_id: TeamId(m.team_id), + user_id: id, + role: m.role, + permissions: Permissions::from_bits(m.permissions as u64) + .unwrap_or_default(), + accepted: m.accepted, + payouts_split: m.payouts_split, + }))) } else { Ok(None) } @@ -327,7 +322,7 @@ impl TeamMember { let team_members = sqlx::query!( " - SELECT id, team_id, role, permissions, accepted + SELECT id, team_id, role, permissions, accepted, payouts_split FROM team_members WHERE user_id = $1 ", @@ -336,19 +331,16 @@ impl TeamMember { .fetch_many(executor) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { - Ok(Some(Ok(TeamMember { - id: TeamMemberId(m.id), - team_id: TeamId(m.team_id), - user_id: id, - role: m.role, - permissions: perms, - accepted: m.accepted, - }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } + Ok(Some(Ok(TeamMember { + id: TeamMemberId(m.id), + team_id: TeamId(m.team_id), + user_id: id, + role: m.role, + permissions: Permissions::from_bits(m.permissions as u64) + .unwrap_or_default(), + accepted: m.accepted, + payouts_split: m.payouts_split, + }))) } else { Ok(None) } @@ -374,7 +366,7 @@ impl TeamMember { { let result = sqlx::query!( " - SELECT id, user_id, role, permissions, accepted + SELECT id, user_id, role, permissions, accepted, payouts_split FROM team_members WHERE (team_id = $1 AND user_id = $2 AND accepted = TRUE) ", @@ -391,8 +383,9 @@ impl TeamMember { user_id, role: m.role, permissions: Permissions::from_bits(m.permissions as u64) - .ok_or(super::DatabaseError::Bitflag)?, + .unwrap_or_default(), accepted: m.accepted, + payouts_split: m.payouts_split, })) } else { Ok(None) @@ -415,7 +408,7 @@ impl TeamMember { let team_members = sqlx::query!( " - SELECT id, team_id, user_id, role, permissions, accepted + SELECT id, team_id, user_id, role, permissions, accepted, payouts_split FROM team_members WHERE (team_id = ANY($1) AND user_id = $2 AND accepted = TRUE) ", @@ -425,19 +418,15 @@ impl TeamMember { .fetch_many(executor) .try_filter_map(|e| async { if let Some(m) = e.right() { - let permissions = Permissions::from_bits(m.permissions as u64); - if let Some(perms) = permissions { Ok(Some(Ok(TeamMember { id: TeamMemberId(m.id), team_id: TeamId(m.team_id), user_id, role: m.role, - permissions: perms, + permissions: Permissions::from_bits(m.permissions as u64).unwrap_or_default(), accepted: m.accepted, + payouts_split: m.payouts_split }))) - } else { - Ok(Some(Err(super::DatabaseError::Bitflag))) - } } else { Ok(None) } @@ -463,7 +452,7 @@ impl TeamMember { { let result = sqlx::query!( " - SELECT id, user_id, role, permissions, accepted + SELECT id, user_id, role, permissions, accepted, payouts_split FROM team_members WHERE (team_id = $1 AND user_id = $2) ", @@ -480,8 +469,9 @@ impl TeamMember { user_id, role: m.role, permissions: Permissions::from_bits(m.permissions as u64) - .ok_or(super::DatabaseError::Bitflag)?, + .unwrap_or_default(), accepted: m.accepted, + payouts_split: m.payouts_split, })) } else { Ok(None) @@ -550,6 +540,7 @@ impl TeamMember { new_permissions: Option, new_role: Option, new_accepted: Option, + new_payouts_split: Option, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, ) -> Result<(), super::DatabaseError> { if let Some(permissions) = new_permissions { @@ -598,6 +589,21 @@ impl TeamMember { } } + if let Some(payouts_split) = new_payouts_split { + sqlx::query!( + " + UPDATE team_members + SET payouts_split = $1 + WHERE (team_id = $2 AND user_id = $3) + ", + payouts_split, + id as TeamId, + user_id as UserId, + ) + .execute(&mut *transaction) + .await?; + } + Ok(()) } @@ -611,7 +617,7 @@ impl TeamMember { { let result = sqlx::query!( " - SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM mods m + SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM mods m INNER JOIN team_members tm ON tm.team_id = m.team_id AND user_id = $2 AND accepted = TRUE WHERE m.id = $1 ", @@ -628,8 +634,9 @@ impl TeamMember { user_id, role: m.role, permissions: Permissions::from_bits(m.permissions as u64) - .ok_or(super::DatabaseError::Bitflag)?, + .unwrap_or_default(), accepted: m.accepted, + payouts_split: m.payouts_split, })) } else { Ok(None) @@ -646,7 +653,7 @@ impl TeamMember { { let result = sqlx::query!( " - SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted FROM versions v + SELECT tm.id, tm.team_id, tm.user_id, tm.role, tm.permissions, tm.accepted, tm.payouts_split FROM versions v INNER JOIN mods m ON m.id = v.mod_id INNER JOIN team_members tm ON tm.team_id = m.team_id AND tm.user_id = $2 AND tm.accepted = TRUE WHERE v.id = $1 @@ -664,8 +671,9 @@ impl TeamMember { user_id, role: m.role, permissions: Permissions::from_bits(m.permissions as u64) - .ok_or(super::DatabaseError::Bitflag)?, + .unwrap_or_default(), accepted: m.accepted, + payouts_split: m.payouts_split, })) } else { Ok(None) diff --git a/src/database/models/user_item.rs b/src/database/models/user_item.rs index 524a4a60e..514b9e247 100644 --- a/src/database/models/user_item.rs +++ b/src/database/models/user_item.rs @@ -1,4 +1,5 @@ use super::ids::{ProjectId, UserId}; +use crate::models::users::Badges; use chrono::{DateTime, Utc}; pub struct User { @@ -11,6 +12,7 @@ pub struct User { pub bio: Option, pub created: DateTime, pub role: String, + pub badges: Badges, } impl User { @@ -54,7 +56,7 @@ impl User { " SELECT u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role + u.created, u.role, u.badges FROM users u WHERE u.id = $1 ", @@ -74,6 +76,8 @@ impl User { bio: row.bio, created: row.created, role: row.role, + badges: Badges::from_bits(row.badges as u64) + .unwrap_or_default(), })) } else { Ok(None) @@ -91,7 +95,7 @@ impl User { " SELECT u.id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role + u.created, u.role, u.badges FROM users u WHERE u.github_id = $1 ", @@ -111,6 +115,8 @@ impl User { bio: row.bio, created: row.created, role: row.role, + badges: Badges::from_bits(row.badges as u64) + .unwrap_or_default(), })) } else { Ok(None) @@ -128,7 +134,7 @@ impl User { " SELECT u.id, u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role + u.created, u.role, u.badges FROM users u WHERE LOWER(u.username) = LOWER($1) ", @@ -148,6 +154,8 @@ impl User { bio: row.bio, created: row.created, role: row.role, + badges: Badges::from_bits(row.badges as u64) + .unwrap_or_default(), })) } else { Ok(None) @@ -169,7 +177,8 @@ impl User { " SELECT u.id, u.github_id, u.name, u.email, u.avatar_url, u.username, u.bio, - u.created, u.role FROM users u + u.created, u.role, u.badges + FROM users u WHERE u.id = ANY($1) ", &user_ids_parsed @@ -186,6 +195,7 @@ impl User { bio: u.bio, created: u.created, role: u.role, + badges: Badges::from_bits(u.badges as u64).unwrap_or_default(), })) }) .try_collect::>() diff --git a/src/models/teams.rs b/src/models/teams.rs index 6d3806847..581a5ea3b 100644 --- a/src/models/teams.rs +++ b/src/models/teams.rs @@ -34,7 +34,9 @@ bitflags::bitflags! { const REMOVE_MEMBER = 1 << 5; const EDIT_MEMBER = 1 << 6; const DELETE_PROJECT = 1 << 7; - const ALL = 0b11111111; + const VIEW_ANALYTICS = 1 << 8; + const VIEW_PAYOUTS = 1 << 9; + const ALL = 0b1111111111; } } @@ -57,6 +59,9 @@ pub struct TeamMember { pub permissions: Option, /// Whether the user has joined the team or is just invited to it pub accepted: bool, + /// Payouts split. This is a weighted average. For example. if a team has two members with this + /// value set to 25.0 for both members, they split revenue 50/50 + pub payouts_split: Option, } impl TeamMember { @@ -71,6 +76,11 @@ impl TeamMember { Some(data.permissions) }, accepted: data.accepted, + payouts_split: if override_permissions { + None + } else { + Some(data.payouts_split) + }, } } } diff --git a/src/models/users.rs b/src/models/users.rs index 90a5fc6b5..1921fcd3f 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -9,6 +9,29 @@ pub struct UserId(pub u64); pub const DELETED_USER: UserId = UserId(127155982985829); +bitflags::bitflags! { + #[derive(Serialize, Deserialize)] + #[serde(transparent)] + pub struct Badges: u64 { + const MIDAS = 1 << 0; + const EARLY_MODPACK_ADOPTER = 1 << 1; + const EARLY_RESPACK_ADOPTER = 1 << 2; + const EARLY_PLUGIN_ADOPTER = 1 << 3; + const ALPHA_TESTER = 1 << 4; + const CONTRIBUTOR = 1 << 5; + const TRANSLATOR = 1 << 6; + + const ALL = 0b1111111; + const NONE = 0b0; + } +} + +impl Default for Badges { + fn default() -> Badges { + Badges::NONE + } +} + #[derive(Serialize, Deserialize, Clone)] pub struct User { pub id: UserId, @@ -20,6 +43,7 @@ pub struct User { pub bio: Option, pub created: DateTime, pub role: Role, + pub badges: Badges, } use crate::database::models::user_item::User as DBUser; @@ -35,6 +59,7 @@ impl From for User { bio: data.bio, created: data.created, role: Role::from_string(&*data.role), + badges: data.badges, } } } diff --git a/src/routes/auth.rs b/src/routes/auth.rs index 1d189c38a..e3af2b8aa 100644 --- a/src/routes/auth.rs +++ b/src/routes/auth.rs @@ -15,7 +15,7 @@ use crate::database::models::{generate_state_id, User}; use crate::models::error::ApiError; use crate::models::ids::base62_impl::{parse_base62, to_base62}; use crate::models::ids::DecodingError; -use crate::models::users::Role; +use crate::models::users::{Badges, Role}; use crate::parse_strings_from_var; use crate::util::auth::get_github_user_from_token; use actix_web::http::StatusCode; @@ -272,6 +272,7 @@ pub async fn auth_callback( bio: user.bio, created: Utc::now(), role: Role::Developer.to_string(), + badges: Badges::default(), } .insert(&mut transaction) .await?; diff --git a/src/routes/project_creation.rs b/src/routes/project_creation.rs index afcfd2721..d91a17fb4 100644 --- a/src/routes/project_creation.rs +++ b/src/routes/project_creation.rs @@ -628,6 +628,7 @@ pub async fn project_create_inner( role: crate::models::teams::OWNER_ROLE.to_owned(), permissions: crate::models::teams::Permissions::ALL, accepted: true, + payouts_split: 100.0, }], }; diff --git a/src/routes/teams.rs b/src/routes/teams.rs index 5ba7bcb10..7e3f11947 100644 --- a/src/routes/teams.rs +++ b/src/routes/teams.rs @@ -189,6 +189,7 @@ pub async fn join_team( None, None, Some(true), + None, &mut transaction, ) .await?; @@ -214,6 +215,8 @@ pub struct NewTeamMember { pub role: String, #[serde(default = "Permissions::default")] pub permissions: Permissions, + #[serde(default)] + pub payouts_split: f32, } #[post("{id}/members")] @@ -255,6 +258,13 @@ pub async fn add_team_member( "The `Owner` role is restricted to one person".to_string(), )); } + + if !(0.0..=5000.0).contains(&new_member.payouts_split) { + return Err(ApiError::InvalidInput( + "Payouts split must be between 0 and 5000!".to_string(), + )); + } + let request = crate::database::models::team_item::TeamMember::get_from_user_id_pending( team_id, new_member.user_id.into(), @@ -291,6 +301,7 @@ pub async fn add_team_member( role: new_member.role.clone(), permissions: new_member.permissions, accepted: false, + payouts_split: new_member.payouts_split, } .insert(&mut transaction) .await?; @@ -349,6 +360,7 @@ pub async fn add_team_member( pub struct EditTeamMember { pub permissions: Option, pub role: Option, + pub payouts_split: Option, } #[patch("{id}/members/{user_id}")] @@ -406,6 +418,14 @@ pub async fn edit_team_member( } } + if let Some(payouts_split) = edit_member.payouts_split { + if !(0.0..=5000.0).contains(&payouts_split) { + return Err(ApiError::InvalidInput( + "Payouts split must be between 0 and 5000!".to_string(), + )); + } + } + if edit_member.role.as_deref() == Some(crate::models::teams::OWNER_ROLE) { return Err(ApiError::InvalidInput( "The `Owner` role is restricted to one person".to_string(), @@ -418,6 +438,7 @@ pub async fn edit_team_member( edit_member.permissions, edit_member.role.clone(), None, + edit_member.payouts_split, &mut transaction, ) .await?; @@ -491,6 +512,7 @@ pub async fn transfer_ownership( None, Some(crate::models::teams::DEFAULT_ROLE.to_string()), None, + None, &mut transaction, ) .await?; @@ -501,6 +523,7 @@ pub async fn transfer_ownership( Some(Permissions::ALL), Some(crate::models::teams::OWNER_ROLE.to_string()), None, + None, &mut transaction, ) .await?; diff --git a/src/routes/users.rs b/src/routes/users.rs index 710b16ca8..1bd4ed6d5 100644 --- a/src/routes/users.rs +++ b/src/routes/users.rs @@ -2,7 +2,7 @@ use crate::database::models::User; use crate::file_hosting::FileHost; use crate::models::notifications::Notification; use crate::models::projects::{Project, ProjectStatus}; -use crate::models::users::{Role, UserId}; +use crate::models::users::{Badges, Role, UserId}; use crate::routes::ApiError; use crate::util::auth::get_user_from_headers; use crate::util::routes::read_from_payload; @@ -154,6 +154,7 @@ pub struct EditUser { #[validate(length(max = 160))] pub bio: Option>, pub role: Option, + pub badges: Option, } #[patch("{id}")] @@ -277,6 +278,27 @@ pub async fn user_edit( .await?; } + if let Some(badges) = &new_user.badges { + if !user.role.is_admin() { + return Err(ApiError::CustomAuthentication( + "You do not have the permissions to edit the badges of this user!" + .to_string(), + )); + } + + sqlx::query!( + " + UPDATE users + SET badges = $1 + WHERE (id = $2) + ", + badges.bits() as i64, + id as crate::database::models::ids::UserId, + ) + .execute(&mut *transaction) + .await?; + } + transaction.commit().await?; Ok(HttpResponse::NoContent().body("")) } else { diff --git a/src/util/auth.rs b/src/util/auth.rs index 2a4f55bc1..47074d986 100644 --- a/src/util/auth.rs +++ b/src/util/auth.rs @@ -72,6 +72,7 @@ where bio: result.bio, created: result.created, role: Role::from_string(&result.role), + badges: result.badges, }), None => Err(AuthenticationError::InvalidCredentials), } diff --git a/src/validate/liteloader.rs b/src/validate/liteloader.rs index 25b0f5d72..a2d84e882 100644 --- a/src/validate/liteloader.rs +++ b/src/validate/liteloader.rs @@ -8,7 +8,7 @@ pub struct LiteLoaderValidator; impl super::Validator for LiteLoaderValidator { fn get_file_extensions(&self) -> &[&str] { - &["litemod"] + &["litemod", "jar"] } fn get_project_types(&self) -> &[&str] {