From 1f983bbecfc6e86945f396f6cd86ea67f0709b6f Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Fri, 20 Mar 2026 20:04:35 -0400 Subject: [PATCH] Minimal subsonic functionality --- src/entities/user.rs | 3 ++ .../m20260320_000015_add_subsonic_password.rs | 35 +++++++++++++++++++ src/migration/mod.rs | 2 ++ src/queries/users.rs | 13 +++++++ 4 files changed, 53 insertions(+) create mode 100644 src/migration/m20260320_000015_add_subsonic_password.rs diff --git a/src/entities/user.rs b/src/entities/user.rs index f00a8a9..60d9628 100644 --- a/src/entities/user.rs +++ b/src/entities/user.rs @@ -19,6 +19,9 @@ pub struct Model { pub username: String, #[serde(skip_serializing)] pub password_hash: String, + #[serde(skip_serializing)] + #[sea_orm(nullable)] + pub subsonic_password: Option, pub role: UserRole, pub created_at: chrono::NaiveDateTime, pub updated_at: chrono::NaiveDateTime, diff --git a/src/migration/m20260320_000015_add_subsonic_password.rs b/src/migration/m20260320_000015_add_subsonic_password.rs new file mode 100644 index 0000000..82ab590 --- /dev/null +++ b/src/migration/m20260320_000015_add_subsonic_password.rs @@ -0,0 +1,35 @@ +use sea_orm_migration::prelude::*; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Users::Table) + .add_column(ColumnDef::new(Users::SubsonicPassword).text()) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Users::Table) + .drop_column(Users::SubsonicPassword) + .to_owned(), + ) + .await + } +} + +#[derive(DeriveIden)] +enum Users { + Table, + SubsonicPassword, +} diff --git a/src/migration/mod.rs b/src/migration/mod.rs index 2981bfd..5ba9f6e 100644 --- a/src/migration/mod.rs +++ b/src/migration/mod.rs @@ -13,6 +13,7 @@ mod m20260319_000011_create_users; mod m20260319_000012_add_user_id_to_wanted_items; mod m20260320_000013_add_artist_monitoring; mod m20260320_000014_create_playlists; +mod m20260320_000015_add_subsonic_password; pub struct Migrator; @@ -33,6 +34,7 @@ impl MigratorTrait for Migrator { Box::new(m20260319_000012_add_user_id_to_wanted_items::Migration), Box::new(m20260320_000013_add_artist_monitoring::Migration), Box::new(m20260320_000014_create_playlists::Migration), + Box::new(m20260320_000015_add_subsonic_password::Migration), ] } } diff --git a/src/queries/users.rs b/src/queries/users.rs index b06aa29..8881bc2 100644 --- a/src/queries/users.rs +++ b/src/queries/users.rs @@ -52,6 +52,19 @@ pub async fn count(db: &DatabaseConnection) -> DbResult { Ok(Users::find().count(db).await?) } +/// Set the Subsonic password for a user. Stored as plaintext per the Subsonic protocol. +pub async fn set_subsonic_password( + db: &DatabaseConnection, + user_id: i32, + password: &str, +) -> DbResult { + let existing = get_by_id(db, user_id).await?; + let mut active: ActiveModel = existing.into(); + active.subsonic_password = Set(Some(password.to_string())); + active.updated_at = Set(Utc::now().naive_utc()); + Ok(active.update(db).await?) +} + /// Assign all orphaned wanted items (user_id IS NULL) to the given user. pub async fn adopt_orphaned_wanted_items(db: &DatabaseConnection, user_id: i32) -> DbResult { use crate::entities::wanted_item;