diff --git a/Application/PlayLists/Commands/AddTrackToPlayListCommand.cs b/Application/PlayLists/Commands/AddTrackToPlayListCommand.cs new file mode 100644 index 0000000..3d5e96b --- /dev/null +++ b/Application/PlayLists/Commands/AddTrackToPlayListCommand.cs @@ -0,0 +1,8 @@ +using Ardalis.Result; +using Mediator; + +namespace Musify.Application.PlayLists.Commands +{ + public record AddTrackToPlayListCommand(long UserId, Guid PlayListId, Guid TrackId) + : ICommand; +} diff --git a/Application/PlayLists/Commands/RemoveTrackFromPlayListCommand.cs b/Application/PlayLists/Commands/RemoveTrackFromPlayListCommand.cs new file mode 100644 index 0000000..991267d --- /dev/null +++ b/Application/PlayLists/Commands/RemoveTrackFromPlayListCommand.cs @@ -0,0 +1,8 @@ +using Ardalis.Result; +using Mediator; + +namespace Musify.Application.PlayLists.Commands +{ + public record RemoveTrackFromPlayListCommand(long UserId, Guid PlayListId, Guid TrackId) + : ICommand; +} diff --git a/Application/PlayLists/Handlers/AddTrackToPlayListCommandHandler.cs b/Application/PlayLists/Handlers/AddTrackToPlayListCommandHandler.cs new file mode 100644 index 0000000..c078f9f --- /dev/null +++ b/Application/PlayLists/Handlers/AddTrackToPlayListCommandHandler.cs @@ -0,0 +1,70 @@ +using Ardalis.Result; +using Mediator; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Musify.Application.Contracts; +using Musify.Application.PlayLists.Commands; +using Musify.Domain.Entities; + +namespace Musify.Application.PlayLists.Handlers +{ + public class AddTrackToPlayListCommandHandler( + IDatabase database, + ILogger logger) + : ICommandHandler + { + public async ValueTask Handle(AddTrackToPlayListCommand request, CancellationToken cancellationToken) + { + var playList = await database.PlayLists + .SingleOrDefaultAsync(pl => pl.Id == request.PlayListId, cancellationToken); + if (playList is null) + { + logger.LogInformation("Playlist {PlayListId} not found", request.PlayListId); + return Result.NotFound(); + } + + if (playList.UserId != request.UserId) + { + logger.LogWarning("User {UserId} is not the owner of playlist {PlayListId}", request.UserId, request.PlayListId); + return Result.Unauthorized(); + } + + var trackExists = await database.Tracks + .AsNoTracking() + .AnyAsync(t => t.Id == request.TrackId, cancellationToken); + if (!trackExists) + { + logger.LogInformation("Track {TrackId} not found", request.TrackId); + return Result.NotFound($"Track {request.TrackId} not found"); + } + + var alreadyAdded = await database.PlayListHasTracks + .AsNoTracking() + .AnyAsync(plt => plt.PlayListId == request.PlayListId && plt.TrackId == request.TrackId, cancellationToken); + if (alreadyAdded) + { + logger.LogInformation("Track {TrackId} already in playlist {PlayListId}", request.TrackId, request.PlayListId); + return Result.Conflict("Track is already in the playlist."); + } + + var nextPosition = await database.PlayListHasTracks + .Where(plt => plt.PlayListId == request.PlayListId) + .Select(plt => (int?)plt.Position) + .MaxAsync(cancellationToken) + 1 ?? 0; + + await database.PlayListHasTracks.AddAsync(new PlayListHasTrack + { + PlayListId = request.PlayListId, + TrackId = request.TrackId, + Position = nextPosition + }, cancellationToken); + + await database.SaveChangesAsync(cancellationToken); + + logger.LogInformation("Added track {TrackId} to playlist {PlayListId} at position {Position}", + request.TrackId, request.PlayListId, nextPosition); + + return Result.Success(); + } + } +} diff --git a/Application/PlayLists/Handlers/RemoveTrackFromPlayListCommandHandler.cs b/Application/PlayLists/Handlers/RemoveTrackFromPlayListCommandHandler.cs new file mode 100644 index 0000000..609ede9 --- /dev/null +++ b/Application/PlayLists/Handlers/RemoveTrackFromPlayListCommandHandler.cs @@ -0,0 +1,47 @@ +using Ardalis.Result; +using Mediator; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Musify.Application.Contracts; +using Musify.Application.PlayLists.Commands; + +namespace Musify.Application.PlayLists.Handlers +{ + public class RemoveTrackFromPlayListCommandHandler( + IDatabase database, + ILogger logger) + : ICommandHandler + { + public async ValueTask Handle(RemoveTrackFromPlayListCommand request, CancellationToken cancellationToken) + { + var playList = await database.PlayLists + .SingleOrDefaultAsync(pl => pl.Id == request.PlayListId, cancellationToken); + if (playList is null) + { + logger.LogInformation("Playlist {PlayListId} not found", request.PlayListId); + return Result.NotFound(); + } + + if (playList.UserId != request.UserId) + { + logger.LogWarning("User {UserId} is not the owner of playlist {PlayListId}", request.UserId, request.PlayListId); + return Result.Unauthorized(); + } + + var link = await database.PlayListHasTracks + .SingleOrDefaultAsync(plt => plt.PlayListId == request.PlayListId && plt.TrackId == request.TrackId, cancellationToken); + if (link is null) + { + logger.LogInformation("Track {TrackId} not in playlist {PlayListId}", request.TrackId, request.PlayListId); + return Result.NotFound("Track is not in the playlist."); + } + + database.PlayListHasTracks.Remove(link); + await database.SaveChangesAsync(cancellationToken); + + logger.LogInformation("Removed track {TrackId} from playlist {PlayListId}", request.TrackId, request.PlayListId); + + return Result.Success(); + } + } +}