This commit is contained in:
2026-09-24 17:58:48 +02:00
parent e84c16cf92
commit 1a302491d1
37 changed files with 0 additions and 61 deletions
@@ -9,7 +9,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums
{
/// <summary>Appends your own tracks to an album in the given order, skipping the ones it already has.</summary>
public record AddTracksToAlbumCommand(long UserId, Guid AlbumId, IReadOnlyList<Guid> TrackIds)
: ICommand<ErrorOr<Success>>;
@@ -50,7 +49,6 @@ namespace Musify.Application.Albums
if (toAdd.Count == 0)
return Result.Success;
// Album track numbers are user-visible, so they start at 1.
var nextTrackNumber = (await database.AlbumHasTracks
.Where(link => link.AlbumId == request.AlbumId)
.MaxAsync(link => (int?)link.TrackNumber, cancellationToken) ?? 0) + 1;
@@ -30,7 +30,6 @@ namespace Musify.Application.Albums
var album = found.Value;
var title = request.Title.Trim();
// This is a full replace of the plain fields; the picture has its own command.
album.Title = title;
album.NormalizedTitle = TextNormalizer.Normalize(title);
album.Description = string.IsNullOrWhiteSpace(request.Description) ? null : request.Description.Trim();
@@ -13,7 +13,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.Albums
{
/// <summary>Replaces an album's picture with a previously uploaded image; the plain fields are untouched.</summary>
public record UpdateAlbumPictureCommand(long UserId, Guid AlbumId, Guid PictureIntentId)
: ICommand<ErrorOr<AlbumApplicationResponse>>;
@@ -83,7 +83,6 @@ namespace Musify.Application.Configuration
public static class PictureSizeParser
{
/// <summary>Parses the <c>size</c> query value; anything unknown means <see cref="PictureSize.Medium"/>.</summary>
public static PictureSize Parse(string? value) =>
Enum.TryParse<PictureSize>(value, ignoreCase: true, out var size) && Enum.IsDefined(size)
? size
@@ -2,7 +2,6 @@ namespace Musify.Application.Contracts
{
public interface IStorageService
{
/// <summary>Opens an object for reading, or returns null when it does not exist.</summary>
public Task<Stream?> GetFileAsync(string bucket, string key, CancellationToken cancellationToken);
public Task<ObjectMetaData?> HeadObjectAsync(string bucket, string key, CancellationToken cancellationToken);
@@ -44,7 +44,6 @@ namespace Musify.Application.Likes
nowLiked = true;
}
// A concurrent double click can hit the unique index; the outcome is already in place, so treat it as a no-op.
var saved = await database.TrySaveChangesAsync(
AppErrors.Conflict("TrackLike.Duplicate", "Track is already liked."), cancellationToken);
if (saved.IsError)
@@ -60,7 +60,6 @@ namespace Musify.Application.Pictures
_ => source.Medium
};
// The resized files only exist once processing has finished; until then serve the original.
var (name, key) = !string.IsNullOrEmpty(resizedName)
? (resizedName, routes.BuildPicturePath(request.Size, resizedName))
: !string.IsNullOrEmpty(source.Original)
@@ -7,7 +7,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.Pictures
{
/// <summary>What an album or playlist needs to switch to a freshly uploaded picture.</summary>
public sealed record PreparedPicture(UploadIntent Intent, EntityPictures Pictures, string FinalKey, ImageSizes Sizes);
public static class PictureSourceChange
@@ -11,7 +11,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists
{
/// <summary>Appends every track of an album to a playlist in album order, skipping the ones it already has.</summary>
public record AddAlbumToPlayListCommand(long UserId, Guid PlayListId, Guid AlbumId)
: ICommand<ErrorOr<AddAlbumToPlayListResponse>>;
@@ -54,7 +53,6 @@ namespace Musify.Application.PlayLists
if (newTrackIds.Count == 0)
return new AddAlbumToPlayListResponse(0);
// Playlist positions are internal indexes, so they start at 0.
var nextPosition = existingTrackIds.Count > 0
? await playListTracksQuery.MaxAsync(link => link.Position, cancellationToken) + 1
: 0;
@@ -9,7 +9,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists
{
/// <summary>Appends tracks to a playlist in the given order, skipping the ones it already has.</summary>
public record AddTracksToPlayListCommand(long UserId, Guid PlayListId, IReadOnlyList<Guid> TrackIds)
: ICommand<ErrorOr<Success>>;
@@ -46,7 +45,6 @@ namespace Musify.Application.PlayLists
if (toAdd.Count == 0)
return Result.Success;
// Playlist positions are internal indexes, so they start at 0.
var playListTracksQuery = database.PlayListHasTracks
.Where(link => link.PlayListId == request.PlayListId);
@@ -30,7 +30,6 @@ namespace Musify.Application.PlayLists
var playList = found.Value;
// This is a full replace of the plain fields; the picture has its own command.
playList.Name = request.NewName.Trim();
playList.NormalizedName = TextNormalizer.Normalize(request.NewName);
playList.Description = string.IsNullOrWhiteSpace(request.NewDescription) ? null : request.NewDescription.Trim();
@@ -13,7 +13,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.PlayLists
{
/// <summary>Replaces a playlist's picture with a previously uploaded image; the plain fields are untouched.</summary>
public record UpdatePlayListPictureCommand(long UserId, Guid PlayListId, Guid PictureIntentId)
: ICommand<ErrorOr<PlayListApplicationResponse>>;
@@ -4,7 +4,6 @@ using Musify.Application.Tracks.Responses;
namespace Musify.Application.Services
{
/// <summary>Builds the stream URL and signed ticket for a processed track. It never touches the database.</summary>
public sealed class TrackStreamIssuer(
IStreamTicketService ticketService,
TrackConfiguration trackConfiguration,
@@ -24,7 +24,6 @@ namespace Musify.Application.Services
string ContentType,
string UploadUrl);
/// <summary>Issues pre-signed upload URLs and the upload intents that track them, checking the user quota first.</summary>
public sealed class UploadIntentIssuer(
IDatabase database,
IStorageService storageService,
@@ -7,10 +7,6 @@ namespace Musify.Application.Shared
{
public static class OwnershipExtensions
{
/// <summary>
/// Loads an active, tracked entity owned by <paramref name="userId"/>: NotFound when it is missing
/// or not active, Forbidden when someone else owns it.
/// </summary>
public static async Task<ErrorOr<T>> FindOwnedAsync<T>(
this DbSet<T> set, Guid id, long userId, CancellationToken cancellationToken)
where T : class, IOwnedEntity, IHasLifeCycle
@@ -18,7 +18,6 @@ namespace Musify.Application.Shared
public static class PaginationExtensions
{
/// <summary>Counts and pages the same (already filtered, ordered and projected) query.</summary>
public static async Task<PaginatedResponse<T>> ToPaginatedAsync<T>(
this IQueryable<T> query, PageRequest page, CancellationToken cancellationToken)
{
@@ -13,7 +13,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.Tracks
{
/// <summary>Starts a listen: records it for signed-in users and issues the stream ticket.</summary>
public record StartListeningCommand(Guid TrackId, long? UserId)
: ICommand<ErrorOr<TrackStreamResponse>>;
@@ -5,7 +5,6 @@ using Musify.Application.Contracts;
namespace Musify.Application.UploadIntents
{
/// <summary>Deletes temporary upload objects that nobody claimed within the retention window.</summary>
public record DeleteStaleTempUploadsCommand : ICommand<int>;
public class DeleteStaleTempUploadsCommandHandler(
@@ -7,7 +7,6 @@ using Musify.Domain.ValueObjects;
namespace Musify.Application.UploadIntents
{
/// <summary>Marks overdue upload intents as expired and deletes the ones expired for longer than the retention window.</summary>
public record ExpireUploadIntentsCommand : ICommand<int>;
public class ExpireUploadIntentsCommandHandler(
@@ -38,7 +38,6 @@ namespace Musify.Application.Users
FollowedId = request.FollowedId
}, cancellationToken);
// A concurrent double click can hit the unique index; already following is a successful no-op.
var saved = await database.TrySaveChangesAsync(
AppErrors.Conflict("UserFollow.Duplicate", "Already following this user."), cancellationToken);
if (saved.IsError)