From fcf3093ad81801aae30cc2df5d7cee67a5dc0d2a Mon Sep 17 00:00:00 2001 From: XShine555 Date: Thu, 24 Sep 2026 12:36:48 +0200 Subject: [PATCH] Unify API route parameters, return IResult everywhere, merge picture upload DTOs and centralize validation limits Guid and long route constraints, id/trackId parameter names, Update*Request without the New prefix, sentence-case operation summaries, shared security scheme id and a single Limits class. --- .../Authentication/JwtBearerOptionsSetup.cs | 14 +- .../RequestAlbumPictureUploadRequest.cs | 6 - .../Albums/UpdateAlbumRequest.cs | 8 +- .../PictureUploadRequest.cs | 6 + .../RequestPlayListPictureUploadRequest.cs | 6 - .../PlayLists/UpdatePlayListRequest.cs | 8 +- .../Musify.Api/Endpoints/AlbumEndpoints.cs | 62 +- .../Musify.Api/Endpoints/ConfigEndpoints.cs | 7 +- .../Musify.Api/Endpoints/GenreEndpoints.cs | 14 +- .../Musify.Api/Endpoints/LikeEndpoints.cs | 8 +- .../Musify.Api/Endpoints/MixEndpoints.cs | 6 +- .../Musify.Api/Endpoints/PlayListEndpoints.cs | 58 +- .../Musify.Api/Endpoints/TrackEndpoints.cs | 36 +- .../Musify.Api/Endpoints/UserEndpoints.cs | 59 +- .../Musify.Api/OpenApi/OpenApiOptionsSetup.cs | 24 +- backend/Hosts/Musify.Api/Program.cs | 11 +- .../Musify.Api/Scalar/ScalarOptionsSetup.cs | 23 +- .../Validators/Albums/AlbumReleaseYear.cs | 8 - .../Albums/CreateAlbumRequestValidator.cs | 6 +- .../Albums/UpdateAlbumRequestValidator.cs | 14 +- backend/Hosts/Musify.Api/Validators/Limits.cs | 12 + ...or.cs => PictureUploadRequestValidator.cs} | 8 +- .../CreatePlayListRequestValidator.cs | 4 +- ...stPlayListPictureUploadRequestValidator.cs | 20 - .../UpdatePlayListRequestValidator.cs | 16 +- .../Tracks/CreateTrackRequestValidator.cs | 2 +- .../Endpoints/AlbumEndpointsTests.cs | 3 +- .../CreateAlbumRequestValidatorTests.cs | 9 +- .../Validators/UploadRequestValidatorTests.cs | 12 +- web-player/src/lib/api/schema.d.ts | 1028 ++++++++--------- web-player/src/lib/server/playlistActions.ts | 4 +- .../routes/(app)/albums/[id]/+page.server.ts | 24 +- .../src/routes/(app)/library/+page.server.ts | 4 +- .../routes/(app)/playlists/+page.server.ts | 4 +- .../(app)/playlists/[id]/+page.server.ts | 23 +- .../routes/(app)/user/[id]/+page.server.ts | 4 +- web-player/src/routes/+page.server.ts | 4 +- .../routes/api/albums/[id]/tracks/+server.ts | 4 +- 38 files changed, 740 insertions(+), 829 deletions(-) delete mode 100644 backend/Hosts/Musify.Api/DataTransferObjects/Albums/RequestAlbumPictureUploadRequest.cs create mode 100644 backend/Hosts/Musify.Api/DataTransferObjects/PictureUploadRequest.cs delete mode 100644 backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs delete mode 100644 backend/Hosts/Musify.Api/Validators/Albums/AlbumReleaseYear.cs create mode 100644 backend/Hosts/Musify.Api/Validators/Limits.cs rename backend/Hosts/Musify.Api/Validators/{Albums/RequestAlbumPictureUploadRequestValidator.cs => PictureUploadRequestValidator.cs} (55%) delete mode 100644 backend/Hosts/Musify.Api/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs diff --git a/backend/Hosts/Musify.Api/Authentication/JwtBearerOptionsSetup.cs b/backend/Hosts/Musify.Api/Authentication/JwtBearerOptionsSetup.cs index db86913..880fd13 100644 --- a/backend/Hosts/Musify.Api/Authentication/JwtBearerOptionsSetup.cs +++ b/backend/Hosts/Musify.Api/Authentication/JwtBearerOptionsSetup.cs @@ -8,27 +8,25 @@ namespace Musify.Api.Authentication; public sealed class JwtBearerOptionsSetup(IOptions options) : IConfigureNamedOptions { - private readonly AuthenticationConfiguration _configuration = options.Value; + private readonly AuthenticationConfiguration configuration = options.Value; public void Configure(string? name, JwtBearerOptions options) { if (name != JwtBearerDefaults.AuthenticationScheme) - { return; - } Configure(options); } public void Configure(JwtBearerOptions options) { - options.MetadataAddress = _configuration.MetadataAddress; - options.RequireHttpsMetadata = _configuration.RequireHttpsMetadata; - options.Audience = _configuration.AudienceAddress; + options.MetadataAddress = configuration.MetadataAddress; + options.RequireHttpsMetadata = configuration.RequireHttpsMetadata; + options.Audience = configuration.AudienceAddress; options.TokenValidationParameters = new TokenValidationParameters { - ValidIssuer = _configuration.IssuerAddress, - ValidAudience = _configuration.AudienceAddress, + ValidIssuer = configuration.IssuerAddress, + ValidAudience = configuration.AudienceAddress, RoleClaimType = ClaimTypes.Role, NameClaimType = ClaimTypes.Name, }; diff --git a/backend/Hosts/Musify.Api/DataTransferObjects/Albums/RequestAlbumPictureUploadRequest.cs b/backend/Hosts/Musify.Api/DataTransferObjects/Albums/RequestAlbumPictureUploadRequest.cs deleted file mode 100644 index a1fb913..0000000 --- a/backend/Hosts/Musify.Api/DataTransferObjects/Albums/RequestAlbumPictureUploadRequest.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Musify.Api.DataTransferObjects.Albums; - -public record RequestAlbumPictureUploadRequest( - string FileType, - string ContentType, - long? ExpectedSizeBytes = null); diff --git a/backend/Hosts/Musify.Api/DataTransferObjects/Albums/UpdateAlbumRequest.cs b/backend/Hosts/Musify.Api/DataTransferObjects/Albums/UpdateAlbumRequest.cs index d01812e..a814831 100644 --- a/backend/Hosts/Musify.Api/DataTransferObjects/Albums/UpdateAlbumRequest.cs +++ b/backend/Hosts/Musify.Api/DataTransferObjects/Albums/UpdateAlbumRequest.cs @@ -1,7 +1,7 @@ namespace Musify.Api.DataTransferObjects.Albums; public record UpdateAlbumRequest( - string NewTitle, - string? NewDescription, - int? NewReleaseYear, - Guid? NewPictureIntentId); + string Title, + string? Description, + int? ReleaseYear, + Guid? PictureIntentId); diff --git a/backend/Hosts/Musify.Api/DataTransferObjects/PictureUploadRequest.cs b/backend/Hosts/Musify.Api/DataTransferObjects/PictureUploadRequest.cs new file mode 100644 index 0000000..c41becc --- /dev/null +++ b/backend/Hosts/Musify.Api/DataTransferObjects/PictureUploadRequest.cs @@ -0,0 +1,6 @@ +namespace Musify.Api.DataTransferObjects; + +public record PictureUploadRequest( + string FileType, + string ContentType, + long? ExpectedSizeBytes = null); diff --git a/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs b/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs deleted file mode 100644 index a72e25c..0000000 --- a/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/RequestPlayListPictureUploadRequest.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Musify.Api.DataTransferObjects.PlayLists; - -public record RequestPlayListPictureUploadRequest( - string FileType, - string ContentType, - long? ExpectedSizeBytes = null); diff --git a/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs b/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs index ddf8b87..78a4d11 100644 --- a/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs +++ b/backend/Hosts/Musify.Api/DataTransferObjects/PlayLists/UpdatePlayListRequest.cs @@ -3,7 +3,7 @@ using Musify.Domain.ValueObjects; namespace Musify.Api.DataTransferObjects.PlayLists; public record UpdatePlayListRequest( - string? NewName, - string? NewDescription, - Guid? NewPictureIntentId, - PlayListVisibility? NewVisibility = null); + string? Name, + string? Description, + Guid? PictureIntentId, + PlayListVisibility? Visibility = null); diff --git a/backend/Hosts/Musify.Api/Endpoints/AlbumEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/AlbumEndpoints.cs index 481e0d4..1e56399 100644 --- a/backend/Hosts/Musify.Api/Endpoints/AlbumEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/AlbumEndpoints.cs @@ -4,12 +4,12 @@ using Musify.Api.DataTransferObjects; using Musify.Api.DataTransferObjects.Albums; using Musify.Api.Extensions; using Musify.Api.Filters; +using Musify.Api.Models; using Musify.Application.Albums; using Musify.Application.Albums.Responses; using Musify.Application.Contracts; using Musify.Application.Pictures; using Musify.Application.Pictures.Responses; -using Musify.Api.Models; using Musify.Application.Shared; using Musify.Application.Tracks.Responses; @@ -27,46 +27,46 @@ public static class AlbumEndpoints group.MapGet("/", GetAlbums) .AddEndpointFilter>() .WithName("GetAlbums") - .WithSummary("Get Paginated Albums, Optionally Filtered By Title.") + .WithSummary("Get paginated albums, optionally filtered by title") .Produces>(); - group.MapGet("/{id}", GetAlbumById) + group.MapGet("/{id:guid}", GetAlbumById) .WithName("GetAlbumById") - .WithSummary("Get An Album By Id.") + .WithSummary("Get an album by id") .Produces() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/users/{userId}", GetAlbumsByUserId) + group.MapGet("/users/{userId:long}", GetAlbumsByUserId) .AddEndpointFilter>() .WithName("GetAlbumsByUserId") - .WithSummary("Get Paginated Albums For A User.") + .WithSummary("Get paginated albums for a user") .Produces>() .Produces(StatusCodes.Status404NotFound); group.MapGet("/recent", GetRecentlyListenedAlbums) .WithName("GetRecentlyListenedAlbums") - .WithSummary("Get The Albums The Current User Listened To Most Recently.") + .WithSummary("Get the albums the current user listened to most recently") .RequireAuthorization() .Produces>() .Produces(StatusCodes.Status401Unauthorized); - group.MapGet("/{albumId}/tracks", GetAlbumTracks) + group.MapGet("/{id:guid}/tracks", GetAlbumTracks) .AddEndpointFilter>() .WithName("GetAlbumTracks") - .WithSummary("Get The Tracks Of An Album Ordered By Track Number.") + .WithSummary("Get the tracks of an album ordered by track number") .Produces>() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/cover", GetAlbumCover) + group.MapGet("/{id:guid}/cover", GetAlbumCover) .WithName("GetAlbumCover") - .WithSummary("Get An Album Cover Image.") + .WithSummary("Get an album cover image") .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound); group.MapPost("/upload-picture", RequestAlbumPictureUpload) .WithName("RequestAlbumPictureUpload") - .WithSummary("Request A Pre-Signed URL To Upload An Album Picture.") - .AddEndpointFilter>() + .WithSummary("Request a pre-signed URL to upload an album picture") + .AddEndpointFilter>() .RequireAuthorization() .Produces() .ProducesValidationProblem() @@ -75,7 +75,7 @@ public static class AlbumEndpoints group.MapPost("/", CreateAlbum) .WithName("CreateAlbum") - .WithSummary("Create A New Album.") + .WithSummary("Create a new album") .AddEndpointFilter>() .RequireAuthorization() .Produces(StatusCodes.Status201Created) @@ -83,9 +83,9 @@ public static class AlbumEndpoints .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); - group.MapPut("/{albumId}", UpdateAlbum) + group.MapPut("/{id:guid}", UpdateAlbum) .WithName("UpdateAlbum") - .WithSummary("Update An Album.") + .WithSummary("Update an album") .AddEndpointFilter>() .RequireAuthorization() .Produces() @@ -94,18 +94,18 @@ public static class AlbumEndpoints .Produces(StatusCodes.Status403Forbidden) .Produces(StatusCodes.Status404NotFound); - group.MapDelete("/{albumId}", DeleteAlbum) + group.MapDelete("/{id:guid}", DeleteAlbum) .WithName("DeleteAlbum") - .WithSummary("Delete An Album.") + .WithSummary("Delete an album") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status403Forbidden) .Produces(StatusCodes.Status404NotFound); - group.MapPost("/{id}/tracks", AddAlbumTracks) + group.MapPost("/{id:guid}/tracks", AddAlbumTracks) .WithName("AddAlbumTracks") - .WithSummary("Add Your Uploaded Tracks To An Album, Skipping The Ones It Already Has.") + .WithSummary("Add your uploaded tracks to an album, skipping the ones it already has") .AddEndpointFilter>() .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) @@ -115,9 +115,9 @@ public static class AlbumEndpoints .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status409Conflict); - group.MapDelete("/{albumId}/tracks/{trackId}", RemoveTrackFromAlbum) + group.MapDelete("/{id:guid}/tracks/{trackId:guid}", RemoveTrackFromAlbum) .WithName("RemoveTrackFromAlbum") - .WithSummary("Remove A Track From An Album.") + .WithSummary("Remove a track from an album") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) @@ -176,11 +176,11 @@ public static class AlbumEndpoints private static async Task GetAlbumTracks( IMediator mediator, - Guid albumId, + Guid id, CancellationToken cancellationToken, [AsParameters] PageQuery page) { - var result = await mediator.Send(new GetAlbumTracksQuery(albumId, page.PageNumber, page.PageSize), cancellationToken); + var result = await mediator.Send(new GetAlbumTracksQuery(id, page.PageNumber, page.PageSize), cancellationToken); return result.ToHttpResult(); } @@ -198,7 +198,7 @@ public static class AlbumEndpoints private static async Task RequestAlbumPictureUpload( IMediator mediator, CurrentUser currentUser, - RequestAlbumPictureUploadRequest request, + PictureUploadRequest request, CancellationToken cancellationToken) { var result = await mediator.Send( @@ -224,12 +224,12 @@ public static class AlbumEndpoints private static async Task UpdateAlbum( IMediator mediator, CurrentUser currentUser, - Guid albumId, + Guid id, UpdateAlbumRequest request, CancellationToken cancellationToken) { var result = await mediator.Send( - new UpdateAlbumCommand(currentUser.RequiredId, albumId, request.NewTitle, request.NewDescription, request.NewReleaseYear, request.NewPictureIntentId), + new UpdateAlbumCommand(currentUser.RequiredId, id, request.Title, request.Description, request.ReleaseYear, request.PictureIntentId), cancellationToken); return result.ToHttpResult(); @@ -238,10 +238,10 @@ public static class AlbumEndpoints private static async Task DeleteAlbum( IMediator mediator, CurrentUser currentUser, - Guid albumId, + Guid id, CancellationToken cancellationToken) { - var result = await mediator.Send(new DeleteAlbumCommand(currentUser.RequiredId, albumId), cancellationToken); + var result = await mediator.Send(new DeleteAlbumCommand(currentUser.RequiredId, id), cancellationToken); return result.ToHttpResult(); } @@ -262,12 +262,12 @@ public static class AlbumEndpoints private static async Task RemoveTrackFromAlbum( IMediator mediator, CurrentUser currentUser, - Guid albumId, + Guid id, Guid trackId, CancellationToken cancellationToken) { var result = await mediator.Send( - new RemoveTrackFromAlbumCommand(currentUser.RequiredId, albumId, trackId), + new RemoveTrackFromAlbumCommand(currentUser.RequiredId, id, trackId), cancellationToken); return result.ToHttpResult(); diff --git a/backend/Hosts/Musify.Api/Endpoints/ConfigEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/ConfigEndpoints.cs index ed4220a..517e79c 100644 --- a/backend/Hosts/Musify.Api/Endpoints/ConfigEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/ConfigEndpoints.cs @@ -13,16 +13,17 @@ public static class ConfigEndpoints group.MapGet("/playback", GetPlaybackPublicConfig) .WithName("GetPlaybackPublicConfig") - .WithSummary("Get The Public Playback Configuration (Whether Anonymous Listening Is Allowed). Works Anonymously.") + .WithSummary("Get the public playback configuration (whether anonymous listening is allowed). Works anonymously") .Produces(); return app; } - private static async Task GetPlaybackPublicConfig( + private static async Task GetPlaybackPublicConfig( IMediator mediator, CancellationToken cancellationToken) { - return await mediator.Send(new GetPlaybackPublicConfigQuery(), cancellationToken); + var result = await mediator.Send(new GetPlaybackPublicConfigQuery(), cancellationToken); + return Results.Ok(result); } } diff --git a/backend/Hosts/Musify.Api/Endpoints/GenreEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/GenreEndpoints.cs index 382655b..d779c88 100644 --- a/backend/Hosts/Musify.Api/Endpoints/GenreEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/GenreEndpoints.cs @@ -13,28 +13,30 @@ public static class GenreEndpoints group.MapGet("/", GetGenres) .WithName("GetGenres") - .WithSummary("Get The Genres That Have At Least One Track, Most Populated First. Works Anonymously.") + .WithSummary("Get the genres that have at least one track, most populated first. Works anonymously") .Produces>(); group.MapGet("/available", GetAvailableGenres) .WithName("GetAvailableGenres") - .WithSummary("Get Every Genre A Track Can Be Tagged With, Including The Genres It Cannot Be Combined With. Works Anonymously.") + .WithSummary("Get every genre a track can be tagged with, including the genres it cannot be combined with. Works anonymously") .Produces>(); return app; } - private static async Task> GetAvailableGenres( + private static async Task GetAvailableGenres( IMediator mediator, CancellationToken cancellationToken) { - return await mediator.Send(new GetAvailableGenresQuery(), cancellationToken); + var result = await mediator.Send(new GetAvailableGenresQuery(), cancellationToken); + return Results.Ok(result); } - private static async Task> GetGenres( + private static async Task GetGenres( IMediator mediator, CancellationToken cancellationToken) { - return await mediator.Send(new GetGenresQuery(), cancellationToken); + var result = await mediator.Send(new GetGenresQuery(), cancellationToken); + return Results.Ok(result); } } diff --git a/backend/Hosts/Musify.Api/Endpoints/LikeEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/LikeEndpoints.cs index 22f747e..6d1ec73 100644 --- a/backend/Hosts/Musify.Api/Endpoints/LikeEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/LikeEndpoints.cs @@ -2,11 +2,11 @@ using Mediator; using Musify.Api.Authentication; using Musify.Api.DataTransferObjects.Likes; using Musify.Api.Extensions; -using Musify.Application.Likes; +using Musify.Api.Filters; using Musify.Api.Models; +using Musify.Application.Likes; using Musify.Application.Shared; using Musify.Application.Tracks.Responses; -using Musify.Api.Filters; namespace Musify.Api.Endpoints; @@ -21,13 +21,13 @@ public static class LikeEndpoints group.MapGet("/", GetLikedTracks) .AddEndpointFilter>() .WithName("GetLikedTracks") - .WithSummary("Get The Current User'S Liked Tracks.") + .WithSummary("Get the current user's liked tracks") .Produces>() .Produces(StatusCodes.Status401Unauthorized); group.MapPost("/toggle", ToggleTrackLike) .WithName("ToggleTrackLike") - .WithSummary("Like Or Unlike A Track By Id.") + .WithSummary("Like or unlike a track by id") .Produces() .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); diff --git a/backend/Hosts/Musify.Api/Endpoints/MixEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/MixEndpoints.cs index 371cbde..b0b0736 100644 --- a/backend/Hosts/Musify.Api/Endpoints/MixEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/MixEndpoints.cs @@ -16,13 +16,13 @@ public static class MixEndpoints group.MapGet("/", GetMixes) .WithName("GetMixes") - .WithSummary("Get The Server-Generated Mixes Of The Current User.") + .WithSummary("Get the server-generated mixes of the current user") .Produces>() .Produces(StatusCodes.Status401Unauthorized); - group.MapGet("/{id}", GetMixById) + group.MapGet("/{id:guid}", GetMixById) .WithName("GetMixById") - .WithSummary("Get A Mix With All Of Its Songs.") + .WithSummary("Get a mix with all of its songs") .Produces() .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); diff --git a/backend/Hosts/Musify.Api/Endpoints/PlayListEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/PlayListEndpoints.cs index c25e71d..74d51ac 100644 --- a/backend/Hosts/Musify.Api/Endpoints/PlayListEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/PlayListEndpoints.cs @@ -4,12 +4,12 @@ using Musify.Api.DataTransferObjects; using Musify.Api.DataTransferObjects.PlayLists; using Musify.Api.Extensions; using Musify.Api.Filters; +using Musify.Api.Models; using Musify.Application.Contracts; using Musify.Application.Pictures; using Musify.Application.Pictures.Responses; using Musify.Application.PlayLists; using Musify.Application.PlayLists.Responses; -using Musify.Api.Models; using Musify.Application.Shared; using Musify.Application.Tracks.Responses; @@ -22,34 +22,34 @@ public static class PlayListEndpoints var group = app.MapGroup("/playlists") .WithTags("PlayLists"); - group.MapGet("/{id}", GetPlayListById) + group.MapGet("/{id:guid}", GetPlayListById) .WithName("GetPlayListById") - .WithSummary("Get A PlayList By Id.") + .WithSummary("Get a playlist by id") .Produces() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/users/{userId}", GetPlayListsByUserId) + group.MapGet("/users/{userId:long}", GetPlayListsByUserId) .AddEndpointFilter>() .WithName("GetPlayListsByUserId") - .WithSummary("Get Paginated PlayLists For A User. Private PlayLists Are Only Returned To Their Owner.") + .WithSummary("Get paginated playlists for a user. Private playlists are only returned to their owner") .Produces>(); - group.MapGet("/{playlistId}/tracks", GetPlayListTracks) + group.MapGet("/{id:guid}/tracks", GetPlayListTracks) .AddEndpointFilter>() .WithName("GetPlayListTracks") - .WithSummary("Get Paginated Tracks Of A PlayList.") + .WithSummary("Get paginated tracks of a playlist") .Produces>() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/cover", GetPlayListCover) + group.MapGet("/{id:guid}/cover", GetPlayListCover) .WithName("GetPlayListCover") - .WithSummary("Get A PlayList Cover Image.") + .WithSummary("Get a playlist cover image") .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound); group.MapPost("/", CreatePlayList) .WithName("CreatePlayList") - .WithSummary("Create A New PlayList.") + .WithSummary("Create a new playlist") .AddEndpointFilter>() .RequireAuthorization() .Produces(StatusCodes.Status201Created) @@ -57,9 +57,9 @@ public static class PlayListEndpoints .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); - group.MapPut("/{playlistId}", UpdatePlayList) + group.MapPut("/{id:guid}", UpdatePlayList) .WithName("UpdatePlayList") - .WithSummary("Update An Existing PlayList.") + .WithSummary("Update an existing playlist") .AddEndpointFilter>() .RequireAuthorization() .Produces() @@ -68,9 +68,9 @@ public static class PlayListEndpoints .Produces(StatusCodes.Status403Forbidden) .Produces(StatusCodes.Status404NotFound); - group.MapDelete("/{playlistId}", DeletePlayList) + group.MapDelete("/{id:guid}", DeletePlayList) .WithName("DeletePlayList") - .WithSummary("Delete A PlayList.") + .WithSummary("Delete a playlist") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) @@ -79,17 +79,17 @@ public static class PlayListEndpoints group.MapPost("/upload-picture", RequestPlayListPictureUpload) .WithName("RequestPlayListPictureUpload") - .WithSummary("Request A Pre-Signed URL To Upload A PlayList Picture.") - .AddEndpointFilter>() + .WithSummary("Request a pre-signed URL to upload a playlist picture") + .AddEndpointFilter>() .RequireAuthorization() .Produces() .ProducesValidationProblem() .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); - group.MapPost("/{id}/tracks", AddPlayListTracks) + group.MapPost("/{id:guid}/tracks", AddPlayListTracks) .WithName("AddPlayListTracks") - .WithSummary("Add Tracks To A PlayList, Skipping The Ones It Already Has.") + .WithSummary("Add tracks to a playlist, skipping the ones it already has") .AddEndpointFilter>() .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) @@ -99,9 +99,9 @@ public static class PlayListEndpoints .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status409Conflict); - group.MapDelete("/{playlistId}/tracks/{trackId}", RemoveTrackFromPlayList) + group.MapDelete("/{id:guid}/tracks/{trackId:guid}", RemoveTrackFromPlayList) .WithName("RemoveTrackFromPlayList") - .WithSummary("Remove A Track From A PlayList.") + .WithSummary("Remove a track from a playlist") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) @@ -136,11 +136,11 @@ public static class PlayListEndpoints private static async Task GetPlayListTracks( IMediator mediator, CurrentUser currentUser, - Guid playlistId, + Guid id, CancellationToken cancellationToken, [AsParameters] PageQuery page) { - var result = await mediator.Send(new GetPlayListTracksQuery(playlistId, page.PageNumber, page.PageSize, currentUser.Id), cancellationToken); + var result = await mediator.Send(new GetPlayListTracksQuery(id, page.PageNumber, page.PageSize, currentUser.Id), cancellationToken); return result.ToHttpResult(); } @@ -171,12 +171,12 @@ public static class PlayListEndpoints private static async Task UpdatePlayList( IMediator mediator, CurrentUser currentUser, - Guid playlistId, + Guid id, UpdatePlayListRequest request, CancellationToken cancellationToken) { var result = await mediator.Send( - new UpdatePlayListCommand(currentUser.RequiredId, playlistId, request.NewName, request.NewDescription, request.NewPictureIntentId, request.NewVisibility), + new UpdatePlayListCommand(currentUser.RequiredId, id, request.Name, request.Description, request.PictureIntentId, request.Visibility), cancellationToken); return result.ToHttpResult(); @@ -185,17 +185,17 @@ public static class PlayListEndpoints private static async Task DeletePlayList( IMediator mediator, CurrentUser currentUser, - Guid playlistId, + Guid id, CancellationToken cancellationToken) { - var result = await mediator.Send(new DeletePlayListCommand(currentUser.RequiredId, playlistId), cancellationToken); + var result = await mediator.Send(new DeletePlayListCommand(currentUser.RequiredId, id), cancellationToken); return result.ToHttpResult(); } private static async Task RequestPlayListPictureUpload( IMediator mediator, CurrentUser currentUser, - RequestPlayListPictureUploadRequest request, + PictureUploadRequest request, CancellationToken cancellationToken) { var result = await mediator.Send( @@ -222,12 +222,12 @@ public static class PlayListEndpoints private static async Task RemoveTrackFromPlayList( IMediator mediator, CurrentUser currentUser, - Guid playlistId, + Guid id, Guid trackId, CancellationToken cancellationToken) { var result = await mediator.Send( - new RemoveTrackFromPlayListCommand(currentUser.RequiredId, playlistId, trackId), + new RemoveTrackFromPlayListCommand(currentUser.RequiredId, id, trackId), cancellationToken); return result.ToHttpResult(); diff --git a/backend/Hosts/Musify.Api/Endpoints/TrackEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/TrackEndpoints.cs index 1a1fd88..3db1c4e 100644 --- a/backend/Hosts/Musify.Api/Endpoints/TrackEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/TrackEndpoints.cs @@ -3,9 +3,9 @@ using Musify.Api.Authentication; using Musify.Api.DataTransferObjects.Tracks; using Musify.Api.Extensions; using Musify.Api.Filters; +using Musify.Api.Models; using Musify.Application.Contracts; using Musify.Application.Pictures; -using Musify.Api.Models; using Musify.Application.Shared; using Musify.Application.Tracks; using Musify.Application.Tracks.Responses; @@ -22,47 +22,47 @@ public static class TrackEndpoints group.MapGet("/", GetTracks) .AddEndpointFilter>() .WithName("GetTracks") - .WithSummary("Get Paginated Tracks, Optionally Filtered By Name And Genre.") + .WithSummary("Get paginated tracks, optionally filtered by name and genre") .Produces>() .ProducesValidationProblem(); - group.MapGet("/{id}", GetTrackById) + group.MapGet("/{id:guid}", GetTrackById) .WithName("GetTrackById") - .WithSummary("Get A Track By Id.") + .WithSummary("Get a track by id") .Produces() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/cover", GetTrackCover) + group.MapGet("/{id:guid}/cover", GetTrackCover) .WithName("GetTrackCover") - .WithSummary("Get A Track Cover Image.") + .WithSummary("Get a track cover image") .Produces(StatusCodes.Status200OK) .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/stream", GetTrackStream) + group.MapGet("/{id:guid}/stream", GetTrackStream) .WithName("GetTrackStream") - .WithSummary("Get A Streaming Manifest URL And Ticket For A Track. Works Anonymously When The Playback Configuration Allows It.") + .WithSummary("Get a streaming manifest URL and ticket for a track. Works anonymously when the playback configuration allows it") .Produces() .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); - group.MapPut("/listens/{listenId}/progress", RecordListeningProgress) + group.MapPut("/listens/{listenId:guid}/progress", RecordListeningProgress) .AddEndpointFilter>() .WithName("RecordListeningProgress") - .WithSummary("Report The Total Seconds Actually Played For A Listen Started By The Stream Endpoint.") + .WithSummary("Report the total seconds actually played for a listen started by the stream endpoint") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound); - group.MapGet("/users/{userId}", GetTracksByUserId) + group.MapGet("/users/{userId:long}", GetTracksByUserId) .AddEndpointFilter>() .WithName("GetTracksByUserId") - .WithSummary("Get Paginated Tracks For A User.") + .WithSummary("Get paginated tracks for a user") .Produces>(); group.MapPost("/", CreateTrack) .WithName("CreateTrack") - .WithSummary("Create A New Track.") + .WithSummary("Create a new track") .AddEndpointFilter>() .RequireAuthorization() .Produces(StatusCodes.Status201Created) @@ -71,9 +71,9 @@ public static class TrackEndpoints .Produces(StatusCodes.Status404NotFound) .Produces(StatusCodes.Status409Conflict); - group.MapDelete("/{trackId}", DeleteTrack) + group.MapDelete("/{id:guid}", DeleteTrack) .WithName("DeleteTrack") - .WithSummary("Delete A Track.") + .WithSummary("Delete a track") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) @@ -83,7 +83,7 @@ public static class TrackEndpoints group.MapPost("/upload-urls", RequestTrackUploadUrls) .WithName("RequestTrackUploadUrls") - .WithSummary("Request Pre-Signed URLs To Upload Track Picture And Audio.") + .WithSummary("Request pre-signed URLs to upload track picture and audio") .AddEndpointFilter>() .RequireAuthorization() .Produces() @@ -176,10 +176,10 @@ public static class TrackEndpoints private static async Task DeleteTrack( IMediator mediator, CurrentUser currentUser, - Guid trackId, + Guid id, CancellationToken cancellationToken) { - var result = await mediator.Send(new DeleteTrackCommand(currentUser.RequiredId, trackId), cancellationToken); + var result = await mediator.Send(new DeleteTrackCommand(currentUser.RequiredId, id), cancellationToken); return result.ToHttpResult(); } diff --git a/backend/Hosts/Musify.Api/Endpoints/UserEndpoints.cs b/backend/Hosts/Musify.Api/Endpoints/UserEndpoints.cs index 5744d64..5eaac41 100644 --- a/backend/Hosts/Musify.Api/Endpoints/UserEndpoints.cs +++ b/backend/Hosts/Musify.Api/Endpoints/UserEndpoints.cs @@ -1,13 +1,13 @@ using Mediator; using Musify.Api.Authentication; using Musify.Api.Extensions; +using Musify.Api.Filters; using Musify.Api.Models; using Musify.Application.Shared; using Musify.Application.Tracks; using Musify.Application.Tracks.Responses; using Musify.Application.Users; using Musify.Application.Users.Responses; -using Musify.Api.Filters; namespace Musify.Api.Endpoints; @@ -21,75 +21,75 @@ public static class UserEndpoints group.MapGet("/", GetUsers) .AddEndpointFilter>() .WithName("GetUsers") - .WithSummary("Get Paginated Users.") + .WithSummary("Get paginated users") .Produces>(); - group.MapGet("/{id}", GetUserById) + group.MapGet("/{id:long}", GetUserById) .WithName("GetUserById") - .WithSummary("Get A User By Id.") + .WithSummary("Get a user by id") .Produces() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/listening-history", GetListeningHistory) + group.MapGet("/{id:long}/listening-history", GetListeningHistory) .WithName("GetListeningHistory") - .WithSummary("Get A User'S Listening History.") + .WithSummary("Get a user's listening history") .Produces>() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/listening-stats", GetListeningStats) + group.MapGet("/{id:long}/listening-stats", GetListeningStats) .WithName("GetListeningStats") - .WithSummary("Get A User'S Listening Stats For The Current Week And Streak.") + .WithSummary("Get a user's listening stats for the current week and streak") .RequireAuthorization() .Produces() .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status403Forbidden); - group.MapGet("/{id}/last-listened-track", GetLastTrackListenedByUserId) + group.MapGet("/{id:long}/last-listened-track", GetLastTrackListenedByUserId) .WithName("GetLastTrackListenedByUserId") - .WithSummary("Get The Last Track A User Listened To.") + .WithSummary("Get the last track a user listened to") .Produces() .Produces(StatusCodes.Status204NoContent); - group.MapGet("/{id}/profile", GetUserProfile) + group.MapGet("/{id:long}/profile", GetUserProfile) .WithName("GetUserProfile") - .WithSummary("Get A User'S Public Profile, Including Follower Counts.") + .WithSummary("Get a user's public profile, including follower counts") .Produces() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/followers", GetFollowers) + group.MapGet("/{id:long}/followers", GetFollowers) .AddEndpointFilter>() .WithName("GetUserFollowers") - .WithSummary("Get The Users Following A User. Visible To The User And To Mutual Followers.") + .WithSummary("Get the users following a user. Visible to the user and to mutual followers") .Produces>() .Produces(StatusCodes.Status403Forbidden) .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/following", GetFollowing) + group.MapGet("/{id:long}/following", GetFollowing) .AddEndpointFilter>() .WithName("GetUserFollowing") - .WithSummary("Get The Users A User Follows.") + .WithSummary("Get the users a user follows") .Produces>() .Produces(StatusCodes.Status404NotFound); - group.MapGet("/{id}/is-following", IsFollowing) + group.MapGet("/{id:long}/is-following", IsFollowing) .WithName("IsFollowingUser") - .WithSummary("Check Whether The Current User Follows Another User.") + .WithSummary("Check whether the current user follows another user") .RequireAuthorization() .Produces() .Produces(StatusCodes.Status401Unauthorized); - group.MapPost("/{id}/follow", FollowUser) + group.MapPost("/{id:long}/follow", FollowUser) .WithName("FollowUser") - .WithSummary("Follow A User.") + .WithSummary("Follow a user") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound) .ProducesValidationProblem(); - group.MapDelete("/{id}/follow", UnfollowUser) + group.MapDelete("/{id:long}/follow", UnfollowUser) .WithName("UnfollowUser") - .WithSummary("Unfollow A User.") + .WithSummary("Unfollow a user") .RequireAuthorization() .Produces(StatusCodes.Status204NoContent) .Produces(StatusCodes.Status401Unauthorized); @@ -117,12 +117,13 @@ public static class UserEndpoints return result.ToHttpResult(); } - private static async Task> GetListeningHistory( + private static async Task GetListeningHistory( IMediator mediator, long id, CancellationToken cancellationToken) { - return await mediator.Send(new GetListeningHistoryQuery(id), cancellationToken); + var result = await mediator.Send(new GetListeningHistoryQuery(id), cancellationToken); + return Results.Ok(result); } private static async Task GetListeningStats( @@ -132,9 +133,10 @@ public static class UserEndpoints CancellationToken cancellationToken) { if (currentUser.RequiredId != id) - return Results.StatusCode(StatusCodes.Status403Forbidden); + return Results.Problem(statusCode: StatusCodes.Status403Forbidden); - return Results.Ok(await mediator.Send(new GetListeningStatsQuery(id), cancellationToken)); + var result = await mediator.Send(new GetListeningStatsQuery(id), cancellationToken); + return Results.Ok(result); } private static async Task GetLastTrackListenedByUserId( @@ -178,13 +180,14 @@ public static class UserEndpoints return result.ToHttpResult(); } - private static async Task IsFollowing( + private static async Task IsFollowing( IMediator mediator, CurrentUser currentUser, long id, CancellationToken cancellationToken) { - return await mediator.Send(new IsFollowingUserQuery(currentUser.RequiredId, id), cancellationToken); + var result = await mediator.Send(new IsFollowingUserQuery(currentUser.RequiredId, id), cancellationToken); + return Results.Ok(result); } private static async Task FollowUser( diff --git a/backend/Hosts/Musify.Api/OpenApi/OpenApiOptionsSetup.cs b/backend/Hosts/Musify.Api/OpenApi/OpenApiOptionsSetup.cs index a7b1cbd..a1ae1ec 100644 --- a/backend/Hosts/Musify.Api/OpenApi/OpenApiOptionsSetup.cs +++ b/backend/Hosts/Musify.Api/OpenApi/OpenApiOptionsSetup.cs @@ -9,9 +9,9 @@ namespace Musify.Api.OpenApi; public sealed class OpenApiOptionsSetup(IOptions options) : IConfigureNamedOptions { - private const string SecuritySchemeId = "OAuth2"; + internal const string SecuritySchemeId = "OAuth2"; - private readonly AuthenticationConfiguration _configuration = options.Value; + private readonly AuthenticationConfiguration configuration = options.Value; public void Configure(string? name, OpenApiOptions options) => Configure(options); @@ -28,9 +28,9 @@ public sealed class OpenApiOptionsSetup(IOptions op { AuthorizationCode = new OpenApiOAuthFlow { - AuthorizationUrl = new Uri(_configuration.AuthorizationEndpoint), - TokenUrl = new Uri(_configuration.TokenEndpoint), - Scopes = _configuration.Scopes.ToDictionary(scope => scope, scope => scope), + AuthorizationUrl = new Uri(configuration.AuthorizationEndpoint), + TokenUrl = new Uri(configuration.TokenEndpoint), + Scopes = configuration.Scopes.ToDictionary(scope => scope, scope => scope), }, }, }; @@ -57,6 +57,16 @@ public sealed class OpenApiOptionsSetup(IOptions op options.AddOperationTransformer((operation, context, _) => { + // Route parameters constrained with :long are user ids, which travel as strings like every other long. + foreach (var parameter in operation.Parameters?.OfType() ?? []) + { + if (parameter.Schema is OpenApiSchema { Type: JsonSchemaType.Integer, Format: "int64" } schema) + { + schema.Type = JsonSchemaType.String; + schema.Format = null; + } + } + var requiresAuthorization = context.Description.ActionDescriptor.EndpointMetadata .OfType() .Any(); @@ -66,15 +76,13 @@ public sealed class OpenApiOptionsSetup(IOptions op .Any(); if (!requiresAuthorization || allowsAnonymous) - { return Task.CompletedTask; - } operation.Security ??= new List(); operation.Security.Add(new OpenApiSecurityRequirement { [new OpenApiSecuritySchemeReference(SecuritySchemeId, context.Document)] = - _configuration.Scopes.ToList(), + configuration.Scopes.ToList(), }); return Task.CompletedTask; diff --git a/backend/Hosts/Musify.Api/Program.cs b/backend/Hosts/Musify.Api/Program.cs index c1f1257..71b704f 100644 --- a/backend/Hosts/Musify.Api/Program.cs +++ b/backend/Hosts/Musify.Api/Program.cs @@ -5,7 +5,9 @@ using Musify.Api.Serialization; using Musify.Infrastructure.Observability; using Scalar.AspNetCore; -var builder = WebApplication.CreateBuilder(); +const string DevCorsPolicy = "dev-cors"; + +var builder = WebApplication.CreateBuilder(args); builder.Services.ConfigureHttpJsonOptions(options => { @@ -14,17 +16,16 @@ builder.Services.ConfigureHttpJsonOptions(options => options.SerializerOptions.Converters.Add(new NullableLongAsStringConverter()); }); -const string devCorsPolicy = "dev-cors"; - builder.Services .AddApplicationServices(builder.Configuration) .AddObservability(builder.Configuration); builder.Services.AddProblemDetails(); +builder.Services.Configure(options => options.ThrowOnBadRequest = false); if (builder.Environment.IsDevelopment()) { - builder.Services.AddCors(options => options.AddPolicy(devCorsPolicy, policy => + builder.Services.AddCors(options => options.AddPolicy(DevCorsPolicy, policy => policy.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod())); } @@ -34,7 +35,7 @@ app.UseExceptionHandler(); if (app.Environment.IsDevelopment()) { - app.UseCors(devCorsPolicy); + app.UseCors(DevCorsPolicy); app.MapOpenApi(); app.MapScalarApiReference(); } diff --git a/backend/Hosts/Musify.Api/Scalar/ScalarOptionsSetup.cs b/backend/Hosts/Musify.Api/Scalar/ScalarOptionsSetup.cs index de89db5..05e77b6 100644 --- a/backend/Hosts/Musify.Api/Scalar/ScalarOptionsSetup.cs +++ b/backend/Hosts/Musify.Api/Scalar/ScalarOptionsSetup.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Options; using Musify.Api.Authentication; +using Musify.Api.OpenApi; using Scalar.AspNetCore; namespace Musify.Api.Scalar; @@ -7,25 +8,23 @@ namespace Musify.Api.Scalar; public sealed class ScalarOptionsSetup(IOptions options) : IConfigureOptions { - private const string SecuritySchemeId = "OAuth2"; - - private readonly AuthenticationConfiguration _configuration = options.Value; + private readonly AuthenticationConfiguration configuration = options.Value; public void Configure(ScalarOptions scalarOptions) { scalarOptions .WithTitle("Musify API") - .AddPreferredSecuritySchemes(SecuritySchemeId) - .AddAuthorizationCodeFlow(SecuritySchemeId, flow => + .AddPreferredSecuritySchemes(OpenApiOptionsSetup.SecuritySchemeId) + .AddAuthorizationCodeFlow(OpenApiOptionsSetup.SecuritySchemeId, flow => { - flow.ClientId = _configuration.ClientId; - flow.ClientSecret = _configuration.ClientSecret; - flow.AuthorizationUrl = _configuration.AuthorizationEndpoint; - flow.TokenUrl = _configuration.TokenEndpoint; + flow.ClientId = configuration.ClientId; + flow.ClientSecret = configuration.ClientSecret; + flow.AuthorizationUrl = configuration.AuthorizationEndpoint; + flow.TokenUrl = configuration.TokenEndpoint; flow.Pkce = Pkce.Sha256; - flow.SelectedScopes = _configuration.Scopes; - flow.RedirectUri = _configuration.ScalarRedirectUri; - flow.RefreshUrl = _configuration.TokenEndpoint; + flow.SelectedScopes = configuration.Scopes; + flow.RedirectUri = configuration.ScalarRedirectUri; + flow.RefreshUrl = configuration.TokenEndpoint; }) .HideModels(); } diff --git a/backend/Hosts/Musify.Api/Validators/Albums/AlbumReleaseYear.cs b/backend/Hosts/Musify.Api/Validators/Albums/AlbumReleaseYear.cs deleted file mode 100644 index 222c8be..0000000 --- a/backend/Hosts/Musify.Api/Validators/Albums/AlbumReleaseYear.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Musify.Api.Validators.Albums; - -public static class AlbumReleaseYear -{ - public const int Earliest = 1877; - - public static int Latest => DateTime.UtcNow.Year + 1; -} diff --git a/backend/Hosts/Musify.Api/Validators/Albums/CreateAlbumRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/Albums/CreateAlbumRequestValidator.cs index 10550eb..0bb90b2 100644 --- a/backend/Hosts/Musify.Api/Validators/Albums/CreateAlbumRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/Albums/CreateAlbumRequestValidator.cs @@ -9,13 +9,13 @@ public sealed class CreateAlbumRequestValidator : AbstractValidator x.Title) .NotEmpty() - .MaximumLength(200); + .MaximumLength(Limits.AlbumTitle); RuleFor(x => x.Description) - .MaximumLength(256); + .MaximumLength(Limits.Description); RuleFor(x => x.ReleaseYear) - .InclusiveBetween(AlbumReleaseYear.Earliest, AlbumReleaseYear.Latest) + .InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear) .When(x => x.ReleaseYear.HasValue); RuleFor(x => x.PictureIntentId) diff --git a/backend/Hosts/Musify.Api/Validators/Albums/UpdateAlbumRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/Albums/UpdateAlbumRequestValidator.cs index 122a906..91620c6 100644 --- a/backend/Hosts/Musify.Api/Validators/Albums/UpdateAlbumRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/Albums/UpdateAlbumRequestValidator.cs @@ -7,15 +7,15 @@ public sealed class UpdateAlbumRequestValidator : AbstractValidator x.NewTitle) + RuleFor(x => x.Title) .NotEmpty() - .MaximumLength(200); + .MaximumLength(Limits.AlbumTitle); - RuleFor(x => x.NewDescription) - .MaximumLength(256); + RuleFor(x => x.Description) + .MaximumLength(Limits.Description); - RuleFor(x => x.NewReleaseYear) - .InclusiveBetween(AlbumReleaseYear.Earliest, AlbumReleaseYear.Latest) - .When(x => x.NewReleaseYear.HasValue); + RuleFor(x => x.ReleaseYear) + .InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear) + .When(x => x.ReleaseYear.HasValue); } } diff --git a/backend/Hosts/Musify.Api/Validators/Limits.cs b/backend/Hosts/Musify.Api/Validators/Limits.cs new file mode 100644 index 0000000..ac782d8 --- /dev/null +++ b/backend/Hosts/Musify.Api/Validators/Limits.cs @@ -0,0 +1,12 @@ +namespace Musify.Api.Validators; + +public static class Limits +{ + public const int TrackTitle = 200; + public const int AlbumTitle = 200; + public const int PlayListName = 50; + public const int Description = 256; + public const int EarliestReleaseYear = 1877; + + public static int LatestReleaseYear => DateTime.UtcNow.Year + 1; +} diff --git a/backend/Hosts/Musify.Api/Validators/Albums/RequestAlbumPictureUploadRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/PictureUploadRequestValidator.cs similarity index 55% rename from backend/Hosts/Musify.Api/Validators/Albums/RequestAlbumPictureUploadRequestValidator.cs rename to backend/Hosts/Musify.Api/Validators/PictureUploadRequestValidator.cs index 0db9287..15a9f40 100644 --- a/backend/Hosts/Musify.Api/Validators/Albums/RequestAlbumPictureUploadRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/PictureUploadRequestValidator.cs @@ -1,12 +1,12 @@ using FluentValidation; -using Musify.Api.DataTransferObjects.Albums; +using Musify.Api.DataTransferObjects; using Musify.Application.Configuration; -namespace Musify.Api.Validators.Albums; +namespace Musify.Api.Validators; -public sealed class RequestAlbumPictureUploadRequestValidator : AbstractValidator +public sealed class PictureUploadRequestValidator : AbstractValidator { - public RequestAlbumPictureUploadRequestValidator(UploadIntentConfiguration uploadConfiguration) + public PictureUploadRequestValidator(UploadIntentConfiguration uploadConfiguration) { RuleFor(x => x.FileType) .MustBeFileType(Uploads.PictureFileTypes); diff --git a/backend/Hosts/Musify.Api/Validators/PlayLists/CreatePlayListRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/PlayLists/CreatePlayListRequestValidator.cs index c28c91e..7695b3c 100644 --- a/backend/Hosts/Musify.Api/Validators/PlayLists/CreatePlayListRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/PlayLists/CreatePlayListRequestValidator.cs @@ -9,10 +9,10 @@ public sealed class CreatePlayListRequestValidator : AbstractValidator x.Name) .NotEmpty() - .MaximumLength(50); + .MaximumLength(Limits.PlayListName); RuleFor(x => x.Description) - .MaximumLength(256); + .MaximumLength(Limits.Description); RuleFor(x => x.Visibility) .IsInEnum(); diff --git a/backend/Hosts/Musify.Api/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs deleted file mode 100644 index 7da850a..0000000 --- a/backend/Hosts/Musify.Api/Validators/PlayLists/RequestPlayListPictureUploadRequestValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -using FluentValidation; -using Musify.Api.DataTransferObjects.PlayLists; -using Musify.Application.Configuration; - -namespace Musify.Api.Validators.PlayLists; - -public sealed class RequestPlayListPictureUploadRequestValidator : AbstractValidator -{ - public RequestPlayListPictureUploadRequestValidator(UploadIntentConfiguration uploadConfiguration) - { - RuleFor(x => x.FileType) - .MustBeFileType(Uploads.PictureFileTypes); - - RuleFor(x => x.ContentType) - .MustBeContentType(Uploads.PictureContentTypes); - - RuleFor(x => x.ExpectedSizeBytes) - .MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes); - } -} diff --git a/backend/Hosts/Musify.Api/Validators/PlayLists/UpdatePlayListRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/PlayLists/UpdatePlayListRequestValidator.cs index c7bbc96..6ca36af 100644 --- a/backend/Hosts/Musify.Api/Validators/PlayLists/UpdatePlayListRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/PlayLists/UpdatePlayListRequestValidator.cs @@ -7,17 +7,17 @@ public sealed class UpdatePlayListRequestValidator : AbstractValidator x.NewName) + RuleFor(x => x.Name) .NotEmpty() - .MaximumLength(50) - .When(x => x.NewName != null); + .MaximumLength(Limits.PlayListName) + .When(x => x.Name != null); - RuleFor(x => x.NewDescription) - .MaximumLength(256) - .When(x => x.NewDescription != null); + RuleFor(x => x.Description) + .MaximumLength(Limits.Description) + .When(x => x.Description != null); - RuleFor(x => x.NewVisibility) + RuleFor(x => x.Visibility) .IsInEnum() - .When(x => x.NewVisibility != null); + .When(x => x.Visibility != null); } } diff --git a/backend/Hosts/Musify.Api/Validators/Tracks/CreateTrackRequestValidator.cs b/backend/Hosts/Musify.Api/Validators/Tracks/CreateTrackRequestValidator.cs index 6584cff..266ba43 100644 --- a/backend/Hosts/Musify.Api/Validators/Tracks/CreateTrackRequestValidator.cs +++ b/backend/Hosts/Musify.Api/Validators/Tracks/CreateTrackRequestValidator.cs @@ -10,7 +10,7 @@ public sealed class CreateTrackRequestValidator : AbstractValidator x.Title) .NotEmpty() - .MaximumLength(200); + .MaximumLength(Limits.TrackTitle); RuleFor(x => x.PictureIntentId) .NotEmpty(); diff --git a/backend/Tests/Musify.Api.Tests/Endpoints/AlbumEndpointsTests.cs b/backend/Tests/Musify.Api.Tests/Endpoints/AlbumEndpointsTests.cs index 6f6d5eb..4a7f5c9 100644 --- a/backend/Tests/Musify.Api.Tests/Endpoints/AlbumEndpointsTests.cs +++ b/backend/Tests/Musify.Api.Tests/Endpoints/AlbumEndpointsTests.cs @@ -1,5 +1,6 @@ using System.Net; using System.Net.Http.Json; +using Musify.Api.DataTransferObjects; using Musify.Api.DataTransferObjects.Albums; using Musify.Api.Tests.TestSupport; using Musify.Application.Albums.Responses; @@ -26,7 +27,7 @@ public sealed class AlbumEndpointsTests(ApiTestFixture fixture) var response = await client.PostAsJsonAsync( "/albums/upload-picture", - new RequestAlbumPictureUploadRequest("webp", "image/webp"), + new PictureUploadRequest("webp", "image/webp"), TestContext.Current.CancellationToken); response.EnsureSuccessStatusCode(); diff --git a/backend/Tests/Musify.Api.Tests/Validators/CreateAlbumRequestValidatorTests.cs b/backend/Tests/Musify.Api.Tests/Validators/CreateAlbumRequestValidatorTests.cs index 7fe97e9..728c829 100644 --- a/backend/Tests/Musify.Api.Tests/Validators/CreateAlbumRequestValidatorTests.cs +++ b/backend/Tests/Musify.Api.Tests/Validators/CreateAlbumRequestValidatorTests.cs @@ -1,4 +1,5 @@ using Musify.Api.DataTransferObjects.Albums; +using Musify.Api.Validators; using Musify.Api.Validators.Albums; using Xunit; @@ -44,7 +45,7 @@ public sealed class CreateAlbumRequestValidatorTests [Fact] public void Validate_ReleaseYearBeforeTheEarliestBoundary_Fails() { - var result = validator.Validate(new CreateAlbumRequest("Title", null, AlbumReleaseYear.Earliest - 1, Guid.NewGuid())); + var result = validator.Validate(new CreateAlbumRequest("Title", null, Limits.EarliestReleaseYear - 1, Guid.NewGuid())); Assert.False(result.IsValid); } @@ -52,7 +53,7 @@ public sealed class CreateAlbumRequestValidatorTests [Fact] public void Validate_ReleaseYearAtTheEarliestBoundary_Passes() { - var result = validator.Validate(new CreateAlbumRequest("Title", null, AlbumReleaseYear.Earliest, Guid.NewGuid())); + var result = validator.Validate(new CreateAlbumRequest("Title", null, Limits.EarliestReleaseYear, Guid.NewGuid())); Assert.True(result.IsValid); } @@ -60,7 +61,7 @@ public sealed class CreateAlbumRequestValidatorTests [Fact] public void Validate_ReleaseYearAtTheLatestBoundary_Passes() { - var result = validator.Validate(new CreateAlbumRequest("Title", null, AlbumReleaseYear.Latest, Guid.NewGuid())); + var result = validator.Validate(new CreateAlbumRequest("Title", null, Limits.LatestReleaseYear, Guid.NewGuid())); Assert.True(result.IsValid); } @@ -68,7 +69,7 @@ public sealed class CreateAlbumRequestValidatorTests [Fact] public void Validate_ReleaseYearPastTheLatestBoundary_Fails() { - var result = validator.Validate(new CreateAlbumRequest("Title", null, AlbumReleaseYear.Latest + 1, Guid.NewGuid())); + var result = validator.Validate(new CreateAlbumRequest("Title", null, Limits.LatestReleaseYear + 1, Guid.NewGuid())); Assert.False(result.IsValid); } diff --git a/backend/Tests/Musify.Api.Tests/Validators/UploadRequestValidatorTests.cs b/backend/Tests/Musify.Api.Tests/Validators/UploadRequestValidatorTests.cs index f671b0e..e9b5fa3 100644 --- a/backend/Tests/Musify.Api.Tests/Validators/UploadRequestValidatorTests.cs +++ b/backend/Tests/Musify.Api.Tests/Validators/UploadRequestValidatorTests.cs @@ -1,6 +1,6 @@ -using Musify.Api.DataTransferObjects.Albums; +using Musify.Api.DataTransferObjects; using Musify.Api.DataTransferObjects.Tracks; -using Musify.Api.Validators.Albums; +using Musify.Api.Validators; using Musify.Api.Validators.Tracks; using Musify.Application.Configuration; using Xunit; @@ -14,9 +14,9 @@ public sealed class UploadRequestValidatorTests [Fact] public void PictureUpload_ValidRequest_Passes() { - var validator = new RequestAlbumPictureUploadRequestValidator(configuration); + var validator = new PictureUploadRequestValidator(configuration); - var result = validator.Validate(new RequestAlbumPictureUploadRequest("webp", "image/webp", 500)); + var result = validator.Validate(new PictureUploadRequest("webp", "image/webp", 500)); Assert.True(result.IsValid); } @@ -30,9 +30,9 @@ public sealed class UploadRequestValidatorTests [InlineData("webp", "image/webp", 1_001L)] public void PictureUpload_InvalidRequest_Fails(string fileType, string contentType, long size) { - var validator = new RequestAlbumPictureUploadRequestValidator(configuration); + var validator = new PictureUploadRequestValidator(configuration); - var result = validator.Validate(new RequestAlbumPictureUploadRequest(fileType, contentType, size)); + var result = validator.Validate(new PictureUploadRequest(fileType, contentType, size)); Assert.False(result.IsValid); } diff --git a/web-player/src/lib/api/schema.d.ts b/web-player/src/lib/api/schema.d.ts index 16a265e..4b274e0 100644 --- a/web-player/src/lib/api/schema.d.ts +++ b/web-player/src/lib/api/schema.d.ts @@ -11,10 +11,10 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated Albums, Optionally Filtered By Title. */ + /** Get paginated albums, optionally filtered by title */ get: operations["GetAlbums"]; put?: never; - /** Create A New Album. */ + /** Create a new album */ post: operations["CreateAlbum"]; delete?: never; options?: never; @@ -29,11 +29,13 @@ export interface paths { path?: never; cookie?: never; }; - /** Get An Album By Id. */ + /** Get an album by id */ get: operations["GetAlbumById"]; - put?: never; + /** Update an album */ + put: operations["UpdateAlbum"]; post?: never; - delete?: never; + /** Delete an album */ + delete: operations["DeleteAlbum"]; options?: never; head?: never; patch?: never; @@ -46,7 +48,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated Albums For A User. */ + /** Get paginated albums for a user */ get: operations["GetAlbumsByUserId"]; put?: never; post?: never; @@ -63,7 +65,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Albums The Current User Listened To Most Recently. */ + /** Get the albums the current user listened to most recently */ get: operations["GetRecentlyListenedAlbums"]; put?: never; post?: never; @@ -73,17 +75,18 @@ export interface paths { patch?: never; trace?: never; }; - "/albums/{albumId}/tracks": { + "/albums/{id}/tracks": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get The Tracks Of An Album Ordered By Track Number. */ + /** Get the tracks of an album ordered by track number */ get: operations["GetAlbumTracks"]; put?: never; - post?: never; + /** Add your uploaded tracks to an album, skipping the ones it already has */ + post: operations["AddAlbumTracks"]; delete?: never; options?: never; head?: never; @@ -97,7 +100,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get An Album Cover Image. */ + /** Get an album cover image */ get: operations["GetAlbumCover"]; put?: never; post?: never; @@ -116,7 +119,7 @@ export interface paths { }; get?: never; put?: never; - /** Request A Pre-Signed URL To Upload An Album Picture. */ + /** Request a pre-signed URL to upload an album picture */ post: operations["RequestAlbumPictureUpload"]; delete?: never; options?: never; @@ -124,42 +127,7 @@ export interface paths { patch?: never; trace?: never; }; - "/albums/{albumId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - /** Update An Album. */ - put: operations["UpdateAlbum"]; - post?: never; - /** Delete An Album. */ - delete: operations["DeleteAlbum"]; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/albums/{id}/tracks": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** Add Your Uploaded Tracks To An Album, Skipping The Ones It Already Has. */ - post: operations["AddAlbumTracks"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/albums/{albumId}/tracks/{trackId}": { + "/albums/{id}/tracks/{trackId}": { parameters: { query?: never; header?: never; @@ -169,7 +137,7 @@ export interface paths { get?: never; put?: never; post?: never; - /** Remove A Track From An Album. */ + /** Remove a track from an album */ delete: operations["RemoveTrackFromAlbum"]; options?: never; head?: never; @@ -183,7 +151,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Public Playback Configuration (Whether Anonymous Listening Is Allowed). Works Anonymously. */ + /** Get the public playback configuration (whether anonymous listening is allowed). Works anonymously */ get: operations["GetPlaybackPublicConfig"]; put?: never; post?: never; @@ -200,7 +168,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Genres That Have At Least One Track, Most Populated First. Works Anonymously. */ + /** Get the genres that have at least one track, most populated first. Works anonymously */ get: operations["GetGenres"]; put?: never; post?: never; @@ -217,7 +185,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Every Genre A Track Can Be Tagged With, Including The Genres It Cannot Be Combined With. Works Anonymously. */ + /** Get every genre a track can be tagged with, including the genres it cannot be combined with. Works anonymously */ get: operations["GetAvailableGenres"]; put?: never; post?: never; @@ -234,7 +202,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Current User'S Liked Tracks. */ + /** Get the current user's liked tracks */ get: operations["GetLikedTracks"]; put?: never; post?: never; @@ -253,7 +221,7 @@ export interface paths { }; get?: never; put?: never; - /** Like Or Unlike A Track By Id. */ + /** Like or unlike a track by id */ post: operations["ToggleTrackLike"]; delete?: never; options?: never; @@ -268,7 +236,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Server-Generated Mixes Of The Current User. */ + /** Get the server-generated mixes of the current user */ get: operations["GetMixes"]; put?: never; post?: never; @@ -285,7 +253,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A Mix With All Of Its Songs. */ + /** Get a mix with all of its songs */ get: operations["GetMixById"]; put?: never; post?: never; @@ -302,11 +270,13 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A PlayList By Id. */ + /** Get a playlist by id */ get: operations["GetPlayListById"]; - put?: never; + /** Update an existing playlist */ + put: operations["UpdatePlayList"]; post?: never; - delete?: never; + /** Delete a playlist */ + delete: operations["DeletePlayList"]; options?: never; head?: never; patch?: never; @@ -319,7 +289,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated PlayLists For A User. Private PlayLists Are Only Returned To Their Owner. */ + /** Get paginated playlists for a user. Private playlists are only returned to their owner */ get: operations["GetPlayListsByUserId"]; put?: never; post?: never; @@ -329,17 +299,18 @@ export interface paths { patch?: never; trace?: never; }; - "/playlists/{playlistId}/tracks": { + "/playlists/{id}/tracks": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get Paginated Tracks Of A PlayList. */ + /** Get paginated tracks of a playlist */ get: operations["GetPlayListTracks"]; put?: never; - post?: never; + /** Add tracks to a playlist, skipping the ones it already has */ + post: operations["AddPlayListTracks"]; delete?: never; options?: never; head?: never; @@ -353,7 +324,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A PlayList Cover Image. */ + /** Get a playlist cover image */ get: operations["GetPlayListCover"]; put?: never; post?: never; @@ -372,7 +343,7 @@ export interface paths { }; get?: never; put?: never; - /** Create A New PlayList. */ + /** Create a new playlist */ post: operations["CreatePlayList"]; delete?: never; options?: never; @@ -380,24 +351,6 @@ export interface paths { patch?: never; trace?: never; }; - "/playlists/{playlistId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - /** Update An Existing PlayList. */ - put: operations["UpdatePlayList"]; - post?: never; - /** Delete A PlayList. */ - delete: operations["DeletePlayList"]; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; "/playlists/upload-picture": { parameters: { query?: never; @@ -407,7 +360,7 @@ export interface paths { }; get?: never; put?: never; - /** Request A Pre-Signed URL To Upload A PlayList Picture. */ + /** Request a pre-signed URL to upload a playlist picture */ post: operations["RequestPlayListPictureUpload"]; delete?: never; options?: never; @@ -415,24 +368,7 @@ export interface paths { patch?: never; trace?: never; }; - "/playlists/{id}/tracks": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - /** Add Tracks To A PlayList, Skipping The Ones It Already Has. */ - post: operations["AddPlayListTracks"]; - delete?: never; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; - "/playlists/{playlistId}/tracks/{trackId}": { + "/playlists/{id}/tracks/{trackId}": { parameters: { query?: never; header?: never; @@ -442,7 +378,7 @@ export interface paths { get?: never; put?: never; post?: never; - /** Remove A Track From A PlayList. */ + /** Remove a track from a playlist */ delete: operations["RemoveTrackFromPlayList"]; options?: never; head?: never; @@ -456,10 +392,10 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated Tracks, Optionally Filtered By Name And Genre. */ + /** Get paginated tracks, optionally filtered by name and genre */ get: operations["GetTracks"]; put?: never; - /** Create A New Track. */ + /** Create a new track */ post: operations["CreateTrack"]; delete?: never; options?: never; @@ -474,11 +410,12 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A Track By Id. */ + /** Get a track by id */ get: operations["GetTrackById"]; put?: never; post?: never; - delete?: never; + /** Delete a track */ + delete: operations["DeleteTrack"]; options?: never; head?: never; patch?: never; @@ -491,7 +428,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A Track Cover Image. */ + /** Get a track cover image */ get: operations["GetTrackCover"]; put?: never; post?: never; @@ -508,7 +445,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A Streaming Manifest URL And Ticket For A Track. Works Anonymously When The Playback Configuration Allows It. */ + /** Get a streaming manifest URL and ticket for a track. Works anonymously when the playback configuration allows it */ get: operations["GetTrackStream"]; put?: never; post?: never; @@ -526,7 +463,7 @@ export interface paths { cookie?: never; }; get?: never; - /** Report The Total Seconds Actually Played For A Listen Started By The Stream Endpoint. */ + /** Report the total seconds actually played for a listen started by the stream endpoint */ put: operations["RecordListeningProgress"]; post?: never; delete?: never; @@ -542,7 +479,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated Tracks For A User. */ + /** Get paginated tracks for a user */ get: operations["GetTracksByUserId"]; put?: never; post?: never; @@ -552,23 +489,6 @@ export interface paths { patch?: never; trace?: never; }; - "/tracks/{trackId}": { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - get?: never; - put?: never; - post?: never; - /** Delete A Track. */ - delete: operations["DeleteTrack"]; - options?: never; - head?: never; - patch?: never; - trace?: never; - }; "/tracks/upload-urls": { parameters: { query?: never; @@ -578,7 +498,7 @@ export interface paths { }; get?: never; put?: never; - /** Request Pre-Signed URLs To Upload Track Picture And Audio. */ + /** Request pre-signed URLs to upload track picture and audio */ post: operations["RequestTrackUploadUrls"]; delete?: never; options?: never; @@ -593,7 +513,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get Paginated Users. */ + /** Get paginated users */ get: operations["GetUsers"]; put?: never; post?: never; @@ -610,7 +530,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A User By Id. */ + /** Get a user by id */ get: operations["GetUserById"]; put?: never; post?: never; @@ -627,7 +547,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A User'S Listening History. */ + /** Get a user's listening history */ get: operations["GetListeningHistory"]; put?: never; post?: never; @@ -644,7 +564,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A User'S Listening Stats For The Current Week And Streak. */ + /** Get a user's listening stats for the current week and streak */ get: operations["GetListeningStats"]; put?: never; post?: never; @@ -661,7 +581,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Last Track A User Listened To. */ + /** Get the last track a user listened to */ get: operations["GetLastTrackListenedByUserId"]; put?: never; post?: never; @@ -678,7 +598,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get A User'S Public Profile, Including Follower Counts. */ + /** Get a user's public profile, including follower counts */ get: operations["GetUserProfile"]; put?: never; post?: never; @@ -695,7 +615,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Users Following A User. Visible To The User And To Mutual Followers. */ + /** Get the users following a user. Visible to the user and to mutual followers */ get: operations["GetUserFollowers"]; put?: never; post?: never; @@ -712,7 +632,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Get The Users A User Follows. */ + /** Get the users a user follows */ get: operations["GetUserFollowing"]; put?: never; post?: never; @@ -729,7 +649,7 @@ export interface paths { path?: never; cookie?: never; }; - /** Check Whether The Current User Follows Another User. */ + /** Check whether the current user follows another user */ get: operations["IsFollowingUser"]; put?: never; post?: never; @@ -748,9 +668,9 @@ export interface paths { }; get?: never; put?: never; - /** Follow A User. */ + /** Follow a user */ post: operations["FollowUser"]; - /** Unfollow A User. */ + /** Unfollow a user */ delete: operations["UnfollowUser"]; options?: never; head?: never; @@ -910,6 +830,12 @@ export interface components { hasNextPage: boolean; hasPreviousPage: boolean; }; + PictureUploadRequest: { + fileType: string; + contentType: string; + /** Format: int64 */ + expectedSizeBytes?: null | number | string; + }; PictureUploadResponse: { /** Format: uuid */ intentId: string; @@ -954,18 +880,6 @@ export interface components { /** Format: double */ playedSeconds: number | string; }; - RequestAlbumPictureUploadRequest: { - fileType: string; - contentType: string; - /** Format: int64 */ - expectedSizeBytes?: null | number | string; - }; - RequestPlayListPictureUploadRequest: { - fileType: string; - contentType: string; - /** Format: int64 */ - expectedSizeBytes?: null | number | string; - }; RequestTrackUploadUrlsRequest: { pictureFileType: string; pictureContentType: string; @@ -1024,19 +938,19 @@ export interface components { expiresInSeconds: number | string; }; UpdateAlbumRequest: { - newTitle: string; - newDescription: null | string; + title: string; + description: null | string; /** Format: int32 */ - newReleaseYear: null | number | string; + releaseYear: null | number | string; /** Format: uuid */ - newPictureIntentId: null | string; + pictureIntentId: null | string; }; UpdatePlayListRequest: { - newName: null | string; - newDescription: null | string; + name: null | string; + description: null | string; /** Format: uuid */ - newPictureIntentId: null | string; - newVisibility?: null | components["schemas"]["PlayListVisibility"]; + pictureIntentId: null | string; + visibility?: null | components["schemas"]["PlayListVisibility"]; }; UserApplicationResponse: { id: string; @@ -1181,6 +1095,103 @@ export interface operations { }; }; }; + UpdateAlbum: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateAlbumRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["AlbumApplicationResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeleteAlbum: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description No Content */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; GetAlbumsByUserId: { parameters: { query?: { @@ -1189,7 +1200,7 @@ export interface operations { }; header?: never; path: { - userId: unknown; + userId: string; }; cookie?: never; }; @@ -1250,7 +1261,7 @@ export interface operations { }; header?: never; path: { - albumId: string; + id: string; }; cookie?: never; }; @@ -1274,179 +1285,6 @@ export interface operations { }; }; }; - GetAlbumCover: { - parameters: { - query?: { - size?: string; - }; - header?: never; - path: { - id: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - RequestAlbumPictureUpload: { - parameters: { - query?: never; - header?: never; - path?: never; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["RequestAlbumPictureUploadRequest"]; - }; - }; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["PictureUploadResponse"]; - }; - }; - /** @description Bad Request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - UpdateAlbum: { - parameters: { - query?: never; - header?: never; - path: { - albumId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdateAlbumRequest"]; - }; - }; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["AlbumApplicationResponse"]; - }; - }; - /** @description Bad Request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - DeleteAlbum: { - parameters: { - query?: never; - header?: never; - path: { - albumId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description No Content */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; AddAlbumTracks: { parameters: { query?: never; @@ -1508,12 +1346,88 @@ export interface operations { }; }; }; + GetAlbumCover: { + parameters: { + query?: { + size?: string; + }; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + RequestAlbumPictureUpload: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["PictureUploadRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PictureUploadResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; RemoveTrackFromAlbum: { parameters: { query?: never; header?: never; path: { - albumId: string; + id: string; trackId: string; }; cookie?: never; @@ -1770,6 +1684,103 @@ export interface operations { }; }; }; + UpdatePlayList: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdatePlayListRequest"]; + }; + }; + responses: { + /** @description OK */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PlayListApplicationResponse"]; + }; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + DeletePlayList: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description No Content */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; GetPlayListsByUserId: { parameters: { query?: { @@ -1779,7 +1790,7 @@ export interface operations { }; header?: never; path: { - userId: unknown; + userId: string; }; cookie?: never; }; @@ -1804,7 +1815,7 @@ export interface operations { }; header?: never; path: { - playlistId: string; + id: string; }; cookie?: never; }; @@ -1828,6 +1839,67 @@ export interface operations { }; }; }; + AddPlayListTracks: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["AddTracksRequest"]; + }; + }; + responses: { + /** @description No Content */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Bad Request */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; + }; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Conflict */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; GetPlayListCover: { parameters: { query?: { @@ -1904,103 +1976,6 @@ export interface operations { }; }; }; - UpdatePlayList: { - parameters: { - query?: never; - header?: never; - path: { - playlistId: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["UpdatePlayListRequest"]; - }; - }; - responses: { - /** @description OK */ - 200: { - headers: { - [name: string]: unknown; - }; - content: { - "application/json": components["schemas"]["PlayListApplicationResponse"]; - }; - }; - /** @description Bad Request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; - DeletePlayList: { - parameters: { - query?: never; - header?: never; - path: { - playlistId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description No Content */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; RequestPlayListPictureUpload: { parameters: { query?: never; @@ -2010,7 +1985,7 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["RequestPlayListPictureUploadRequest"]; + "application/json": components["schemas"]["PictureUploadRequest"]; }; }; responses: { @@ -2048,73 +2023,12 @@ export interface operations { }; }; }; - AddPlayListTracks: { - parameters: { - query?: never; - header?: never; - path: { - id: string; - }; - cookie?: never; - }; - requestBody: { - content: { - "application/json": components["schemas"]["AddTracksRequest"]; - }; - }; - responses: { - /** @description No Content */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Bad Request */ - 400: { - headers: { - [name: string]: unknown; - }; - content: { - "application/problem+json": components["schemas"]["HttpValidationProblemDetails"]; - }; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Conflict */ - 409: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; RemoveTrackFromPlayList: { parameters: { query?: never; header?: never; path: { - playlistId: string; + id: string; trackId: string; }; cookie?: never; @@ -2268,6 +2182,54 @@ export interface operations { }; }; }; + DeleteTrack: { + parameters: { + query?: never; + header?: never; + path: { + id: string; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description No Content */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Unauthorized */ + 401: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Forbidden */ + 403: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Not Found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Conflict */ + 409: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; GetTrackCover: { parameters: { query?: { @@ -2380,7 +2342,7 @@ export interface operations { }; header?: never; path: { - userId: unknown; + userId: string; }; cookie?: never; }; @@ -2397,54 +2359,6 @@ export interface operations { }; }; }; - DeleteTrack: { - parameters: { - query?: never; - header?: never; - path: { - trackId: string; - }; - cookie?: never; - }; - requestBody?: never; - responses: { - /** @description No Content */ - 204: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Unauthorized */ - 401: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Forbidden */ - 403: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Not Found */ - 404: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - /** @description Conflict */ - 409: { - headers: { - [name: string]: unknown; - }; - content?: never; - }; - }; - }; RequestTrackUploadUrls: { parameters: { query?: never; @@ -2528,7 +2442,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2557,7 +2471,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2586,7 +2500,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2622,7 +2536,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2651,7 +2565,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2683,7 +2597,7 @@ export interface operations { }; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2722,7 +2636,7 @@ export interface operations { }; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2751,7 +2665,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2780,7 +2694,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; @@ -2823,7 +2737,7 @@ export interface operations { query?: never; header?: never; path: { - id: unknown; + id: string; }; cookie?: never; }; diff --git a/web-player/src/lib/server/playlistActions.ts b/web-player/src/lib/server/playlistActions.ts index 2f93141..3379aea 100644 --- a/web-player/src/lib/server/playlistActions.ts +++ b/web-player/src/lib/server/playlistActions.ts @@ -40,8 +40,8 @@ export async function addAlbumToPlaylistAction({ request, params, locals, fetch } const api = createApiClient({ fetch, accessToken }); - const { data: tracks, error: tracksErr } = await api.GET('/albums/{albumId}/tracks', { - params: { path: { albumId }, query: { pageNumber: 1, pageSize: ALBUM_TRACKS_PAGE_SIZE } } + const { data: tracks, error: tracksErr } = await api.GET('/albums/{id}/tracks', { + params: { path: { id: albumId }, query: { pageNumber: 1, pageSize: ALBUM_TRACKS_PAGE_SIZE } } }); if (tracksErr || !tracks) { diff --git a/web-player/src/routes/(app)/albums/[id]/+page.server.ts b/web-player/src/routes/(app)/albums/[id]/+page.server.ts index e3d2b68..82bb728 100644 --- a/web-player/src/routes/(app)/albums/[id]/+page.server.ts +++ b/web-player/src/routes/(app)/albums/[id]/+page.server.ts @@ -18,9 +18,9 @@ export const load: PageServerLoad = async ({ params, locals, url, fetch, parent const [albumRes, tracksRes, libraryRes] = await Promise.all([ api.GET('/albums/{id}', { params: { path: { id: params.id } } }), - api.GET('/albums/{albumId}/tracks', { + api.GET('/albums/{id}/tracks', { params: { - path: { albumId: params.id }, + path: { id: params.id }, query: { pageNumber: 1, pageSize: ALBUM_TRACKS_PAGE_SIZE } } }), @@ -71,8 +71,8 @@ export const actions: Actions = { if (!trackId) return fail(400, { message: 'Falta la canción.' }); const api = createApiClient({ fetch, accessToken }); - const result = await api.DELETE('/albums/{albumId}/tracks/{trackId}', { - params: { path: { albumId: params.id, trackId } } + const result = await api.DELETE('/albums/{id}/tracks/{trackId}', { + params: { path: { id: params.id, trackId } } }); const failure = unwrapOrFail(result, 'No se pudo quitar la canción.'); if (failure) return failure; @@ -102,13 +102,13 @@ export const actions: Actions = { newPictureIntentId = uploaded.intentId; } - const result = await api.PUT('/albums/{albumId}', { - params: { path: { albumId: params.id } }, + const result = await api.PUT('/albums/{id}', { + params: { path: { id: params.id } }, body: { - newTitle: parsed.body.title, - newDescription: parsed.body.description, - newReleaseYear: parsed.body.releaseYear, - newPictureIntentId + title: parsed.body.title, + description: parsed.body.description, + releaseYear: parsed.body.releaseYear, + pictureIntentId: newPictureIntentId } }); const failure = unwrapOrFail(result, 'No se pudo actualizar el álbum.'); @@ -121,8 +121,8 @@ export const actions: Actions = { if (typeof accessToken !== 'string') return accessToken; const api = createApiClient({ fetch, accessToken }); - const result = await api.DELETE('/albums/{albumId}', { - params: { path: { albumId: params.id } } + const result = await api.DELETE('/albums/{id}', { + params: { path: { id: params.id } } }); const failure = unwrapOrFail(result, 'No se pudo eliminar el álbum.'); if (failure) return failure; diff --git a/web-player/src/routes/(app)/library/+page.server.ts b/web-player/src/routes/(app)/library/+page.server.ts index 3a49811..a0fccb1 100644 --- a/web-player/src/routes/(app)/library/+page.server.ts +++ b/web-player/src/routes/(app)/library/+page.server.ts @@ -28,8 +28,8 @@ export const actions: Actions = { if (!trackId) return fail(400, { message: 'Falta la canción.' }); const api = createApiClient({ fetch, accessToken }); - const result = await api.DELETE('/tracks/{trackId}', { - params: { path: { trackId } } + const result = await api.DELETE('/tracks/{id}', { + params: { path: { id: trackId } } }); const failure = unwrapOrFail(result, 'No se pudo borrar la canción.'); if (failure) return failure; diff --git a/web-player/src/routes/(app)/playlists/+page.server.ts b/web-player/src/routes/(app)/playlists/+page.server.ts index 8b41e64..a710d2c 100644 --- a/web-player/src/routes/(app)/playlists/+page.server.ts +++ b/web-player/src/routes/(app)/playlists/+page.server.ts @@ -26,8 +26,8 @@ export const load: PageServerLoad = async ({ locals, url, fetch }) => { fetchAllPages( async (pageNumber, pageSize) => ( - await api.GET('/playlists/{playlistId}/tracks', { - params: { path: { playlistId: playlist.id }, query: { pageNumber, pageSize } } + await api.GET('/playlists/{id}/tracks', { + params: { path: { id: playlist.id }, query: { pageNumber, pageSize } } }) ).data, PLAYLIST_TRACKS_LIMIT diff --git a/web-player/src/routes/(app)/playlists/[id]/+page.server.ts b/web-player/src/routes/(app)/playlists/[id]/+page.server.ts index 32882b6..9bae75f 100644 --- a/web-player/src/routes/(app)/playlists/[id]/+page.server.ts +++ b/web-player/src/routes/(app)/playlists/[id]/+page.server.ts @@ -23,8 +23,8 @@ export const load: PageServerLoad = async ({ params, locals, url, fetch, parent fetchAllPages( async (pageNumber, pageSize) => ( - await api.GET('/playlists/{playlistId}/tracks', { - params: { path: { playlistId: params.id }, query: { pageNumber, pageSize } } + await api.GET('/playlists/{id}/tracks', { + params: { path: { id: params.id }, query: { pageNumber, pageSize } } }) ).data, PLAYLIST_TRACKS_LIMIT @@ -44,8 +44,8 @@ export const actions: Actions = { if (!trackId) return fail(400, { message: 'Falta la canción.' }); const api = createApiClient({ fetch, accessToken }); - const result = await api.DELETE('/playlists/{playlistId}/tracks/{trackId}', { - params: { path: { playlistId: params.id, trackId } } + const result = await api.DELETE('/playlists/{id}/tracks/{trackId}', { + params: { path: { id: params.id, trackId } } }); const failure = unwrapOrFail(result, 'No se pudo quitar la canción.'); if (failure) return failure; @@ -78,9 +78,14 @@ export const actions: Actions = { newPictureIntentId = result.intentId; } - const result = await api.PUT('/playlists/{playlistId}', { - params: { path: { playlistId: params.id } }, - body: { newName: name, newDescription: description, newPictureIntentId, newVisibility } + const result = await api.PUT('/playlists/{id}', { + params: { path: { id: params.id } }, + body: { + name, + description, + pictureIntentId: newPictureIntentId, + visibility: newVisibility + } }); const failure = unwrapOrFail(result, 'No se pudo actualizar la playlist.'); if (failure) return failure; @@ -92,8 +97,8 @@ export const actions: Actions = { if (typeof accessToken !== 'string') return accessToken; const api = createApiClient({ fetch, accessToken }); - const result = await api.DELETE('/playlists/{playlistId}', { - params: { path: { playlistId: params.id } } + const result = await api.DELETE('/playlists/{id}', { + params: { path: { id: params.id } } }); const failure = unwrapOrFail(result, 'No se pudo eliminar la playlist.'); if (failure) return failure; diff --git a/web-player/src/routes/(app)/user/[id]/+page.server.ts b/web-player/src/routes/(app)/user/[id]/+page.server.ts index 2760ce2..7f64317 100644 --- a/web-player/src/routes/(app)/user/[id]/+page.server.ts +++ b/web-player/src/routes/(app)/user/[id]/+page.server.ts @@ -25,8 +25,8 @@ export const load: PageServerLoad = async ({ params, locals, url, fetch, parent const tracksByPlaylist = await Promise.all( playlistItems.map((playlist) => api - .GET('/playlists/{playlistId}/tracks', { - params: { path: { playlistId: playlist.id }, query: { pageNumber: 1, pageSize: 1 } } + .GET('/playlists/{id}/tracks', { + params: { path: { id: playlist.id }, query: { pageNumber: 1, pageSize: 1 } } }) .then((res) => Number(res.data?.totalItemCount ?? 0)) ) diff --git a/web-player/src/routes/+page.server.ts b/web-player/src/routes/+page.server.ts index 791961b..35a1c2d 100644 --- a/web-player/src/routes/+page.server.ts +++ b/web-player/src/routes/+page.server.ts @@ -45,9 +45,9 @@ export const load: PageServerLoad = async ({ locals, url, fetch }) => { const spotlightPlaylist = playlistItems[0] ?? null; const spotlightTracksPromise = spotlightPlaylist ? api - .GET('/playlists/{playlistId}/tracks', { + .GET('/playlists/{id}/tracks', { params: { - path: { playlistId: spotlightPlaylist.id }, + path: { id: spotlightPlaylist.id }, query: { pageNumber: 1, pageSize: HOME_SPOTLIGHT_TRACKS_LIMIT } } }) diff --git a/web-player/src/routes/api/albums/[id]/tracks/+server.ts b/web-player/src/routes/api/albums/[id]/tracks/+server.ts index e356c9c..6c9ff1c 100644 --- a/web-player/src/routes/api/albums/[id]/tracks/+server.ts +++ b/web-player/src/routes/api/albums/[id]/tracks/+server.ts @@ -5,9 +5,9 @@ import { ALBUM_TRACKS_PAGE_SIZE } from '$lib/config'; export const GET: RequestHandler = async ({ params, locals, fetch }) => { const api = createApiClient({ fetch, accessToken: locals.accessToken ?? undefined }); - const result = await api.GET('/albums/{albumId}/tracks', { + const result = await api.GET('/albums/{id}/tracks', { params: { - path: { albumId: params.id }, + path: { id: params.id }, query: { pageNumber: 1, pageSize: ALBUM_TRACKS_PAGE_SIZE } } });