Adding episodes triggers

This commit is contained in:
Zoe Roux 2021-06-22 23:19:32 +02:00
parent d2f774e32d
commit 37c752229e
11 changed files with 132 additions and 18 deletions

View File

@ -0,0 +1,10 @@
using System;
namespace Kyoo.Models.Attributes
{
/// <summary>
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class ComputedAttribute : NotMergeableAttribute { }
}

View File

@ -17,12 +17,17 @@ namespace Kyoo.Models
public int ID { get; set; }
/// <inheritdoc />
public string Slug
[Computed] public string Slug
{
get => GetSlug(ShowSlug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
get
{
if (ShowSlug == null && Show == null)
return GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber);
return GetSlug(ShowSlug ?? Show.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
}
[UsedImplicitly] private set
{
Match match = Regex.Match(value, @"(?<show>.*)-s(?<season>\d*)e(?<episode>\d*)");
Match match = Regex.Match(value, @"(?<show>.+)-s(?<season>\d+)e(?<episode>\d+)");
if (match.Success)
{

View File

@ -16,12 +16,17 @@ namespace Kyoo.Models
public int ID { get; set; }
/// <inheritdoc />
public string Slug
[Computed] public string Slug
{
get => $"{ShowSlug}-s{SeasonNumber}";
get
{
if (ShowSlug == null && Show == null)
return $"{ShowID}-s{SeasonNumber}";
return $"{ShowSlug ?? Show?.Slug}-s{SeasonNumber}";
}
[UsedImplicitly] private set
{
Match match = Regex.Match(value, @"(?<show>.*)-s(?<season>\d*)");
Match match = Regex.Match(value ?? "", @"(?<show>.+)-s(?<season>\d+)");
if (!match.Success)
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");

View File

@ -29,7 +29,7 @@ namespace Kyoo.Models
public int ID { get; set; }
/// <inheritdoc />
public string Slug
[Computed] public string Slug
{
get
{

View File

@ -330,6 +330,16 @@ namespace Kyoo
modelBuilder.Entity<Track>()
.Property(x => x.Slug)
.ValueGeneratedOnAddOrUpdate();
modelBuilder.Entity<Episode>()
.Property(x => x.EpisodeNumber)
.HasDefaultValue(-1);
modelBuilder.Entity<Episode>()
.Property(x => x.SeasonNumber)
.HasDefaultValue(-1);
modelBuilder.Entity<Episode>()
.Property(x => x.AbsoluteNumber)
.HasDefaultValue(-1);
}
/// <summary>

View File

@ -14,6 +14,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
</ItemGroup>

View File

@ -257,6 +257,8 @@ namespace Kyoo.Controllers
/// <exception cref="ArgumentException">You can throw this if the resource is illegal and should not be saved.</exception>
protected virtual Task Validate(T resource)
{
if (typeof(T).GetProperty(nameof(resource.Slug))!.GetCustomAttribute<ComputedAttribute>() != null)
return Task.CompletedTask;
if (string.IsNullOrEmpty(resource.Slug))
throw new ArgumentException("Resource can't have null as a slug.");
if (int.TryParse(resource.Slug, out int _))

View File

@ -18,10 +18,26 @@ namespace Kyoo.SqLite.Migrations
UPDATE Seasons SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) || '-s' || SeasonNumber
WHERE ID == new.ID;
END");
migrationBuilder.Sql(@"
CREATE TRIGGER EpisodeSlugInsert AFTER INSERT ON Episodes FOR EACH ROW
BEGIN
UPDATE Episodes SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) || '-s' || SeasonNumber || 'e' || EpisodeNumber
WHERE ID == new.ID;
END");
migrationBuilder.Sql(@"
CREATE TRIGGER EpisodeSlugUpdate AFTER UPDATE OF EpisodeNumber, SeasonNumber, ShowID ON Episodes FOR EACH ROW
BEGIN
UPDATE Episodes SET Slug = (SELECT Slug from Shows WHERE ID = ShowID) || '-s' || SeasonNumber || 'e' || EpisodeNumber
WHERE ID == new.ID;
END");
migrationBuilder.Sql(@"
CREATE TRIGGER ShowSlugUpdate AFTER UPDATE OF Slug ON Shows FOR EACH ROW
BEGIN
UPDATE Seasons SET Slug = new.Slug || '-s' || SeasonNumber WHERE ShowID = new.ID;
UPDATE Episodes SET Slug = new.Slug || '-s' || SeasonNumber || 'e' || EpisodeNumber WHERE ShowID = new.ID;
END;");
}
@ -29,6 +45,8 @@ namespace Kyoo.SqLite.Migrations
{
migrationBuilder.Sql("DROP TRIGGER SeasonSlugInsert;");
migrationBuilder.Sql("DROP TRIGGER SeasonSlugUpdate;");
migrationBuilder.Sql("DROP TRIGGER EpisodeSlugInsert;");
migrationBuilder.Sql("DROP TRIGGER EpisodeSlugUpdate;");
migrationBuilder.Sql("DROP TRIGGER ShowSlugUpdate;");
}
}

View File

@ -1,3 +1,5 @@
using System.Threading.Tasks;
using Kyoo.Controllers;
using Kyoo.Models;
using Xunit;
@ -25,8 +27,70 @@ namespace Kyoo.Tests.Library
public abstract class AEpisodeTests : RepositoryTests<Episode>
{
private readonly IEpisodeRepository _repository;
protected AEpisodeTests(RepositoryActivator repositories)
: base(repositories)
{ }
{
_repository = repositories.LibraryManager.EpisodeRepository;
}
[Fact]
public async Task SlugEditTest()
{
Episode episode = await _repository.Get(1);
Assert.Equal($"{TestSample.Get<Show>().Slug}-s1e1", episode.Slug);
Show show = new()
{
ID = episode.ShowID,
Slug = "new-slug"
};
await Repositories.LibraryManager.ShowRepository.Edit(show, false);
episode = await _repository.Get(1);
Assert.Equal("new-slug-s1e1", episode.Slug);
}
[Fact]
public async Task SeasonNumberEditTest()
{
Episode episode = await _repository.Get(1);
Assert.Equal($"{TestSample.Get<Show>().Slug}-s1e1", episode.Slug);
await _repository.Edit(new Episode
{
ID = 1,
SeasonNumber = 2
}, false);
episode = await _repository.Get(1);
Assert.Equal($"{TestSample.Get<Show>().Slug}-s2e1", episode.Slug);
}
[Fact]
public async Task EpisodeNumberEditTest()
{
Episode episode = await _repository.Get(1);
Assert.Equal($"{TestSample.Get<Show>().Slug}-s1e1", episode.Slug);
await _repository.Edit(new Episode
{
ID = 1,
EpisodeNumber = 2
}, false);
episode = await _repository.Get(1);
Assert.Equal($"{TestSample.Get<Show>().Slug}-s1e2", episode.Slug);
}
[Fact]
public async Task EpisodeCreationSlugTest()
{
Episode season = await _repository.Create(new Episode
{
ShowID = TestSample.Get<Show>().ID,
SeasonNumber = 2,
EpisodeNumber = 4
});
Assert.Equal($"{TestSample.Get<Show>().Slug}-s2e4", season.Slug);
}
// TODO absolute numbering tests
}
}

View File

@ -145,7 +145,7 @@ namespace Kyoo.Controllers
/// <returns>The <see cref="resource"/> parameter is returned.</returns>
private async Task<Episode> ValidateTracks(Episode resource)
{
resource.Tracks = await resource.Tracks.MapAsync((x, i) =>
resource.Tracks = await TaskUtils.DefaultIfNull(resource.Tracks?.MapAsync((x, i) =>
{
x.Episode = resource;
x.TrackIndex = resource.Tracks.Take(i).Count(y => x.Language == y.Language
@ -153,7 +153,7 @@ namespace Kyoo.Controllers
&& x.Codec == y.Codec
&& x.Type == y.Type);
return _tracks.Create(x);
}).ToListAsync();
}).ToListAsync());
return resource;
}
@ -161,13 +161,12 @@ namespace Kyoo.Controllers
protected override async Task Validate(Episode resource)
{
await base.Validate(resource);
resource.ExternalIDs = await resource.ExternalIDs.SelectAsync(async x =>
await resource.ExternalIDs.ForEachAsync(async x =>
{
x.Second = await _providers.CreateIfNotExists(x.Second);
x.SecondID = x.Second.ID;
_database.Entry(x.Second).State = EntityState.Detached;
return x;
}).ToListAsync();
});
}
/// <inheritdoc />