+ {% if available_tracks | length > 0 %}
+
+ {% endif %}
+
{% if tracks | length > 0 %}
@@ -62,6 +76,9 @@
{% endif %}
+
diff --git a/src/controllers/media.rs b/src/controllers/media.rs
index 4270fbe..dd9afba 100644
--- a/src/controllers/media.rs
+++ b/src/controllers/media.rs
@@ -44,6 +44,13 @@ struct AlbumForm {
artist: Option,
release_date: Option,
published: Option,
+ #[serde(default)]
+ track_ids: Vec,
+}
+
+#[derive(Debug, Deserialize)]
+struct AlbumSongForm {
+ track_id: Uuid,
}
#[derive(Debug, Serialize)]
@@ -538,7 +545,12 @@ async fn admin_tracks(
#[debug_handler]
async fn admin_album_new(auth: auth::JWT, ViewEngine(v): ViewEngine, State(ctx): State) -> Result {
admin::current_admin(auth, &ctx).await?;
- format::view(&v, "admin/audio/new_album.html", json!({}))
+ let available_tracks = audio_tracks::Entity::find()
+ .filter(audio_tracks::Column::AlbumId.is_null())
+ .order_by_asc(audio_tracks::Column::Title)
+ .all(&ctx.db)
+ .await?;
+ format::view(&v, "admin/audio/new_album.html", json!({ "available_tracks": available_tracks }))
}
#[debug_handler]
@@ -552,7 +564,7 @@ async fn admin_album_create(
let release_date = normalize_empty(params.release_date)
.and_then(|date| NaiveDate::parse_from_str(&date, "%Y-%m-%d").ok());
- audio_albums::ActiveModel {
+ let album = audio_albums::ActiveModel {
id: Set(Uuid::new_v4()),
title: Set(params.title.clone()),
slug: Set(unique_album_slug(&ctx, ¶ms.title).await?),
@@ -569,6 +581,17 @@ async fn admin_album_create(
.insert(&ctx.db)
.await?;
+ for track_id in params.track_ids {
+ let track = track_by_id(&ctx, track_id).await?;
+ if track.album_id.is_some() {
+ return Err(Error::BadRequest("selected song already belongs to an album".to_string()));
+ }
+
+ let mut active = track.into_active_model();
+ active.album_id = Set(Some(album.id));
+ active.update(&ctx.db).await?;
+ }
+
format::redirect("/admin/audio/albums")
}
@@ -587,14 +610,62 @@ async fn admin_album_tracks(
.order_by_asc(audio_tracks::Column::Title)
.all(&ctx.db)
.await?;
+ let available_tracks = audio_tracks::Entity::find()
+ .filter(audio_tracks::Column::AlbumId.is_null())
+ .order_by_asc(audio_tracks::Column::Title)
+ .all(&ctx.db)
+ .await?;
format::view(
&v,
"admin/audio/tracks.html",
- json!({ "album": album, "tracks": tracks }),
+ json!({ "album": album, "tracks": tracks, "available_tracks": available_tracks }),
)
}
+#[debug_handler]
+async fn admin_album_add_track(
+ auth: auth::JWT,
+ Path(album_id): Path,
+ State(ctx): State,
+ Form(params): Form,
+) -> Result {
+ admin::current_admin(auth, &ctx).await?;
+ album_by_id(&ctx, album_id).await?;
+ let track = track_by_id(&ctx, params.track_id).await?;
+
+ if track.album_id.is_some() {
+ return Err(Error::BadRequest("song already belongs to an album".to_string()));
+ }
+
+ let mut active = track.into_active_model();
+ active.album_id = Set(Some(album_id));
+ active.update(&ctx.db).await?;
+
+ format::redirect(&format!("/admin/audio/albums/{album_id}/tracks"))
+}
+
+#[debug_handler]
+async fn admin_track_remove_from_album(
+ auth: auth::JWT,
+ Path(id): Path,
+ State(ctx): State,
+) -> Result {
+ admin::current_admin(auth, &ctx).await?;
+ let track = track_by_id(&ctx, id).await?;
+ let album_id = track.album_id;
+ let mut active = track.into_active_model();
+ active.album_id = Set(None);
+ active.track_number = Set(None);
+ active.update(&ctx.db).await?;
+
+ if let Some(album_id) = album_id {
+ format::redirect(&format!("/admin/audio/albums/{album_id}/tracks"))
+ } else {
+ format::redirect("/admin/audio/tracks")
+ }
+}
+
#[debug_handler]
async fn admin_track_upload_form(
auth: auth::JWT,
@@ -856,9 +927,11 @@ pub fn routes() -> Routes {
.add("/admin/audio/tracks/upload", get(admin_song_upload_form))
.add("/admin/audio/tracks/upload-file", post(admin_song_upload).layer(DefaultBodyLimit::max(AUDIO_MAX_BYTES + 1024 * 1024)))
.add("/admin/audio/albums/{album_id}/tracks", get(admin_album_tracks))
+ .add("/admin/audio/albums/{album_id}/tracks/add", post(admin_album_add_track))
.add("/admin/audio/albums/{album_id}/tracks/upload", get(admin_track_upload_form))
.add("/admin/audio/albums/{album_id}/tracks/upload-file", post(admin_track_upload).layer(DefaultBodyLimit::max(AUDIO_MAX_BYTES + 1024 * 1024)))
.add("/admin/audio/tracks/{id}/publish", post(admin_track_publish))
.add("/admin/audio/tracks/{id}/unpublish", post(admin_track_unpublish))
+ .add("/admin/audio/tracks/{id}/remove-from-album", post(admin_track_remove_from_album))
.add("/admin/audio/tracks/{id}/delete", post(admin_track_delete))
}