Checkpoint - changing PCs
This commit contains broken code
This commit is contained in:
parent
06914d1135
commit
616916548a
5 changed files with 128 additions and 45 deletions
|
|
@ -112,7 +112,7 @@ public class ReadingProfileServiceTest: AbstractDbTest
|
||||||
WidthOverride = 53,
|
WidthOverride = 53,
|
||||||
};
|
};
|
||||||
|
|
||||||
await rps.UpdateReadingProfileForSeries(user.Id, series.Id, dto);
|
await rps.UpdateImplicitReadingProfile(user.Id, series.Id, dto);
|
||||||
|
|
||||||
var profile = await UnitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(user.Id, series.Id);
|
var profile = await UnitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(user.Id, series.Id);
|
||||||
Assert.NotNull(profile);
|
Assert.NotNull(profile);
|
||||||
|
|
@ -145,7 +145,8 @@ public class ReadingProfileServiceTest: AbstractDbTest
|
||||||
lib.Series.Add(series2);
|
lib.Series.Add(series2);
|
||||||
|
|
||||||
var lib2 = new LibraryBuilder("Manga2").Build();
|
var lib2 = new LibraryBuilder("Manga2").Build();
|
||||||
var series3 = new SeriesBuilder("A Tropical Fish Yearns for Snow").WithLibraryId(lib2.Id).Build();
|
var series3 = new SeriesBuilder("A Tropical Fish Yearns for Snow").Build();
|
||||||
|
lib2.Series.Add(series3);
|
||||||
|
|
||||||
user.Libraries.Add(lib2);
|
user.Libraries.Add(lib2);
|
||||||
await UnitOfWork.CommitAsync();
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
@ -153,15 +154,15 @@ public class ReadingProfileServiceTest: AbstractDbTest
|
||||||
user.UserPreferences.DefaultReadingProfileId = profile3.Id;
|
user.UserPreferences.DefaultReadingProfileId = profile3.Id;
|
||||||
await UnitOfWork.CommitAsync();
|
await UnitOfWork.CommitAsync();
|
||||||
|
|
||||||
var p = await rps.GetReadingProfileForSeries(user.Id, series);
|
var p = await rps.GetReadingProfileForSeries(user.Id, series.Id);
|
||||||
Assert.NotNull(p);
|
Assert.NotNull(p);
|
||||||
Assert.Equal("Series Specific", p.Name);
|
Assert.Equal("Series Specific", p.Name);
|
||||||
|
|
||||||
p = await rps.GetReadingProfileForSeries(user.Id, series2);
|
p = await rps.GetReadingProfileForSeries(user.Id, series2.Id);
|
||||||
Assert.NotNull(p);
|
Assert.NotNull(p);
|
||||||
Assert.Equal("Library Specific", p.Name);
|
Assert.Equal("Library Specific", p.Name);
|
||||||
|
|
||||||
p = await rps.GetReadingProfileForSeries(user.Id, series3);
|
p = await rps.GetReadingProfileForSeries(user.Id, series3.Id);
|
||||||
Assert.NotNull(p);
|
Assert.NotNull(p);
|
||||||
Assert.Equal("Global", p.Name);
|
Assert.Equal("Global", p.Name);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,67 @@
|
||||||
|
#nullable enable
|
||||||
|
using System.Threading.Tasks;
|
||||||
using API.Data;
|
using API.Data;
|
||||||
|
using API.DTOs;
|
||||||
|
using API.Extensions;
|
||||||
|
using API.Services;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace API.Controllers;
|
namespace API.Controllers;
|
||||||
|
|
||||||
public class ReadingProfileController(ILogger<ReadingProfileController> logger, IUnitOfWork unitOfWork): BaseApiController
|
public class ReadingProfileController(ILogger<ReadingProfileController> logger, IUnitOfWork unitOfWork,
|
||||||
|
IReadingProfileService readingProfileService): BaseApiController
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the ReadingProfile that should be applied to the given series, walks up the tree.
|
||||||
|
/// Series -> Library -> Default
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("{seriesId}")]
|
||||||
|
public async Task<ActionResult<UserReadingProfileDto?>> GetProfileForSeries(int seriesId)
|
||||||
|
{
|
||||||
|
return Ok(await readingProfileService.GetReadingProfileForSeries(User.GetUserId(), seriesId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update, or create the given profile
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dto"></param>
|
||||||
|
/// <param name="seriesCtx">
|
||||||
|
/// Optionally, from which series the update is called.
|
||||||
|
/// If set, will delete the implicit reading profile if it exists
|
||||||
|
/// </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<ActionResult> UpdateReadingProfile([FromBody] UserReadingProfileDto dto, [FromQuery] int? seriesCtx)
|
||||||
|
{
|
||||||
|
if (seriesCtx.HasValue)
|
||||||
|
{
|
||||||
|
await readingProfileService.DeleteImplicitForSeries(User.GetUserId(), seriesCtx.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var success = await readingProfileService.UpdateReadingProfile(User.GetUserId(), dto);
|
||||||
|
if (!success) return BadRequest();
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the implicit reading profile for a series, creates one if none exists
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dto"></param>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost("series")]
|
||||||
|
public async Task<ActionResult> UpdateReadingProfileForSeries([FromBody] UserReadingProfileDto dto, [FromQuery] int seriesId)
|
||||||
|
{
|
||||||
|
var success = await readingProfileService.UpdateImplicitReadingProfile(User.GetUserId(), seriesId, dto);
|
||||||
|
if (!success) return BadRequest();
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,11 @@ 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.DTOs;
|
||||||
using API.Entities;
|
using API.Entities;
|
||||||
using API.Extensions.QueryExtensions;
|
using API.Extensions.QueryExtensions;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using AutoMapper.QueryableExtensions;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace API.Data.Repositories;
|
namespace API.Data.Repositories;
|
||||||
|
|
@ -22,8 +24,11 @@ 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<UserReadingProfileDto?> GetProfileDtoForSeries(int userId, int seriesId);
|
||||||
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId);
|
Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId);
|
||||||
|
Task<UserReadingProfileDto?> GetProfileDtoForLibrary(int userId, int libraryId);
|
||||||
Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None);
|
||||||
|
Task<UserReadingProfileDto?> GetProfileDto(int profileId);
|
||||||
|
|
||||||
void Add(AppUserReadingProfile readingProfile);
|
void Add(AppUserReadingProfile readingProfile);
|
||||||
void Update(AppUserReadingProfile readingProfile);
|
void Update(AppUserReadingProfile readingProfile);
|
||||||
|
|
@ -47,6 +52,14 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserReadingProfileDto?> GetProfileDtoForSeries(int userId, int seriesId)
|
||||||
|
{
|
||||||
|
return await context.AppUserReadingProfile
|
||||||
|
.Where(rp => rp.UserId == userId && rp.Series.Any(s => s.Id == seriesId))
|
||||||
|
.ProjectTo<UserReadingProfileDto>(mapper.ConfigurationProvider)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId)
|
public async Task<AppUserReadingProfile?> GetProfileForLibrary(int userId, int libraryId)
|
||||||
{
|
{
|
||||||
return await context.AppUserReadingProfile
|
return await context.AppUserReadingProfile
|
||||||
|
|
@ -54,6 +67,14 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<UserReadingProfileDto?> GetProfileDtoForLibrary(int userId, int libraryId)
|
||||||
|
{
|
||||||
|
return await context.AppUserReadingProfile
|
||||||
|
.Where(rp => rp.UserId == userId && rp.Libraries.Any(s => s.Id == libraryId))
|
||||||
|
.ProjectTo<UserReadingProfileDto>(mapper.ConfigurationProvider)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
public async Task<AppUserReadingProfile?> GetProfile(int profileId, ReadingProfileIncludes includes = ReadingProfileIncludes.None)
|
||||||
{
|
{
|
||||||
return await context.AppUserReadingProfile
|
return await context.AppUserReadingProfile
|
||||||
|
|
@ -61,6 +82,13 @@ public class AppUserReadingProfileRepository(DataContext context, IMapper mapper
|
||||||
.Includes(includes)
|
.Includes(includes)
|
||||||
.FirstOrDefaultAsync();
|
.FirstOrDefaultAsync();
|
||||||
}
|
}
|
||||||
|
public async Task<UserReadingProfileDto?> GetProfileDto(int profileId)
|
||||||
|
{
|
||||||
|
return await context.AppUserReadingProfile
|
||||||
|
.Where(rp => rp.Id == profileId)
|
||||||
|
.ProjectTo<UserReadingProfileDto>(mapper.ConfigurationProvider)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
public void Add(AppUserReadingProfile readingProfile)
|
public void Add(AppUserReadingProfile readingProfile)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -283,6 +283,14 @@ public class AutoMapperProfiles : Profile
|
||||||
opt =>
|
opt =>
|
||||||
opt.MapFrom(src => src.BookReaderLayoutMode));
|
opt.MapFrom(src => src.BookReaderLayoutMode));
|
||||||
|
|
||||||
|
CreateMap<AppUserReadingProfile, UserReadingProfileDto>()
|
||||||
|
.ForMember(dest => dest.BookReaderThemeName,
|
||||||
|
opt =>
|
||||||
|
opt.MapFrom(src => src.BookThemeName))
|
||||||
|
.ForMember(dest => dest.BookReaderLayoutMode,
|
||||||
|
opt =>
|
||||||
|
opt.MapFrom(src => src.BookReaderLayoutMode));
|
||||||
|
|
||||||
|
|
||||||
CreateMap<AppUserBookmark, BookmarkDto>();
|
CreateMap<AppUserBookmark, BookmarkDto>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ public interface IReadingProfileService
|
||||||
/// Series -> Library -> Default
|
/// Series -> Library -> Default
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
/// <param name="series"></param>
|
/// <param name="seriesId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<AppUserReadingProfile> GetReadingProfileForSeries(int userId, Series series);
|
Task<UserReadingProfileDto> GetReadingProfileForSeries(int userId, int seriesId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates, or adds a specific reading profile for a user
|
/// Updates, or adds a specific reading profile for a user
|
||||||
|
|
@ -32,15 +32,13 @@ public interface IReadingProfileService
|
||||||
Task<bool> UpdateReadingProfile(int userId, UserReadingProfileDto dto);
|
Task<bool> UpdateReadingProfile(int userId, UserReadingProfileDto dto);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates, or adds a specific reading profile for a user for a specific series.
|
/// Updates the implicit reading profile for a series, creates one if none exists
|
||||||
/// If the reading profile is not assigned to the given series (Library, Default fallback),
|
|
||||||
/// a new implicit reading profile is created
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="userId"></param>
|
/// <param name="userId"></param>
|
||||||
/// <param name="seriesId"></param>
|
/// <param name="seriesId"></param>
|
||||||
/// <param name="dto"></param>
|
/// <param name="dto"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> UpdateReadingProfileForSeries(int userId, int seriesId, UserReadingProfileDto dto);
|
Task<bool> UpdateImplicitReadingProfile(int userId, int seriesId, UserReadingProfileDto dto);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deletes the implicit reading profile for a given series, if it exists
|
/// Deletes the implicit reading profile for a given series, if it exists
|
||||||
|
|
@ -62,21 +60,24 @@ public interface IReadingProfileService
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileService
|
public class ReadingProfileService(IUnitOfWork unitOfWork, ILocalizationService localizationService): IReadingProfileService
|
||||||
{
|
{
|
||||||
|
|
||||||
public async Task<AppUserReadingProfile> GetReadingProfileForSeries(int userId, Series series)
|
public async Task<UserReadingProfileDto> GetReadingProfileForSeries(int userId, int seriesId)
|
||||||
{
|
{
|
||||||
var seriesProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(userId, series.Id);
|
var seriesProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfileDtoForSeries(userId, seriesId);
|
||||||
if (seriesProfile != null) return seriesProfile;
|
if (seriesProfile != null) return seriesProfile;
|
||||||
|
|
||||||
var libraryProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfileForLibrary(userId, series.Id);
|
var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
||||||
|
if (series == null) throw new KavitaException(await localizationService.Translate(userId, "series-doesnt-exist"));
|
||||||
|
|
||||||
|
var libraryProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfileDtoForLibrary(userId, series.LibraryId);
|
||||||
if (libraryProfile != null) return libraryProfile;
|
if (libraryProfile != null) return libraryProfile;
|
||||||
|
|
||||||
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||||
if (user == null) throw new UnauthorizedAccessException();
|
if (user == null) throw new UnauthorizedAccessException();
|
||||||
|
|
||||||
return await unitOfWork.AppUserReadingProfileRepository.GetProfile(user.UserPreferences.DefaultReadingProfileId);
|
return await unitOfWork.AppUserReadingProfileRepository.GetProfileDto(user.UserPreferences.DefaultReadingProfileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UpdateReadingProfile(int userId, UserReadingProfileDto dto)
|
public async Task<bool> UpdateReadingProfile(int userId, UserReadingProfileDto dto)
|
||||||
|
|
@ -94,45 +95,32 @@ public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileServi
|
||||||
return await unitOfWork.CommitAsync();
|
return await unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> UpdateReadingProfileForSeries(int userId, int seriesId, UserReadingProfileDto dto)
|
public async Task<bool> UpdateImplicitReadingProfile(int userId, int seriesId, UserReadingProfileDto dto)
|
||||||
{
|
{
|
||||||
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(dto.Id);
|
var existingProfile = await unitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(userId, seriesId);
|
||||||
|
|
||||||
// TODO: Rewrite
|
// Series already had an implicit profile, update it
|
||||||
var isNew = false;
|
if (existingProfile is {Implicit: true})
|
||||||
if (existingProfile == null || existingProfile.Series.All(s => s.Id != seriesId))
|
|
||||||
{
|
|
||||||
var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
|
||||||
if (series == null) throw new KeyNotFoundException();
|
|
||||||
|
|
||||||
existingProfile = new AppUserReadingProfileBuilder(userId)
|
|
||||||
.WithSeries(series)
|
|
||||||
.WithImplicit(true)
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
isNew = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (existingProfile.UserId != userId) return false;
|
|
||||||
|
|
||||||
UpdateReaderProfileFields(existingProfile, dto);
|
|
||||||
|
|
||||||
if (isNew)
|
|
||||||
{
|
|
||||||
unitOfWork.AppUserReadingProfileRepository.Add(existingProfile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
UpdateReaderProfileFields(existingProfile, dto);
|
||||||
unitOfWork.AppUserReadingProfileRepository.Update(existingProfile);
|
unitOfWork.AppUserReadingProfileRepository.Update(existingProfile);
|
||||||
|
return await unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var series = await unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId) ?? throw new KeyNotFoundException();
|
||||||
|
existingProfile = new AppUserReadingProfileBuilder(userId)
|
||||||
|
.WithSeries(series)
|
||||||
|
.WithImplicit(true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
unitOfWork.AppUserReadingProfileRepository.Add(existingProfile);
|
||||||
return await unitOfWork.CommitAsync();
|
return await unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task DeleteImplicitForSeries(int userId, int seriesId)
|
public async Task DeleteImplicitForSeries(int userId, int seriesId)
|
||||||
{
|
{
|
||||||
var profile = await unitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(userId, seriesId);
|
var profile = await unitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(userId, seriesId);
|
||||||
if (profile == null) return;
|
if (profile == null) throw new KavitaException(await localizationService.Translate(userId, "profile-doesnt-exist"));
|
||||||
|
|
||||||
if (!profile.Implicit) return;
|
if (!profile.Implicit) return;
|
||||||
|
|
||||||
|
|
@ -144,7 +132,7 @@ public class ReadingProfileService(IUnitOfWork unitOfWork): IReadingProfileServi
|
||||||
public async Task DeleteReadingProfile(int userId, int profileId)
|
public async Task DeleteReadingProfile(int userId, int profileId)
|
||||||
{
|
{
|
||||||
var profile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(profileId);
|
var profile = await unitOfWork.AppUserReadingProfileRepository.GetProfile(profileId);
|
||||||
if (profile == null) throw new KeyNotFoundException();
|
if (profile == null) throw new KavitaException(await localizationService.Translate(userId, "profile-doesnt-exist"));
|
||||||
|
|
||||||
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.UserPreferences);
|
var user = await unitOfWork.UserRepository.GetUserByIdAsync(userId, AppUserIncludes.UserPreferences);
|
||||||
if (user == null || profile.UserId != userId) throw new UnauthorizedAccessException();
|
if (user == null || profile.UserId != userId) throw new UnauthorizedAccessException();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue