diff --git a/DeepDrftAPI/Controllers/TrackController.cs b/DeepDrftAPI/Controllers/TrackController.cs index 6591dc9..83ad7ec 100644 --- a/DeepDrftAPI/Controllers/TrackController.cs +++ b/DeepDrftAPI/Controllers/TrackController.cs @@ -124,11 +124,12 @@ public class TrackController : ControllerBase [FromForm] string? album, [FromForm] string? genre, [FromForm] string? releaseDate, + [FromForm] string? originalFileName, [FromForm] long createdByUserId, CancellationToken cancellationToken) { - _logger.LogInformation("UploadTrack called: trackName={TrackName}, artist={Artist}, size={Size}", - trackName, artist, wav?.Length); + _logger.LogInformation("UploadTrack called: trackName={TrackName}, artist={Artist}, fileName={FileName}, size={Size}", + trackName, artist, originalFileName, wav?.Length); if (wav is null || wav.Length == 0) { @@ -182,6 +183,7 @@ public class TrackController : ControllerBase string.IsNullOrWhiteSpace(genre) ? null : genre, parsedReleaseDate, createdByUserId, + string.IsNullOrWhiteSpace(originalFileName) ? null : originalFileName, cancellationToken); if (!result.Success || result.Value is null) diff --git a/DeepDrftAPI/Services/UnifiedTrackService.cs b/DeepDrftAPI/Services/UnifiedTrackService.cs index 6963100..796105c 100644 --- a/DeepDrftAPI/Services/UnifiedTrackService.cs +++ b/DeepDrftAPI/Services/UnifiedTrackService.cs @@ -49,10 +49,11 @@ public class UnifiedTrackService string? genre, DateOnly? releaseDate, long createdByUserId, + string? originalFileName, CancellationToken ct) { var unpersisted = await _contentTrackContentService.AddTrackFromWavAsync( - tempFilePath, trackName, artist, album, genre, releaseDate); + tempFilePath, trackName, artist, album, genre, releaseDate, originalFileName: originalFileName); if (unpersisted is null) { diff --git a/DeepDrftContent/TrackContentService.cs b/DeepDrftContent/TrackContentService.cs index 7a4f8a3..6eaf7a2 100644 --- a/DeepDrftContent/TrackContentService.cs +++ b/DeepDrftContent/TrackContentService.cs @@ -29,6 +29,7 @@ public class TrackContentService /// Optional album name /// Optional genre /// Optional release date + /// Optional original browser filename captured at upload time /// The track entity with generated ID and media path public async Task AddTrackFromWavAsync( string wavFilePath, @@ -36,7 +37,8 @@ public class TrackContentService string artist, string? album = null, string? genre = null, - DateOnly? releaseDate = null) + DateOnly? releaseDate = null, + string? originalFileName = null) { try { @@ -71,7 +73,8 @@ public class TrackContentService Artist = artist, Album = album, Genre = genre, - ReleaseDate = releaseDate + ReleaseDate = releaseDate, + OriginalFileName = originalFileName }; return trackEntity; diff --git a/DeepDrftData/Data/Configurations/TrackConfiguration.cs b/DeepDrftData/Data/Configurations/TrackConfiguration.cs index 1075da7..128639d 100644 --- a/DeepDrftData/Data/Configurations/TrackConfiguration.cs +++ b/DeepDrftData/Data/Configurations/TrackConfiguration.cs @@ -53,6 +53,10 @@ public class TrackConfiguration : BaseEntityConfiguration builder.Property(e => e.CreatedByUserId) .HasColumnName("created_by_user_id"); + builder.Property(e => e.OriginalFileName) + .HasMaxLength(500) + .HasColumnName("original_file_name"); + // Names the is_deleted index explicitly. BaseEntityConfiguration.Configure already // calls HasIndex(e => e.IsDeleted); this adds HasDatabaseName so EF always uses // "IX_track_is_deleted" regardless of auto-naming conventions. diff --git a/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.Designer.cs b/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.Designer.cs new file mode 100644 index 0000000..cd2d5f4 --- /dev/null +++ b/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.Designer.cs @@ -0,0 +1,107 @@ +// +using System; +using DeepDrftData.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DeepDrftData.Migrations +{ + [DbContext(typeof(DeepDrftContext))] + [Migration("20260607124422_AddOriginalFileName")] + partial class AddOriginalFileName + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DeepDrftModels.Entities.TrackEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Album") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("album"); + + b.Property("Artist") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("artist"); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_at"); + + b.Property("CreatedByUserId") + .HasColumnType("bigint") + .HasColumnName("created_by_user_id"); + + b.Property("EntryKey") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("entry_key"); + + b.Property("Genre") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("genre"); + + b.Property("ImagePath") + .HasMaxLength(500) + .HasColumnType("character varying(500)") + .HasColumnName("image_path"); + + b.Property("IsDeleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("is_deleted"); + + b.Property("OriginalFileName") + .HasMaxLength(500) + .HasColumnType("character varying(500)") + .HasColumnName("original_file_name"); + + b.Property("ReleaseDate") + .HasColumnType("date") + .HasColumnName("release_date"); + + b.Property("TrackName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("track_name"); + + b.Property("UpdatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_at"); + + b.HasKey("Id"); + + b.HasIndex("IsDeleted") + .HasDatabaseName("IX_track_is_deleted"); + + b.ToTable("track", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.cs b/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.cs new file mode 100644 index 0000000..7cf2da5 --- /dev/null +++ b/DeepDrftData/Migrations/20260607124422_AddOriginalFileName.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DeepDrftData.Migrations +{ + /// + public partial class AddOriginalFileName : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "original_file_name", + table: "track", + type: "character varying(500)", + maxLength: 500, + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "original_file_name", + table: "track"); + } + } +} diff --git a/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs b/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs index ed99ec0..45cd361 100644 --- a/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs +++ b/DeepDrftData/Migrations/DeepDrftContextModelSnapshot.cs @@ -72,6 +72,11 @@ namespace DeepDrftData.Migrations .HasDefaultValue(false) .HasColumnName("is_deleted"); + b.Property("OriginalFileName") + .HasMaxLength(500) + .HasColumnType("character varying(500)") + .HasColumnName("original_file_name"); + b.Property("ReleaseDate") .HasColumnType("date") .HasColumnName("release_date"); diff --git a/DeepDrftData/TrackConverter.cs b/DeepDrftData/TrackConverter.cs index 30e7173..b8d2172 100644 --- a/DeepDrftData/TrackConverter.cs +++ b/DeepDrftData/TrackConverter.cs @@ -24,7 +24,8 @@ public class TrackConverter : IEntityToModelConverter Genre = entity.Genre, ReleaseDate = entity.ReleaseDate, ImagePath = entity.ImagePath, - CreatedByUserId = entity.CreatedByUserId + CreatedByUserId = entity.CreatedByUserId, + OriginalFileName = entity.OriginalFileName }; public static TrackEntity Convert(TrackDto model) => new() @@ -39,6 +40,7 @@ public class TrackConverter : IEntityToModelConverter Genre = model.Genre, ReleaseDate = model.ReleaseDate, ImagePath = model.ImagePath, - CreatedByUserId = model.CreatedByUserId + CreatedByUserId = model.CreatedByUserId, + OriginalFileName = model.OriginalFileName }; } diff --git a/DeepDrftManager/Components/Pages/Tracks/TrackList.razor b/DeepDrftManager/Components/Pages/Tracks/TrackList.razor index fdee66d..aacde5e 100644 --- a/DeepDrftManager/Components/Pages/Tracks/TrackList.razor +++ b/DeepDrftManager/Components/Pages/Tracks/TrackList.razor @@ -47,6 +47,7 @@ Genre Release Date Entry Key + File Name Actions @@ -56,6 +57,7 @@ @(context.Genre ?? "—") @(context.ReleaseDate?.ToString("yyyy-MM-dd") ?? "—") @context.EntryKey + @(context.OriginalFileName ?? "—") Id. A vault-without-SQL /// orphan is handled and logged server-side; here it surfaces as a failed result. + /// is the browser's filename, captured at upload time and + /// stored as metadata; it is not user-editable afterwards. /// Task> UploadTrackAsync( Stream wavStream, @@ -25,6 +27,7 @@ public interface ICmsTrackService string? album, string? genre, string? releaseDate, + string? originalFileName, long createdByUserId, CancellationToken ct = default); diff --git a/DeepDrftModels/DTOs/TrackDto.cs b/DeepDrftModels/DTOs/TrackDto.cs index c368262..6b499db 100644 --- a/DeepDrftModels/DTOs/TrackDto.cs +++ b/DeepDrftModels/DTOs/TrackDto.cs @@ -18,4 +18,5 @@ public class TrackDto : BaseModel public DateOnly? ReleaseDate { get; set; } public string? ImagePath { get; set; } public long? CreatedByUserId { get; set; } + public string? OriginalFileName { get; set; } } diff --git a/DeepDrftModels/Entities/TrackEntity.cs b/DeepDrftModels/Entities/TrackEntity.cs index 28d8b14..688c22e 100644 --- a/DeepDrftModels/Entities/TrackEntity.cs +++ b/DeepDrftModels/Entities/TrackEntity.cs @@ -15,4 +15,5 @@ public class TrackEntity : BaseEntity, IEntity public DateOnly? ReleaseDate { get; set; } public string? ImagePath { get; set; } public long? CreatedByUserId { get; set; } + public string? OriginalFileName { get; set; } }