Change editor rule
This commit is contained in:
@@ -1,20 +1,21 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects;
|
||||
|
||||
namespace Musify.Api.Validators;
|
||||
|
||||
public sealed class AddTracksRequestValidator : AbstractValidator<AddTracksRequest>
|
||||
namespace Musify.Api.Validators
|
||||
{
|
||||
public const int MaxTracksPerRequest = 500;
|
||||
|
||||
public AddTracksRequestValidator()
|
||||
public sealed class AddTracksRequestValidator : AbstractValidator<AddTracksRequest>
|
||||
{
|
||||
RuleFor(x => x.TrackIds)
|
||||
.NotEmpty()
|
||||
.Must(ids => ids.Count <= MaxTracksPerRequest)
|
||||
.WithMessage($"At most {MaxTracksPerRequest} tracks can be added at once.");
|
||||
public const int MaxTracksPerRequest = 500;
|
||||
|
||||
RuleForEach(x => x.TrackIds)
|
||||
.NotEmpty();
|
||||
public AddTracksRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.TrackIds)
|
||||
.NotEmpty()
|
||||
.Must(ids => ids.Count <= MaxTracksPerRequest)
|
||||
.WithMessage($"At most {MaxTracksPerRequest} tracks can be added at once.");
|
||||
|
||||
RuleForEach(x => x.TrackIds)
|
||||
.NotEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.Albums;
|
||||
|
||||
namespace Musify.Api.Validators.Albums;
|
||||
|
||||
public sealed class CreateAlbumRequestValidator : AbstractValidator<CreateAlbumRequest>
|
||||
namespace Musify.Api.Validators.Albums
|
||||
{
|
||||
public CreateAlbumRequestValidator()
|
||||
public sealed class CreateAlbumRequestValidator : AbstractValidator<CreateAlbumRequest>
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.AlbumTitle);
|
||||
public CreateAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.AlbumTitle);
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
|
||||
RuleFor(x => x.ReleaseYear)
|
||||
.InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear)
|
||||
.When(x => x.ReleaseYear.HasValue);
|
||||
RuleFor(x => x.ReleaseYear)
|
||||
.InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear)
|
||||
.When(x => x.ReleaseYear.HasValue);
|
||||
|
||||
RuleFor(x => x.PictureIntentId)
|
||||
.NotEmpty();
|
||||
RuleFor(x => x.PictureIntentId)
|
||||
.NotEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.Albums;
|
||||
|
||||
namespace Musify.Api.Validators.Albums;
|
||||
|
||||
public sealed class UpdateAlbumRequestValidator : AbstractValidator<UpdateAlbumRequest>
|
||||
namespace Musify.Api.Validators.Albums
|
||||
{
|
||||
public UpdateAlbumRequestValidator()
|
||||
public sealed class UpdateAlbumRequestValidator : AbstractValidator<UpdateAlbumRequest>
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.AlbumTitle);
|
||||
public UpdateAlbumRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.AlbumTitle);
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
|
||||
RuleFor(x => x.ReleaseYear)
|
||||
.InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear)
|
||||
.When(x => x.ReleaseYear.HasValue);
|
||||
RuleFor(x => x.ReleaseYear)
|
||||
.InclusiveBetween(Limits.EarliestReleaseYear, Limits.LatestReleaseYear)
|
||||
.When(x => x.ReleaseYear.HasValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
namespace Musify.Api.Validators;
|
||||
|
||||
public static class Limits
|
||||
namespace Musify.Api.Validators
|
||||
{
|
||||
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 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;
|
||||
public static int LatestReleaseYear => DateTime.UtcNow.Year + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,17 @@ using FluentValidation;
|
||||
using Musify.Api.Models;
|
||||
using Musify.Application.Shared;
|
||||
|
||||
namespace Musify.Api.Validators;
|
||||
|
||||
public sealed class PageQueryValidator : AbstractValidator<PageQuery>
|
||||
namespace Musify.Api.Validators
|
||||
{
|
||||
public PageQueryValidator()
|
||||
public sealed class PageQueryValidator : AbstractValidator<PageQuery>
|
||||
{
|
||||
RuleFor(x => x.PageNumber)
|
||||
.GreaterThanOrEqualTo(1);
|
||||
public PageQueryValidator()
|
||||
{
|
||||
RuleFor(x => x.PageNumber)
|
||||
.GreaterThanOrEqualTo(1);
|
||||
|
||||
RuleFor(x => x.PageSize)
|
||||
.InclusiveBetween(1, PageRequest.MaxPageSize);
|
||||
RuleFor(x => x.PageSize)
|
||||
.InclusiveBetween(1, PageRequest.MaxPageSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,20 @@ using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects;
|
||||
using Musify.Application.Configuration;
|
||||
|
||||
namespace Musify.Api.Validators;
|
||||
|
||||
public sealed class PictureUploadRequestValidator : AbstractValidator<PictureUploadRequest>
|
||||
namespace Musify.Api.Validators
|
||||
{
|
||||
public PictureUploadRequestValidator(UploadIntentConfiguration uploadConfiguration)
|
||||
public sealed class PictureUploadRequestValidator : AbstractValidator<PictureUploadRequest>
|
||||
{
|
||||
RuleFor(x => x.FileType)
|
||||
.MustBeFileType(Uploads.PictureFileTypes);
|
||||
public PictureUploadRequestValidator(UploadIntentConfiguration uploadConfiguration)
|
||||
{
|
||||
RuleFor(x => x.FileType)
|
||||
.MustBeFileType(Uploads.PictureFileTypes);
|
||||
|
||||
RuleFor(x => x.ContentType)
|
||||
.MustBeContentType(Uploads.PictureContentTypes);
|
||||
RuleFor(x => x.ContentType)
|
||||
.MustBeContentType(Uploads.PictureContentTypes);
|
||||
|
||||
RuleFor(x => x.ExpectedSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
RuleFor(x => x.ExpectedSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.PlayLists;
|
||||
|
||||
namespace Musify.Api.Validators.PlayLists;
|
||||
|
||||
public sealed class CreatePlayListRequestValidator : AbstractValidator<CreatePlayListRequest>
|
||||
namespace Musify.Api.Validators.PlayLists
|
||||
{
|
||||
public CreatePlayListRequestValidator()
|
||||
public sealed class CreatePlayListRequestValidator : AbstractValidator<CreatePlayListRequest>
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.PlayListName);
|
||||
public CreatePlayListRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.PlayListName);
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description);
|
||||
|
||||
RuleFor(x => x.Visibility)
|
||||
.IsInEnum();
|
||||
RuleFor(x => x.Visibility)
|
||||
.IsInEnum();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.PlayLists;
|
||||
|
||||
namespace Musify.Api.Validators.PlayLists;
|
||||
|
||||
public sealed class UpdatePlayListRequestValidator : AbstractValidator<UpdatePlayListRequest>
|
||||
namespace Musify.Api.Validators.PlayLists
|
||||
{
|
||||
public UpdatePlayListRequestValidator()
|
||||
public sealed class UpdatePlayListRequestValidator : AbstractValidator<UpdatePlayListRequest>
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.PlayListName)
|
||||
.When(x => x.Name != null);
|
||||
public UpdatePlayListRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Name)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.PlayListName)
|
||||
.When(x => x.Name != null);
|
||||
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description)
|
||||
.When(x => x.Description != null);
|
||||
RuleFor(x => x.Description)
|
||||
.MaximumLength(Limits.Description)
|
||||
.When(x => x.Description != null);
|
||||
|
||||
RuleFor(x => x.Visibility)
|
||||
.IsInEnum()
|
||||
.When(x => x.Visibility != null);
|
||||
RuleFor(x => x.Visibility)
|
||||
.IsInEnum()
|
||||
.When(x => x.Visibility != null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,33 +2,34 @@ using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.Tracks;
|
||||
using Musify.Domain.ValueObjects;
|
||||
|
||||
namespace Musify.Api.Validators.Tracks;
|
||||
|
||||
public sealed class CreateTrackRequestValidator : AbstractValidator<CreateTrackRequest>
|
||||
namespace Musify.Api.Validators.Tracks
|
||||
{
|
||||
public CreateTrackRequestValidator()
|
||||
public sealed class CreateTrackRequestValidator : AbstractValidator<CreateTrackRequest>
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.TrackTitle);
|
||||
public CreateTrackRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.Title)
|
||||
.NotEmpty()
|
||||
.MaximumLength(Limits.TrackTitle);
|
||||
|
||||
RuleFor(x => x.PictureIntentId)
|
||||
.NotEmpty();
|
||||
RuleFor(x => x.PictureIntentId)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.AudioIntentId)
|
||||
.NotEmpty();
|
||||
RuleFor(x => x.AudioIntentId)
|
||||
.NotEmpty();
|
||||
|
||||
RuleFor(x => x.Tags)
|
||||
.NotEmpty()
|
||||
.WithMessage("At least one tag is required.");
|
||||
RuleFor(x => x.Tags)
|
||||
.NotEmpty()
|
||||
.WithMessage("At least one tag is required.");
|
||||
|
||||
RuleFor(x => x.Tags)
|
||||
.Must(tags => GenreCompatibility.FindConflicts(tags).Count == 0)
|
||||
.When(x => x.Tags is { Count: > 0 })
|
||||
.WithMessage(x =>
|
||||
{
|
||||
var conflict = GenreCompatibility.FindConflicts(x.Tags).First();
|
||||
return $"Tags '{conflict.First}' and '{conflict.Second}' are not compatible.";
|
||||
});
|
||||
RuleFor(x => x.Tags)
|
||||
.Must(tags => GenreCompatibility.FindConflicts(tags).Count == 0)
|
||||
.When(x => x.Tags is { Count: > 0 })
|
||||
.WithMessage(x =>
|
||||
{
|
||||
var conflict = GenreCompatibility.FindConflicts(x.Tags).First();
|
||||
return $"Tags '{conflict.First}' and '{conflict.Second}' are not compatible.";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-7
@@ -1,14 +1,15 @@
|
||||
using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.Tracks;
|
||||
|
||||
namespace Musify.Api.Validators.Tracks;
|
||||
|
||||
public sealed class RecordListeningProgressRequestValidator : AbstractValidator<RecordListeningProgressRequest>
|
||||
namespace Musify.Api.Validators.Tracks
|
||||
{
|
||||
public RecordListeningProgressRequestValidator()
|
||||
public sealed class RecordListeningProgressRequestValidator : AbstractValidator<RecordListeningProgressRequest>
|
||||
{
|
||||
RuleFor(x => x.PlayedSeconds)
|
||||
.Must(seconds => double.IsFinite(seconds) && seconds >= 0)
|
||||
.WithMessage("'Played Seconds' must be a non-negative number.");
|
||||
public RecordListeningProgressRequestValidator()
|
||||
{
|
||||
RuleFor(x => x.PlayedSeconds)
|
||||
.Must(seconds => double.IsFinite(seconds) && seconds >= 0)
|
||||
.WithMessage("'Played Seconds' must be a non-negative number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-16
@@ -2,28 +2,29 @@ using FluentValidation;
|
||||
using Musify.Api.DataTransferObjects.Tracks;
|
||||
using Musify.Application.Configuration;
|
||||
|
||||
namespace Musify.Api.Validators.Tracks;
|
||||
|
||||
public sealed class RequestTrackUploadUrlsRequestValidator : AbstractValidator<RequestTrackUploadUrlsRequest>
|
||||
namespace Musify.Api.Validators.Tracks
|
||||
{
|
||||
public RequestTrackUploadUrlsRequestValidator(UploadIntentConfiguration uploadConfiguration)
|
||||
public sealed class RequestTrackUploadUrlsRequestValidator : AbstractValidator<RequestTrackUploadUrlsRequest>
|
||||
{
|
||||
RuleFor(x => x.PictureFileType)
|
||||
.MustBeFileType(Uploads.PictureFileTypes);
|
||||
public RequestTrackUploadUrlsRequestValidator(UploadIntentConfiguration uploadConfiguration)
|
||||
{
|
||||
RuleFor(x => x.PictureFileType)
|
||||
.MustBeFileType(Uploads.PictureFileTypes);
|
||||
|
||||
RuleFor(x => x.PictureContentType)
|
||||
.MustBeContentType(Uploads.PictureContentTypes);
|
||||
RuleFor(x => x.PictureContentType)
|
||||
.MustBeContentType(Uploads.PictureContentTypes);
|
||||
|
||||
RuleFor(x => x.AudioFileType)
|
||||
.MustBeFileType(Uploads.AudioFileTypes);
|
||||
RuleFor(x => x.AudioFileType)
|
||||
.MustBeFileType(Uploads.AudioFileTypes);
|
||||
|
||||
RuleFor(x => x.AudioContentType)
|
||||
.MustBeContentType(Uploads.AudioContentTypes);
|
||||
RuleFor(x => x.AudioContentType)
|
||||
.MustBeContentType(Uploads.AudioContentTypes);
|
||||
|
||||
RuleFor(x => x.ExpectedPictureSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
RuleFor(x => x.ExpectedPictureSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
|
||||
RuleFor(x => x.ExpectedAudioSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
RuleFor(x => x.ExpectedAudioSizeBytes)
|
||||
.MustBeValidUploadSize(uploadConfiguration.MaxUploadBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,43 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace Musify.Api.Validators;
|
||||
|
||||
public static class Uploads
|
||||
namespace Musify.Api.Validators
|
||||
{
|
||||
public static readonly IReadOnlySet<string> PictureFileTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "jpg", "jpeg", "png", "webp" };
|
||||
public static class Uploads
|
||||
{
|
||||
public static readonly IReadOnlySet<string> PictureFileTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "jpg", "jpeg", "png", "webp" };
|
||||
|
||||
public static readonly IReadOnlySet<string> PictureContentTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "image/jpeg", "image/png", "image/webp" };
|
||||
public static readonly IReadOnlySet<string> PictureContentTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "image/jpeg", "image/png", "image/webp" };
|
||||
|
||||
public static readonly IReadOnlySet<string> AudioFileTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "mp3", "wav", "flac", "ogg", "m4a", "aac" };
|
||||
public static readonly IReadOnlySet<string> AudioFileTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "mp3", "wav", "flac", "ogg", "m4a", "aac" };
|
||||
|
||||
public static readonly IReadOnlySet<string> AudioContentTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"audio/mpeg", "audio/mp3", "audio/wav", "audio/x-wav", "audio/wave", "audio/flac", "audio/x-flac",
|
||||
"audio/ogg", "audio/mp4", "audio/x-m4a", "audio/m4a", "audio/aac"
|
||||
};
|
||||
public static readonly IReadOnlySet<string> AudioContentTypes =
|
||||
new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"audio/mpeg", "audio/mp3", "audio/wav", "audio/x-wav", "audio/wave", "audio/flac", "audio/x-flac",
|
||||
"audio/ogg", "audio/mp4", "audio/x-m4a", "audio/m4a", "audio/aac"
|
||||
};
|
||||
|
||||
public static IRuleBuilderOptions<T, string> MustBeFileType<T>(
|
||||
this IRuleBuilder<T, string> rule, IReadOnlySet<string> allowed) =>
|
||||
rule
|
||||
.NotEmpty()
|
||||
.Length(1, 10)
|
||||
.Matches("^[A-Za-z0-9]+$").WithMessage("'{PropertyName}' must contain only letters and digits.")
|
||||
.Must(allowed.Contains).WithMessage("'{PropertyName}' must be one of: " + string.Join(", ", allowed) + ".");
|
||||
public static IRuleBuilderOptions<T, string> MustBeFileType<T>(
|
||||
this IRuleBuilder<T, string> rule, IReadOnlySet<string> allowed) =>
|
||||
rule
|
||||
.NotEmpty()
|
||||
.Length(1, 10)
|
||||
.Matches("^[A-Za-z0-9]+$").WithMessage("'{PropertyName}' must contain only letters and digits.")
|
||||
.Must(allowed.Contains).WithMessage("'{PropertyName}' must be one of: " + string.Join(", ", allowed) + ".");
|
||||
|
||||
public static IRuleBuilderOptions<T, string> MustBeContentType<T>(
|
||||
this IRuleBuilder<T, string> rule, IReadOnlySet<string> allowed) =>
|
||||
rule
|
||||
.NotEmpty()
|
||||
.Must(allowed.Contains).WithMessage("'{PropertyName}' is not an allowed content type.");
|
||||
public static IRuleBuilderOptions<T, string> MustBeContentType<T>(
|
||||
this IRuleBuilder<T, string> rule, IReadOnlySet<string> allowed) =>
|
||||
rule
|
||||
.NotEmpty()
|
||||
.Must(allowed.Contains).WithMessage("'{PropertyName}' is not an allowed content type.");
|
||||
|
||||
public static IRuleBuilderOptions<T, long?> MustBeValidUploadSize<T>(
|
||||
this IRuleBuilder<T, long?> rule, long maxUploadBytes) =>
|
||||
rule
|
||||
.Must(size => size is null || (size > 0 && size <= maxUploadBytes))
|
||||
.WithMessage($"'{{PropertyName}}' must be greater than 0 and at most {maxUploadBytes} bytes.");
|
||||
public static IRuleBuilderOptions<T, long?> MustBeValidUploadSize<T>(
|
||||
this IRuleBuilder<T, long?> rule, long maxUploadBytes) =>
|
||||
rule
|
||||
.Must(size => size is null || (size > 0 && size <= maxUploadBytes))
|
||||
.WithMessage($"'{{PropertyName}}' must be greater than 0 and at most {maxUploadBytes} bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user