Some unit tests, names and small fixes
This commit is contained in:
parent
23c4a451b4
commit
06914d1135
10 changed files with 332 additions and 13 deletions
174
API.Tests/Services/ReadingProfileServiceTest.cs
Normal file
174
API.Tests/Services/ReadingProfileServiceTest.cs
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using API.Data.Repositories;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Entities;
|
||||||
|
using API.Entities.Enums;
|
||||||
|
using API.Helpers.Builders;
|
||||||
|
using API.Services;
|
||||||
|
using Kavita.Common;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace API.Tests.Services;
|
||||||
|
|
||||||
|
public class ReadingProfileServiceTest: AbstractDbTest
|
||||||
|
{
|
||||||
|
|
||||||
|
public async Task<(IReadingProfileService, AppUser, Library, Series)> Setup()
|
||||||
|
{
|
||||||
|
var user = new AppUserBuilder("amelia", "amelia@localhost").Build();
|
||||||
|
Context.AppUser.Add(user);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
var series = new SeriesBuilder("Spice and Wolf").Build();
|
||||||
|
|
||||||
|
var library = new LibraryBuilder("Manga")
|
||||||
|
.WithSeries(series)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
user.Libraries.Add(library);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
var rps = new ReadingProfileService(UnitOfWork);
|
||||||
|
user = await UnitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.UserPreferences);
|
||||||
|
|
||||||
|
return (rps, user, library, series);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task DeleteImplicitSeriesReadingProfile()
|
||||||
|
{
|
||||||
|
await ResetDb();
|
||||||
|
var (rps, user, library, series) = await Setup();
|
||||||
|
|
||||||
|
var series2 = new SeriesBuilder("Rainbows After Storms").Build();
|
||||||
|
library.Series.Add(series2);
|
||||||
|
|
||||||
|
var profile = new AppUserReadingProfileBuilder(user.Id)
|
||||||
|
.WithImplicit(true)
|
||||||
|
.WithSeries(series)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var profile2 = new AppUserReadingProfileBuilder(user.Id)
|
||||||
|
.WithSeries(series2)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
UnitOfWork.AppUserReadingProfileRepository.Add(profile);
|
||||||
|
UnitOfWork.AppUserReadingProfileRepository.Add(profile2);
|
||||||
|
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
await rps.DeleteImplicitForSeries(user.Id, series.Id);
|
||||||
|
await rps.DeleteImplicitForSeries(user.Id, series2.Id);
|
||||||
|
|
||||||
|
profile = await UnitOfWork.AppUserReadingProfileRepository.GetProfile(profile.Id);
|
||||||
|
Assert.NotNull(profile);
|
||||||
|
Assert.Empty(profile.Series);
|
||||||
|
|
||||||
|
profile2 = await UnitOfWork.AppUserReadingProfileRepository.GetProfile(profile2.Id);
|
||||||
|
Assert.NotNull(profile2);
|
||||||
|
Assert.NotEmpty(profile2.Series);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CantDeleteDefaultReadingProfile()
|
||||||
|
{
|
||||||
|
await ResetDb();
|
||||||
|
var (rps, user, _, _) = await Setup();
|
||||||
|
|
||||||
|
var profile = new AppUserReadingProfileBuilder(user.Id).Build();
|
||||||
|
Context.AppUserReadingProfile.Add(profile);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
user.UserPreferences.DefaultReadingProfileId = profile.Id;
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
await Assert.ThrowsAsync<KavitaException>(async () =>
|
||||||
|
{
|
||||||
|
await rps.DeleteReadingProfile(user.Id, profile.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
var profile2 = new AppUserReadingProfileBuilder(user.Id).Build();
|
||||||
|
Context.AppUserReadingProfile.Add(profile2);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
await rps.DeleteReadingProfile(user.Id, profile2.Id);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
var allProfiles = await Context.AppUserReadingProfile.ToListAsync();
|
||||||
|
Assert.Single(allProfiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CreateImplicitSeriesReadingProfile()
|
||||||
|
{
|
||||||
|
await ResetDb();
|
||||||
|
var (rps, user, _, series) = await Setup();
|
||||||
|
|
||||||
|
var dto = new UserReadingProfileDto
|
||||||
|
{
|
||||||
|
ReaderMode = ReaderMode.Webtoon,
|
||||||
|
ScalingOption = ScalingOption.FitToHeight,
|
||||||
|
WidthOverride = 53,
|
||||||
|
};
|
||||||
|
|
||||||
|
await rps.UpdateReadingProfileForSeries(user.Id, series.Id, dto);
|
||||||
|
|
||||||
|
var profile = await UnitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(user.Id, series.Id);
|
||||||
|
Assert.NotNull(profile);
|
||||||
|
Assert.Contains(profile.Series, s => s.Id == series.Id);
|
||||||
|
Assert.True(profile.Implicit);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GetCorrectProfile()
|
||||||
|
{
|
||||||
|
await ResetDb();
|
||||||
|
var (rps, user, lib, series) = await Setup();
|
||||||
|
|
||||||
|
var profile = new AppUserReadingProfileBuilder(user.Id)
|
||||||
|
.WithSeries(series)
|
||||||
|
.WithName("Series Specific")
|
||||||
|
.Build();
|
||||||
|
var profile2 = new AppUserReadingProfileBuilder(user.Id)
|
||||||
|
.WithLibrary(lib)
|
||||||
|
.WithName("Library Specific")
|
||||||
|
.Build();
|
||||||
|
var profile3 = new AppUserReadingProfileBuilder(user.Id)
|
||||||
|
.WithName("Global")
|
||||||
|
.Build();
|
||||||
|
Context.AppUserReadingProfile.Add(profile);
|
||||||
|
Context.AppUserReadingProfile.Add(profile2);
|
||||||
|
Context.AppUserReadingProfile.Add(profile3);
|
||||||
|
|
||||||
|
var series2 = new SeriesBuilder("Rainbows After Storms").Build();
|
||||||
|
lib.Series.Add(series2);
|
||||||
|
|
||||||
|
var lib2 = new LibraryBuilder("Manga2").Build();
|
||||||
|
var series3 = new SeriesBuilder("A Tropical Fish Yearns for Snow").WithLibraryId(lib2.Id).Build();
|
||||||
|
|
||||||
|
user.Libraries.Add(lib2);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
user.UserPreferences.DefaultReadingProfileId = profile3.Id;
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
|
var p = await rps.GetReadingProfileForSeries(user.Id, series);
|
||||||
|
Assert.NotNull(p);
|
||||||
|
Assert.Equal("Series Specific", p.Name);
|
||||||
|
|
||||||
|
p = await rps.GetReadingProfileForSeries(user.Id, series2);
|
||||||
|
Assert.NotNull(p);
|
||||||
|
Assert.Equal("Library Specific", p.Name);
|
||||||
|
|
||||||
|
p = await rps.GetReadingProfileForSeries(user.Id, series3);
|
||||||
|
Assert.NotNull(p);
|
||||||
|
Assert.Equal("Global", p.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ResetDb()
|
||||||
|
{
|
||||||
|
Context.AppUserReadingProfile.RemoveRange(Context.AppUserReadingProfile);
|
||||||
|
await UnitOfWork.CommitAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,8 @@ public sealed record UserReadingProfileDto
|
||||||
|
|
||||||
public int UserId { get; init; }
|
public int UserId { get; init; }
|
||||||
|
|
||||||
|
public string Name { get; init; }
|
||||||
|
|
||||||
/// <inheritdoc cref="AppUserReadingProfile.Implicit"/>
|
/// <inheritdoc cref="AppUserReadingProfile.Implicit"/>
|
||||||
public bool Implicit { get; set; } = false;
|
public bool Implicit { get; set; } = false;
|
||||||
|
|
||||||
|
|
@ -61,6 +63,9 @@ public sealed record UserReadingProfileDto
|
||||||
[Required]
|
[Required]
|
||||||
public bool AllowAutomaticWebtoonReaderDetection { get; set; }
|
public bool AllowAutomaticWebtoonReaderDetection { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="AppUserReadingProfile.WidthOverride"/>
|
||||||
|
public int? WidthOverride { get; set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region EpubReader
|
#region EpubReader
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
namespace API.Data.Migrations
|
namespace API.Data.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(DataContext))]
|
[DbContext(typeof(DataContext))]
|
||||||
[Migration("20250514215429_AppUserReadingProfiles")]
|
[Migration("20250515215234_AppUserReadingProfiles")]
|
||||||
partial class AppUserReadingProfiles
|
partial class AppUserReadingProfiles
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -672,6 +672,12 @@ namespace API.Data.Migrations
|
||||||
b.Property<int>("LayoutMode")
|
b.Property<int>("LayoutMode")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("PageSplitOption")
|
b.Property<int>("PageSplitOption")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
|
@ -23,6 +23,8 @@ namespace API.Data.Migrations
|
||||||
{
|
{
|
||||||
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
.Annotation("Sqlite:Autoincrement", true),
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
NormalizedName = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
UserId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
ReadingDirection = table.Column<int>(type: "INTEGER", nullable: false),
|
ReadingDirection = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
ScalingOption = table.Column<int>(type: "INTEGER", nullable: false),
|
ScalingOption = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
|
@ -669,6 +669,12 @@ namespace API.Data.Migrations
|
||||||
b.Property<int>("LayoutMode")
|
b.Property<int>("LayoutMode")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("NormalizedName")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
b.Property<int>("PageSplitOption")
|
b.Property<int>("PageSplitOption")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,29 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
|
using API.Extensions.QueryExtensions;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace API.Data.Repositories;
|
namespace API.Data.Repositories;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ReadingProfileIncludes
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Series = 1 << 1,
|
||||||
|
Library = 1 << 2
|
||||||
|
}
|
||||||
|
|
||||||
public interface IAppUserReadingProfileRepository
|
public interface IAppUserReadingProfileRepository
|
||||||
{
|
{
|
||||||
Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId);
|
Task<IList<AppUserReadingProfile>> GetProfilesForUser(int userId);
|
||||||
Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId);
|
Task<AppUserReadingProfile?> GetProfileForSeries(int userId, int seriesId);
|
||||||
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId);
|
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId);
|
||||||
Task<AppUserReadingProfile?> GetProfile(int profileId);
|
Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||||
|
|
||||||
void Add(AppUserReadingProfile readingProfile);
|
void Add(AppUserReadingProfile readingProfile);
|
||||||
void Update(AppUserReadingProfile readingProfile);
|
void Update(AppUserReadingProfile readingProfile);
|
||||||
|
|
@ -44,10 +54,11 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<AppUserReadingProfile?> GetProfile(int profileId)
|
public async Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
||||||
{
|
{
|
||||||
return await context.AppUserReadingProfile
|
return await context.AppUserReadingProfile
|
||||||
.Where(rp => rp.Id == profileId)
|
.Where(rp => rp.Id == profileId)
|
||||||
|
.Includes(includes)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@ public class AppUserReadingProfile
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string NormalizedName { get; set; }
|
||||||
|
|
||||||
public int UserId { get; set; }
|
public int UserId { get; set; }
|
||||||
public AppUser User { get; set; }
|
public AppUser User { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -342,4 +342,20 @@ public static class IncludesExtensions
|
||||||
|
|
||||||
return queryable;
|
return queryable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IQueryable<AppUserReadingProfile> Includes(this IQueryable<AppUserReadingProfile> queryable, ReadingProfileIncludes includeFlags)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (includeFlags.HasFlag(ReadingProfileIncludes.Series))
|
||||||
|
{
|
||||||
|
queryable = queryable.Include(r => r.Series);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includeFlags.HasFlag(ReadingProfileIncludes.Library))
|
||||||
|
{
|
||||||
|
queryable = queryable.Include(r => r.Libraries);
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
48
API/Helpers/Builders/AppUserReadingProfileBuilder.cs
Normal file
48
API/Helpers/Builders/AppUserReadingProfileBuilder.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
using API.Entities;
|
||||||
|
using API.Extensions;
|
||||||
|
|
||||||
|
namespace API.Helpers.Builders;
|
||||||
|
|
||||||
|
public class AppUserReadingProfileBuilder
|
||||||
|
{
|
||||||
|
private readonly AppUserReadingProfile _profile;
|
||||||
|
|
||||||
|
public AppUserReadingProfile Build() => _profile;
|
||||||
|
|
||||||
|
public AppUserReadingProfileBuilder(int userId)
|
||||||
|
{
|
||||||
|
_profile = new AppUserReadingProfile
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
Series = [],
|
||||||
|
Libraries = [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUserReadingProfileBuilder WithSeries(Series series)
|
||||||
|
{
|
||||||
|
_profile.Series.Add(series);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUserReadingProfileBuilder WithLibrary(Library library)
|
||||||
|
{
|
||||||
|
_profile.Libraries.Add(library);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUserReadingProfileBuilder WithImplicit(bool b)
|
||||||
|
{
|
||||||
|
_profile.Implicit = b;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppUserReadingProfileBuilder WithName(string name)
|
||||||
|
{
|
||||||
|
_profile.Name = name;
|
||||||
|
_profile.NormalizedName = name.ToNormalized();
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
|
using API.Data.Repositories;
|
||||||
using API.DTOs;
|
using API.DTOs;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
|
using API.Extensions;
|
||||||
|
using API.Helpers.Builders;
|
||||||
|
using Kavita.Common;
|
||||||
|
|
||||||
namespace API.Services;
|
namespace API.Services;
|
||||||
|
|
||||||
|
|
@ -45,6 +50,16 @@ public interface IReadingProfileService
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task DeleteImplicitForSeries(int userId, int seriesId);
|
Task DeleteImplicitForSeries(int userId, int seriesId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a given profile for a user
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="profileId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="UnauthorizedAccessException"></exception>
|
||||||
|
/// <exception cref="KavitaException">The default profile for the user cannot be deleted</exception>
|
||||||
|
Task DeleteReadingProfile(int userId, int profileId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileService
|
public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileService
|
||||||
|
|
@ -69,10 +84,7 @@ public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileServi
|
||||||
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(dto.Id);
|
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(dto.Id);
|
||||||
if (existingProfile == null)
|
if (existingProfile == null)
|
||||||
{
|
{
|
||||||
existingProfile = new AppUserReadingProfile
|
existingProfile = new AppUserReadingProfileBuilder(userId).Build();
|
||||||
{
|
|
||||||
UserId = userId,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingProfile.UserId != userId) return false;
|
if (existingProfile.UserId != userId) return false;
|
||||||
|
|
@ -86,19 +98,34 @@ public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileServi
|
||||||
{
|
{
|
||||||
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(dto.Id);
|
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(dto.Id);
|
||||||
|
|
||||||
|
// TODO: Rewrite
|
||||||
|
var isNew = false;
|
||||||
if (existingProfile == null || existingProfile.Series.All(s => s.Id != seriesId))
|
if (existingProfile == null || existingProfile.Series.All(s => s.Id != seriesId))
|
||||||
{
|
{
|
||||||
existingProfile = new AppUserReadingProfile
|
var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
||||||
{
|
if (series == null) throw new KeyNotFoundException();
|
||||||
Implicit = true,
|
|
||||||
UserId = userId,
|
existingProfile = new AppUserReadingProfileBuilder(userId)
|
||||||
};
|
.WithSeries(series)
|
||||||
|
.WithImplicit(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
isNew = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingProfile.UserId != userId) return false;
|
if (existingProfile.UserId != userId) return false;
|
||||||
|
|
||||||
UpdateReaderProfileFields(existingProfile, dto);
|
UpdateReaderProfileFields(existingProfile, dto);
|
||||||
unitOfWork.AppUserReadingProfileRepository.Update(existingProfile);
|
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
unitOfWork.AppUserReadingProfileRepository.Add(existingProfile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unitOfWork.AppUserReadingProfileRepository.Update(existingProfile);
|
||||||
|
}
|
||||||
|
|
||||||
return await unitOfWork.CommitAsync();
|
return await unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,12 +136,33 @@ public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileServi
|
||||||
|
|
||||||
if (!profile.Implicit) return;
|
if (!profile.Implicit) return;
|
||||||
|
|
||||||
|
profile.Series = profile.Series.Where(s => s.Id != seriesId).ToList();
|
||||||
|
|
||||||
|
await unitOfWork.CommitAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteReadingProfile(int userId, int profileId)
|
||||||
|
{
|
||||||
|
var profile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(profileId);
|
||||||
|
if (profile == null) throw new KeyNotFoundException();
|
||||||
|
|
||||||
|
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.UserPreferences);
|
||||||
|
if (user == null || profile.UserId != userId) throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
|
if (user.UserPreferences.DefaultReadingProfileId == profileId) throw new KavitaException("cant-delete-default-profile");
|
||||||
|
|
||||||
unitOfWork.AppUserReadingProfileRepository.Remove(profile);
|
unitOfWork.AppUserReadingProfileRepository.Remove(profile);
|
||||||
await unitOfWork.CommitAsync();
|
await unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateReaderProfileFields(AppUserReadingProfile existingProfile, UserReadingProfileDto dto)
|
private static void UpdateReaderProfileFields(AppUserReadingProfile existingProfile, UserReadingProfileDto dto)
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(dto.Name) && existingProfile.NormalizedName != dto.Name.ToNormalized())
|
||||||
|
{
|
||||||
|
existingProfile.Name = dto.Name;
|
||||||
|
existingProfile.NormalizedName = dto.Name.ToNormalized();
|
||||||
|
}
|
||||||
|
|
||||||
// Manga Reader
|
// Manga Reader
|
||||||
existingProfile.ReadingDirection = dto.ReadingDirection;
|
existingProfile.ReadingDirection = dto.ReadingDirection;
|
||||||
existingProfile.ScalingOption = dto.ScalingOption;
|
existingProfile.ScalingOption = dto.ScalingOption;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue