add song and add album working now
Some checks failed
CI / Check Style (push) Has been cancelled
CI / Run Clippy (push) Has been cancelled
CI / Run Tests (push) Has been cancelled

This commit is contained in:
Priec
2026-05-17 19:01:01 +02:00
parent c1ecfa459d
commit ec5a3a3d73
4 changed files with 115 additions and 3 deletions

1
.gitignore vendored
View File

@@ -20,3 +20,4 @@ target/
*.sqlite-*
.env
.env.production
uploads/

View File

@@ -40,6 +40,27 @@
<textarea name="description" rows="6" class="textarea textarea-bordered w-full"></textarea>
</div>
<div class="form-control">
<label class="label"><span class="label-text">Songs</span></label>
{% if available_tracks | length > 0 %}
<div class="divide-y divide-base-300 rounded border border-base-300">
{% for song in available_tracks %}
<label class="flex cursor-pointer items-center gap-3 p-2 hover:bg-base-200">
<input type="checkbox" name="track_ids" value="{{ song.id }}" class="checkbox checkbox-sm">
<span class="min-w-0 flex-1">
<span class="block truncate font-medium">{{ song.title }}</span>
<span class="block truncate text-xs opacity-70">{{ song.audio_file_id }}</span>
</span>
</label>
{% endfor %}
</div>
{% else %}
<div class="rounded border border-base-300 p-2 text-sm opacity-70">
No ungrouped songs available.
</div>
{% endif %}
</div>
<label class="label cursor-pointer justify-start gap-2">
<input type="checkbox" name="published" class="checkbox checkbox-sm">
<span class="label-text">Published</span>

View File

@@ -17,6 +17,20 @@
<div class="card border border-base-300 bg-base-100 shadow-sm">
<div class="card-body">
{% if available_tracks | length > 0 %}
<form method="post" action="/admin/audio/albums/{{ album.id }}/tracks/add" class="mb-4 flex flex-wrap items-end gap-2">
<div class="form-control flex-1">
<label class="label"><span class="label-text">Add existing song</span></label>
<select name="track_id" required class="select select-bordered w-full">
{% for song in available_tracks %}
<option value="{{ song.id }}">{{ song.title }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-neutral btn-sm">Add to album</button>
</form>
{% endif %}
{% if tracks | length > 0 %}
<div class="overflow-x-auto">
<table class="table">
@@ -62,6 +76,9 @@
<button type="submit" class="btn btn-ghost btn-sm">Publish</button>
</form>
{% endif %}
<form method="post" action="/admin/audio/tracks/{{ track.id }}/remove-from-album">
<button type="submit" class="btn btn-ghost btn-sm">Remove</button>
</form>
<form method="post" action="/admin/audio/tracks/{{ track.id }}/delete">
<button type="submit" class="btn btn-ghost btn-sm">Delete</button>
</form>

View File

@@ -44,6 +44,13 @@ struct AlbumForm {
artist: Option<String>,
release_date: Option<String>,
published: Option<String>,
#[serde(default)]
track_ids: Vec<Uuid>,
}
#[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<TeraView>, State(ctx): State<AppContext>) -> Result<Response> {
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, &params.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<Uuid>,
State(ctx): State<AppContext>,
Form(params): Form<AlbumSongForm>,
) -> Result<Response> {
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<Uuid>,
State(ctx): State<AppContext>,
) -> Result<Response> {
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))
}