From 021fee616dcd92dad54677bc526b19c5ee51fa56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antti=20Ellil=C3=A4?= Date: Thu, 9 Jan 2025 23:37:17 +0200 Subject: [PATCH 01/30] Allow skipping updater at runtime with an environmental variable (#2388) Co-authored-by: Modrinth Bot <106493074+modrinth-bot@users.noreply.github.com> --- apps/app/src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/app/src/main.rs b/apps/app/src/main.rs index 402f3c8cc..f313bb9a3 100644 --- a/apps/app/src/main.rs +++ b/apps/app/src/main.rs @@ -4,6 +4,7 @@ )] use native_dialog::{MessageDialog, MessageType}; +use std::env; use tauri::{Listener, Manager}; use theseus::prelude::*; @@ -29,7 +30,12 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> { theseus::EventState::init(app.clone()).await?; #[cfg(feature = "updater")] - { + 'updater: { + if env::var("MODRINTH_EXTERNAL_UPDATE_PROVIDER").is_ok() { + State::init().await?; + break 'updater; + } + use tauri_plugin_updater::UpdaterExt; let updater = app.updater_builder().build()?; From c52d5e9a7477cff403ee0c364a2cbf32555f5b8a Mon Sep 17 00:00:00 2001 From: jebibot Date: Fri, 10 Jan 2025 06:37:42 +0900 Subject: [PATCH 02/30] feat(app): update profile every time token is refreshed (#2328) Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com> Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> --- packages/app-lib/src/state/minecraft_auth.rs | 22 +++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/app-lib/src/state/minecraft_auth.rs b/packages/app-lib/src/state/minecraft_auth.rs index e1c204aaf..411e49c89 100644 --- a/packages/app-lib/src/state/minecraft_auth.rs +++ b/packages/app-lib/src/state/minecraft_auth.rs @@ -178,19 +178,16 @@ pub async fn login_finish( minecraft_entitlements(&minecraft_token.access_token).await?; - let profile = minecraft_profile(&minecraft_token.access_token).await?; - - let profile_id = profile.id.unwrap_or_default(); - - let credentials = Credentials { - id: profile_id, - username: profile.name, + let mut credentials = Credentials { + id: Uuid::default(), + username: String::default(), access_token: minecraft_token.access_token, refresh_token: oauth_token.value.refresh_token, expires: oauth_token.date + Duration::seconds(oauth_token.value.expires_in as i64), active: true, }; + credentials.get_profile().await?; credentials.upsert(exec).await?; @@ -245,11 +242,22 @@ impl Credentials { self.expires = oauth_token.date + Duration::seconds(oauth_token.value.expires_in as i64); + self.get_profile().await?; + self.upsert(exec).await?; Ok(()) } + async fn get_profile(&mut self) -> crate::Result<()> { + let profile = minecraft_profile(&self.access_token).await?; + + self.id = profile.id.unwrap_or_default(); + self.username = profile.name; + + Ok(()) + } + #[tracing::instrument] pub async fn get_default_credential( exec: impl sqlx::Executor<'_, Database = sqlx::Sqlite> + Copy, From f859c34442e0eda81c5286d2b2f608cbab35753e Mon Sep 17 00:00:00 2001 From: Prospector <6166773+Prospector@users.noreply.github.com> Date: Thu, 9 Jan 2025 15:13:05 -0800 Subject: [PATCH 03/30] Fix some text color issues. Remove experimental colors reset for now. (#3136) Co-authored-by: Jai Agrawal <18202329+Geometrically@users.noreply.github.com> --- apps/frontend/src/pages/[type]/[id].vue | 2 +- packages/assets/styles/variables.scss | 17 ----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/apps/frontend/src/pages/[type]/[id].vue b/apps/frontend/src/pages/[type]/[id].vue index 73d2ce9ba..198fa03f3 100644 --- a/apps/frontend/src/pages/[type]/[id].vue +++ b/apps/frontend/src/pages/[type]/[id].vue @@ -506,7 +506,7 @@ placeholder="Search collections..." class="search-input menu-search" /> -
+
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com> --- apps/app-frontend/src/components/ui/friends/FriendsList.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/app-frontend/src/components/ui/friends/FriendsList.vue b/apps/app-frontend/src/components/ui/friends/FriendsList.vue index ef5b9f23f..c936489bc 100644 --- a/apps/app-frontend/src/components/ui/friends/FriendsList.vue +++ b/apps/app-frontend/src/components/ui/friends/FriendsList.vue @@ -20,7 +20,7 @@ import ModalWrapper from '@/components/ui/modal/ModalWrapper.vue' const props = defineProps<{ credentials: unknown | null - signIn: () => void2 + signIn: () => void }>() const userCredentials = computed(() => props.credentials) From fd9653e2837b995666baa34fdad3d680bac415d7 Mon Sep 17 00:00:00 2001 From: Awakened Redstone <40528665+Awakened-Redstone@users.noreply.github.com> Date: Thu, 9 Jan 2025 20:14:12 -0300 Subject: [PATCH 05/30] fix: Properly handle empty version list on `version/latest` (#3132) Co-authored-by: Jai Agrawal <18202329+Geometrically@users.noreply.github.com> --- apps/frontend/src/pages/[type]/[id]/version/[version].vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/frontend/src/pages/[type]/[id]/version/[version].vue b/apps/frontend/src/pages/[type]/[id]/version/[version].vue index f03723a58..de17bcde5 100644 --- a/apps/frontend/src/pages/[type]/[id]/version/[version].vue +++ b/apps/frontend/src/pages/[type]/[id]/version/[version].vue @@ -821,6 +821,13 @@ export default defineNuxtComponent({ if (route.query.version) { versionList = versionList.filter((x) => x.game_versions.includes(route.query.version)); } + if (versionList.length === 0) { + throw createError({ + fatal: true, + statusCode: 404, + message: "No version matches the filters", + }); + } version = versionList.reduce((a, b) => (a.date_published > b.date_published ? a : b)); } else { version = props.versions.find((x) => x.id === route.params.version); From 6266f29b99d8b9d22f9d814c0afe45511350013e Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Fri, 10 Jan 2025 00:16:17 +0100 Subject: [PATCH 06/30] fix(frontend): lowercase giftcard sorting (#2986) Resolves #1409 --- apps/frontend/src/pages/dashboard/revenue/withdraw.vue | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/frontend/src/pages/dashboard/revenue/withdraw.vue b/apps/frontend/src/pages/dashboard/revenue/withdraw.vue index eec8468c6..b48431d07 100644 --- a/apps/frontend/src/pages/dashboard/revenue/withdraw.vue +++ b/apps/frontend/src/pages/dashboard/revenue/withdraw.vue @@ -38,9 +38,13 @@
From 494616e9f2e90c1c49db3e63c4b474abccc35028 Mon Sep 17 00:00:00 2001 From: Erb3 <49862976+Erb3@users.noreply.github.com> Date: Fri, 10 Jan 2025 17:42:31 +0100 Subject: [PATCH 09/30] chore: run lint (#3140) * chore: run lint * fix: whoops messed up lint --- apps/frontend/src/pages/[type]/[id].vue | 60 +++++++++++----------- apps/labrinth/src/routes/internal/admin.rs | 2 +- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/apps/frontend/src/pages/[type]/[id].vue b/apps/frontend/src/pages/[type]/[id].vue index 5a3afd6e8..fa7b79a25 100644 --- a/apps/frontend/src/pages/[type]/[id].vue +++ b/apps/frontend/src/pages/[type]/[id].vue @@ -275,7 +275,7 @@
(versionFilter && x.includes(versionFilter)) || @@ -284,21 +284,21 @@ ) .slice() .reverse()" - :key="version" - :color="currentGameVersion === version ? 'brand' : 'standard'" + :key="gameVersion" + :color="currentGameVersion === gameVersion ? 'brand' : 'standard'" > @@ -785,31 +785,31 @@ From 0d7934e3b8e38ca426c61e9f2f504c7530f58b9f Mon Sep 17 00:00:00 2001 From: Josiah Glosson Date: Wed, 15 Jan 2025 17:34:21 -0600 Subject: [PATCH 15/30] Fix importing newer Prism instances (#3129) * Fix importing newer Prism instances and clean up import code a bit * cargo fmt --------- Co-authored-by: Jai Agrawal <18202329+Geometrically@users.noreply.github.com> --- packages/app-lib/src/api/pack/import/mmc.rs | 40 ++++++++++----------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/packages/app-lib/src/api/pack/import/mmc.rs b/packages/app-lib/src/api/pack/import/mmc.rs index 8d718bbc0..dcc15d304 100644 --- a/packages/app-lib/src/api/pack/import/mmc.rs +++ b/packages/app-lib/src/api/pack/import/mmc.rs @@ -180,9 +180,8 @@ pub async fn import_mmc( instance_folder: String, // instance folder in mmc_base_path profile_path: &str, // path to profile ) -> crate::Result<()> { - let mmc_instance_path = mmc_base_path - .join("instances") - .join(instance_folder.clone()); + let mmc_instance_path = + mmc_base_path.join("instances").join(instance_folder); let mmc_pack = io::read_to_string(&mmc_instance_path.join("mmc-pack.json")).await?; @@ -209,9 +208,18 @@ pub async fn import_mmc( profile_path: profile_path.to_string(), }; - // Managed pack - let backup_name = "Imported Modpack".to_string(); + let mut minecraft_folder = mmc_instance_path.join("minecraft"); + if !minecraft_folder.is_dir() { + minecraft_folder = mmc_instance_path.join(".minecraft"); + if !minecraft_folder.is_dir() { + return Err(crate::ErrorKind::InputError( + "Instance is missing Minecraft directory".to_string(), + ) + .into()); + } + } + // Managed pack if instance_cfg.managed_pack.unwrap_or(false) { match instance_cfg.managed_pack_type { Some(MMCManagedPackType::Modrinth) => { @@ -220,38 +228,26 @@ pub async fn import_mmc( // Modrinth Managed Pack // Kept separate as we may in the future want to add special handling for modrinth managed packs - let backup_name = "Imported Modrinth Modpack".to_string(); - let minecraft_folder = mmc_base_path.join("instances").join(instance_folder).join(".minecraft"); - import_mmc_unmanaged(profile_path, minecraft_folder, backup_name, description, mmc_pack).await?; + import_mmc_unmanaged(profile_path, minecraft_folder, "Imported Modrinth Modpack".to_string(), description, mmc_pack).await?; } Some(MMCManagedPackType::Flame) | Some(MMCManagedPackType::ATLauncher) => { // For flame/atlauncher managed packs // Treat as unmanaged, but with 'minecraft' folder instead of '.minecraft' - let minecraft_folder = mmc_base_path.join("instances").join(instance_folder).join("minecraft"); - import_mmc_unmanaged(profile_path, minecraft_folder, backup_name, description, mmc_pack).await?; + import_mmc_unmanaged(profile_path, minecraft_folder, "Imported Modpack".to_string(), description, mmc_pack).await?; }, Some(_) => { // For managed packs that aren't modrinth, flame, atlauncher // Treat as unmanaged - let backup_name = "ImportedModpack".to_string(); - let minecraft_folder = mmc_base_path.join("instances").join(instance_folder).join(".minecraft"); - import_mmc_unmanaged(profile_path, minecraft_folder, backup_name, description, mmc_pack).await?; + import_mmc_unmanaged(profile_path, minecraft_folder, "ImportedModpack".to_string(), description, mmc_pack).await?; }, - _ => return Err(crate::ErrorKind::InputError({ - "Instance is managed, but managed pack type not specified in instance.cfg".to_string() - }).into()) + _ => return Err(crate::ErrorKind::InputError("Instance is managed, but managed pack type not specified in instance.cfg".to_string()).into()) } } else { // Direclty import unmanaged pack - let backup_name = "Imported Modpack".to_string(); - let minecraft_folder = mmc_base_path - .join("instances") - .join(instance_folder) - .join(".minecraft"); import_mmc_unmanaged( profile_path, minecraft_folder, - backup_name, + "Imported Modpack".to_string(), description, mmc_pack, ) From 5c8e7a8b3898250451dafba9fe80cf6b563b71c1 Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 16:40:13 -0800 Subject: [PATCH 16/30] Support new delphi response type --- .../labrinth/src/database/models/team_item.rs | 2 +- apps/labrinth/src/routes/internal/admin.rs | 34 +++++++++++++------ apps/labrinth/src/routes/internal/billing.rs | 2 +- apps/labrinth/src/routes/v3/oauth_clients.rs | 4 +-- apps/labrinth/src/util/guards.rs | 2 +- 5 files changed, 28 insertions(+), 16 deletions(-) diff --git a/apps/labrinth/src/database/models/team_item.rs b/apps/labrinth/src/database/models/team_item.rs index 8f6f811ef..d343596cf 100644 --- a/apps/labrinth/src/database/models/team_item.rs +++ b/apps/labrinth/src/database/models/team_item.rs @@ -405,7 +405,7 @@ impl TeamMember { Ok(()) } - pub async fn delete<'a, 'b>( + pub async fn delete( id: TeamId, user_id: UserId, transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>, diff --git a/apps/labrinth/src/routes/internal/admin.rs b/apps/labrinth/src/routes/internal/admin.rs index e983bae84..f52667d9a 100644 --- a/apps/labrinth/src/routes/internal/admin.rs +++ b/apps/labrinth/src/routes/internal/admin.rs @@ -189,7 +189,7 @@ pub struct DelphiIngest { pub url: String, pub project_id: crate::models::ids::ProjectId, pub version_id: crate::models::ids::VersionId, - pub issues: Vec, + pub issues: HashMap>, } #[post("/_delphi", guard = "admin_key_guard")] @@ -218,29 +218,41 @@ pub async fn delphi_result_ingest( )) })?; + let mut header = format!("Suspicious traces found at {}", body.url); + + for (issue, trace) in &body.issues { + for (path, code) in trace { + header.push_str(&format!( + "\n issue {issue} found at file {}: \n ```\n{}\n```", + path, code + )); + } + } + crate::util::webhook::send_slack_webhook( body.project_id, &pool, &redis, webhook_url, - Some(format!( - "Suspicious traces found at {}. Traces: {}", - body.url, - body.issues.join(", ") - )), + Some(header), ) .await .ok(); + let mut thread_header = format!("Suspicious traces found at [version {}](https://modrinth.com/project/{}/version/{})", body.version_id, body.project_id, body.version_id); + + for (issue, trace) in &body.issues { + for path in trace.keys() { + thread_header + .push_str(&format!("\n issue {issue} found at file {}", path)); + } + } + let mut transaction = pool.begin().await?; ThreadMessageBuilder { author_id: Some(crate::database::models::UserId(AUTOMOD_ID)), body: MessageBody::Text { - body: format!( - "WSR; Suspicious traces found for version_id {}. Traces: {}", - body.version_id, - body.issues.join(", ") - ), + body: thread_header, private: true, replying_to: None, associated_images: vec![], diff --git a/apps/labrinth/src/routes/internal/billing.rs b/apps/labrinth/src/routes/internal/billing.rs index 38a130c59..8d313a4dc 100644 --- a/apps/labrinth/src/routes/internal/billing.rs +++ b/apps/labrinth/src/routes/internal/billing.rs @@ -884,7 +884,7 @@ pub async fn active_servers( .head() .headers() .get("X-Master-Key") - .map_or(false, |it| it.as_bytes() == master_key.as_bytes()) + .is_some_and(|it| it.as_bytes() == master_key.as_bytes()) { return Err(ApiError::CustomAuthentication( "Invalid master key".to_string(), diff --git a/apps/labrinth/src/routes/v3/oauth_clients.rs b/apps/labrinth/src/routes/v3/oauth_clients.rs index a65dcc75d..3a9648f9f 100644 --- a/apps/labrinth/src/routes/v3/oauth_clients.rs +++ b/apps/labrinth/src/routes/v3/oauth_clients.rs @@ -160,7 +160,7 @@ pub struct NewOAuthApp { } #[post("app")] -pub async fn oauth_client_create<'a>( +pub async fn oauth_client_create( req: HttpRequest, new_oauth_app: web::Json, pool: web::Data, @@ -221,7 +221,7 @@ pub async fn oauth_client_create<'a>( } #[delete("app/{id}")] -pub async fn oauth_client_delete<'a>( +pub async fn oauth_client_delete( req: HttpRequest, client_id: web::Path, pool: web::Data, diff --git a/apps/labrinth/src/util/guards.rs b/apps/labrinth/src/util/guards.rs index f7ad43ccf..e6401fa4f 100644 --- a/apps/labrinth/src/util/guards.rs +++ b/apps/labrinth/src/util/guards.rs @@ -8,5 +8,5 @@ pub fn admin_key_guard(ctx: &GuardContext) -> bool { ctx.head() .headers() .get(ADMIN_KEY_HEADER) - .map_or(false, |it| it.as_bytes() == admin_key.as_bytes()) + .is_some_and(|it| it.as_bytes() == admin_key.as_bytes()) } From 9e97c068d8d62d037ea3c958a80fdf01b45d288c Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 17:41:41 -0800 Subject: [PATCH 17/30] Fix version_fields, loader_fields_loaders missing primary keys --- .../20250117013050_missing-primary-keys.sql | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 apps/labrinth/migrations/20250117013050_missing-primary-keys.sql diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql new file mode 100644 index 000000000..1bcadd678 --- /dev/null +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -0,0 +1,17 @@ +WITH CTE AS ( + SELECT ctid, + ROW_NUMBER() OVER (PARTITION BY version_id, field_id, enum_value ORDER BY ctid) AS row_num + FROM version_fields +) +DELETE FROM version_fields +WHERE ctid IN ( + SELECT ctid + FROM CTE + WHERE row_num > 1 +); + +ALTER TABLE version_fields +ADD PRIMARY KEY (version_id, field_id, enum_value); + +ALTER TABLE loader_fields_loaders +ADD PRIMARY KEY (loader_id, loader_field_id); \ No newline at end of file From 8abe2283d766b0e3b89c0c49a566d65ceec81e03 Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 17:49:26 -0800 Subject: [PATCH 18/30] Fix clippy --- apps/labrinth/src/routes/internal/billing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/labrinth/src/routes/internal/billing.rs b/apps/labrinth/src/routes/internal/billing.rs index 8d313a4dc..d6dc71bb4 100644 --- a/apps/labrinth/src/routes/internal/billing.rs +++ b/apps/labrinth/src/routes/internal/billing.rs @@ -880,11 +880,11 @@ pub async fn active_servers( ) -> Result { let master_key = dotenvy::var("PYRO_API_KEY")?; - if !req + if req .head() .headers() .get("X-Master-Key") - .is_some_and(|it| it.as_bytes() == master_key.as_bytes()) + .is_none_or(|it| it.as_bytes() != master_key.as_bytes()) { return Err(ApiError::CustomAuthentication( "Invalid master key".to_string(), From 208015a911dc53d678c81857e1b05377cefa81db Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 18:21:11 -0800 Subject: [PATCH 19/30] Bump rust version --- apps/labrinth/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/labrinth/Dockerfile b/apps/labrinth/Dockerfile index e7126e6dc..851579f78 100644 --- a/apps/labrinth/Dockerfile +++ b/apps/labrinth/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.81.0 as build +FROM rust:1.84.0 as build ENV PKG_CONFIG_ALLOW_CROSS=1 WORKDIR /usr/src/labrinth From 497b0bca0b85287b0542e7a19012c3d7c720fd01 Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 23:00:11 -0800 Subject: [PATCH 20/30] Fix broken migration on labrinth --- ...63153f6879d507dc1d1bb38846e16d9fa6cbd6cceea2efbfd51.json | 2 +- ...ac6d0c83fec4117d340e5970b27edc76f21b903f362329a6542.json | 2 +- ...f58b86083b659cb647498fcc20e38265b9d316ca8c0a2cbc02a.json | 2 +- .../migrations/20250117013050_missing-primary-keys.sql | 6 ++++++ apps/labrinth/src/database/models/project_item.rs | 6 +++--- apps/labrinth/src/database/models/version_item.rs | 6 +++--- apps/labrinth/src/search/indexing/local_import.rs | 6 +++++- 7 files changed, 20 insertions(+), 10 deletions(-) diff --git a/apps/labrinth/.sqlx/query-10f81e605c9ef63153f6879d507dc1d1bb38846e16d9fa6cbd6cceea2efbfd51.json b/apps/labrinth/.sqlx/query-10f81e605c9ef63153f6879d507dc1d1bb38846e16d9fa6cbd6cceea2efbfd51.json index 4caa17396..b2cf2a4c6 100644 --- a/apps/labrinth/.sqlx/query-10f81e605c9ef63153f6879d507dc1d1bb38846e16d9fa6cbd6cceea2efbfd51.json +++ b/apps/labrinth/.sqlx/query-10f81e605c9ef63153f6879d507dc1d1bb38846e16d9fa6cbd6cceea2efbfd51.json @@ -38,7 +38,7 @@ false, false, true, - true, + false, true ] }, diff --git a/apps/labrinth/.sqlx/query-53c50911a9e98ac6d0c83fec4117d340e5970b27edc76f21b903f362329a6542.json b/apps/labrinth/.sqlx/query-53c50911a9e98ac6d0c83fec4117d340e5970b27edc76f21b903f362329a6542.json index f932bd386..551803257 100644 --- a/apps/labrinth/.sqlx/query-53c50911a9e98ac6d0c83fec4117d340e5970b27edc76f21b903f362329a6542.json +++ b/apps/labrinth/.sqlx/query-53c50911a9e98ac6d0c83fec4117d340e5970b27edc76f21b903f362329a6542.json @@ -38,7 +38,7 @@ false, false, true, - true, + false, true ] }, diff --git a/apps/labrinth/.sqlx/query-7fa5098b1083af58b86083b659cb647498fcc20e38265b9d316ca8c0a2cbc02a.json b/apps/labrinth/.sqlx/query-7fa5098b1083af58b86083b659cb647498fcc20e38265b9d316ca8c0a2cbc02a.json index da471b1da..3610b34ca 100644 --- a/apps/labrinth/.sqlx/query-7fa5098b1083af58b86083b659cb647498fcc20e38265b9d316ca8c0a2cbc02a.json +++ b/apps/labrinth/.sqlx/query-7fa5098b1083af58b86083b659cb647498fcc20e38265b9d316ca8c0a2cbc02a.json @@ -44,7 +44,7 @@ false, false, true, - true, + false, true ] }, diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql index 1bcadd678..b39039b8e 100644 --- a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -1,3 +1,9 @@ +ALTER TABLE version_fields + ALTER COLUMN enum_value SET DEFAULT -1; + +ALTER TABLE version_fields + ALTER COLUMN enum_value SET NOT NULL; + WITH CTE AS ( SELECT ctid, ROW_NUMBER() OVER (PARTITION BY version_id, field_id, enum_value ORDER BY ctid) AS row_num diff --git a/apps/labrinth/src/database/models/project_item.rs b/apps/labrinth/src/database/models/project_item.rs index 1bd07d224..f7f3ab9ca 100644 --- a/apps/labrinth/src/database/models/project_item.rs +++ b/apps/labrinth/src/database/models/project_item.rs @@ -595,12 +595,12 @@ impl Project { version_id: VersionId(m.version_id), field_id: LoaderFieldId(m.field_id), int_value: m.int_value, - enum_value: m.enum_value.map(LoaderFieldEnumValueId), + enum_value: if m.enum_value == -1 { None } else { Some(LoaderFieldEnumValueId(m.enum_value)) }, string_value: m.string_value, }; - if let Some(enum_value) = m.enum_value { - loader_field_enum_value_ids.insert(LoaderFieldEnumValueId(enum_value)); + if m.enum_value != -1 { + loader_field_enum_value_ids.insert(LoaderFieldEnumValueId(m.enum_value)); } acc.entry(ProjectId(m.mod_id)).or_default().push(qvf); diff --git a/apps/labrinth/src/database/models/version_item.rs b/apps/labrinth/src/database/models/version_item.rs index 792c9ac0e..f8de51f69 100644 --- a/apps/labrinth/src/database/models/version_item.rs +++ b/apps/labrinth/src/database/models/version_item.rs @@ -499,12 +499,12 @@ impl Version { version_id: VersionId(m.version_id), field_id: LoaderFieldId(m.field_id), int_value: m.int_value, - enum_value: m.enum_value.map(LoaderFieldEnumValueId), + enum_value: if m.enum_value == -1 { None } else { Some(LoaderFieldEnumValueId(m.enum_value)) }, string_value: m.string_value, }; - if let Some(enum_value) = m.enum_value { - loader_field_enum_value_ids.insert(LoaderFieldEnumValueId(enum_value)); + if m.enum_value != -1 { + loader_field_enum_value_ids.insert(LoaderFieldEnumValueId(m.enum_value)); } acc.entry(VersionId(m.version_id)).or_default().push(qvf); diff --git a/apps/labrinth/src/search/indexing/local_import.rs b/apps/labrinth/src/search/indexing/local_import.rs index f24af8e28..4306888f3 100644 --- a/apps/labrinth/src/search/indexing/local_import.rs +++ b/apps/labrinth/src/search/indexing/local_import.rs @@ -505,7 +505,11 @@ async fn index_versions( version_id: VersionId(m.version_id), field_id: LoaderFieldId(m.field_id), int_value: m.int_value, - enum_value: m.enum_value.map(LoaderFieldEnumValueId), + enum_value: if m.enum_value == -1 { + None + } else { + Some(LoaderFieldEnumValueId(m.enum_value)) + }, string_value: m.string_value, }; From 7fd3d737b817b3c973bb381833eca4a0201aa75b Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 23:32:26 -0800 Subject: [PATCH 21/30] Fix broken migration on labrinth (again) --- .../labrinth/migrations/20250117013050_missing-primary-keys.sql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql index b39039b8e..4ec551ff1 100644 --- a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -1,6 +1,8 @@ ALTER TABLE version_fields ALTER COLUMN enum_value SET DEFAULT -1; +UPDATE version_fields SET enum_value = -1 WHERE enum_value IS NULL; + ALTER TABLE version_fields ALTER COLUMN enum_value SET NOT NULL; From 701bf853d54c7ed5643b2d21ae3042efc84f8a45 Mon Sep 17 00:00:00 2001 From: Jai A Date: Thu, 16 Jan 2025 23:59:07 -0800 Subject: [PATCH 22/30] Fix broken migration on labrinth (againx2) --- .../migrations/20250117013050_missing-primary-keys.sql | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql index 4ec551ff1..1a8588e23 100644 --- a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -1,3 +1,6 @@ +ALTER TABLE version_fields +DROP CONSTRAINT version_fields_enum_value_fkey; + ALTER TABLE version_fields ALTER COLUMN enum_value SET DEFAULT -1; From 24295ea482ed95856beca1002c489fd204040c12 Mon Sep 17 00:00:00 2001 From: Jai A Date: Fri, 17 Jan 2025 08:53:54 -0800 Subject: [PATCH 23/30] fix version uploading --- .../migrations/20250117013050_missing-primary-keys.sql | 2 +- apps/labrinth/src/database/models/loader_fields.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql index 1a8588e23..2054cf49f 100644 --- a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -20,7 +20,7 @@ WHERE ctid IN ( FROM CTE WHERE row_num > 1 ); - +x ALTER TABLE version_fields ADD PRIMARY KEY (version_id, field_id, enum_value); diff --git a/apps/labrinth/src/database/models/loader_fields.rs b/apps/labrinth/src/database/models/loader_fields.rs index 70c74150e..292c6e12a 100644 --- a/apps/labrinth/src/database/models/loader_fields.rs +++ b/apps/labrinth/src/database/models/loader_fields.rs @@ -757,7 +757,12 @@ impl VersionField { l.field_id.0, l.version_id.0, l.int_value, - l.enum_value.as_ref().map(|e| e.0), + if let Some(enum_value) = l.enum_value.as_ref().map(|e| e.0) + { + enum_value + } else { + -1 + }, l.string_value.clone(), ) }) @@ -772,7 +777,7 @@ impl VersionField { &version_ids[..], &int_values[..] as &[Option], &string_values[..] as &[Option], - &enum_values[..] as &[Option] + &enum_values[..] as &[i32] ) .execute(&mut **transaction) .await?; From d7814e115d5324ee59a9ee19becbb8de4da932f1 Mon Sep 17 00:00:00 2001 From: Jai A Date: Fri, 17 Jan 2025 09:05:42 -0800 Subject: [PATCH 24/30] fix migration typo --- .../labrinth/migrations/20250117013050_missing-primary-keys.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql index 2054cf49f..1a8588e23 100644 --- a/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql +++ b/apps/labrinth/migrations/20250117013050_missing-primary-keys.sql @@ -20,7 +20,7 @@ WHERE ctid IN ( FROM CTE WHERE row_num > 1 ); -x + ALTER TABLE version_fields ADD PRIMARY KEY (version_id, field_id, enum_value); From 75b357a0694601ab2c94f5bf96272ec9dc04aead Mon Sep 17 00:00:00 2001 From: Jai Agrawal <18202329+Geometrically@users.noreply.github.com> Date: Fri, 17 Jan 2025 16:41:49 -0800 Subject: [PATCH 25/30] Staff support dashboard routes (#3160) * Staff support dashboard routes * Fix clippy --- .../frontend/src/pages/admin/billing/[id].vue | 210 ++++++++++++++++++ .../src/pages/settings/billing/charges.vue | 18 +- apps/frontend/src/pages/user/[id].vue | 89 +++++++- .../src/database/models/loader_fields.rs | 7 +- apps/labrinth/src/routes/internal/billing.rs | 38 +++- apps/labrinth/src/routes/v2/users.rs | 4 +- .../src/routes/v3/project_creation.rs | 4 - apps/labrinth/src/routes/v3/users.rs | 21 +- .../src/routes/v3/version_creation.rs | 16 +- 9 files changed, 371 insertions(+), 36 deletions(-) create mode 100644 apps/frontend/src/pages/admin/billing/[id].vue diff --git a/apps/frontend/src/pages/admin/billing/[id].vue b/apps/frontend/src/pages/admin/billing/[id].vue new file mode 100644 index 000000000..c5c72b5d4 --- /dev/null +++ b/apps/frontend/src/pages/admin/billing/[id].vue @@ -0,0 +1,210 @@ + + diff --git a/apps/frontend/src/pages/settings/billing/charges.vue b/apps/frontend/src/pages/settings/billing/charges.vue index c1195d2a4..a4c8eddc1 100644 --- a/apps/frontend/src/pages/settings/billing/charges.vue +++ b/apps/frontend/src/pages/settings/billing/charges.vue @@ -25,7 +25,7 @@ ⋅ - {{ formatPrice(charge.amount, charge.currency_code) }} + {{ formatPrice(vintl.locale, charge.amount, charge.currency_code) }}
@@ -39,6 +39,7 @@ diff --git a/apps/frontend/src/pages/user/[id].vue b/apps/frontend/src/pages/user/[id].vue index fe48a8485..14c1af888 100644 --- a/apps/frontend/src/pages/user/[id].vue +++ b/apps/frontend/src/pages/user/[id].vue @@ -2,6 +2,57 @@
+ +
+
+ Email +
+ + {{ user.email }} + + + +
+
+ +
+ Auth providers + {{ user.auth_providers.join(", ") }} +
+ +
+ Payment methods + + + + + +
+ +
+ Has password + + {{ user.has_password ? "Yes" : "No" }} + +
+ +
+ Has TOTP + + {{ user.has_totp ? "Yes" : "No" }} + +
+
+
- @@ -89,13 +92,15 @@ :type="charge.status" /> ⋅ + {{ charge.type }} + ⋅ {{ $dayjs(charge.due).format("YYYY-MM-DD") }} ⋅ {{ formatPrice(vintl.locale, charge.amount, charge.currency_code) }}