Release Polish 3 (#3359)
This commit is contained in:
parent
dd3dec269f
commit
f812f61001
34 changed files with 211 additions and 134 deletions
|
@ -42,10 +42,15 @@ public class PersonController : BaseApiController
|
|||
return Ok(await _unitOfWork.PersonRepository.GetPersonDtoByName(name, User.GetUserId()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all roles for a Person
|
||||
/// </summary>
|
||||
/// <param name="personId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("roles")]
|
||||
public async Task<ActionResult<IEnumerable<PersonRole>>> GetRolesForPersonByName(string name)
|
||||
public async Task<ActionResult<IEnumerable<PersonRole>>> GetRolesForPersonByName(int personId)
|
||||
{
|
||||
return Ok(await _unitOfWork.PersonRepository.GetRolesForPersonByName(name, User.GetUserId()));
|
||||
return Ok(await _unitOfWork.PersonRepository.GetRolesForPersonByName(personId, User.GetUserId()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -490,23 +490,27 @@ public class UploadController : BaseApiController
|
|||
[HttpPost("person")]
|
||||
public async Task<ActionResult> UploadPersonCoverImageFromUrl(UploadFileDto uploadFileDto)
|
||||
{
|
||||
// Check if Url is non-empty, request the image and place in temp, then ask image service to handle it.
|
||||
// See if we can do this all in memory without touching underlying system
|
||||
if (string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
return BadRequest(await _localizationService.Translate(User.GetUserId(), "url-required"));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var person = await _unitOfWork.PersonRepository.GetPersonById(uploadFileDto.Id);
|
||||
if (person == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "person-doesnt-exist"));
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetPersonFormat(uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
if (!string.IsNullOrEmpty(uploadFileDto.Url))
|
||||
{
|
||||
person.CoverImage = filePath;
|
||||
person.CoverImageLocked = true;
|
||||
var filePath = await CreateThumbnail(uploadFileDto, $"{ImageService.GetPersonFormat(uploadFileDto.Id)}");
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
person.CoverImage = filePath;
|
||||
person.CoverImageLocked = true;
|
||||
_imageService.UpdateColorScape(person);
|
||||
_unitOfWork.PersonRepository.Update(person);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
person.CoverImage = string.Empty;
|
||||
person.CoverImageLocked = false;
|
||||
_imageService.UpdateColorScape(person);
|
||||
_unitOfWork.PersonRepository.Update(person);
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ public interface IPersonRepository
|
|||
|
||||
Task<string> GetCoverImageAsync(int personId);
|
||||
Task<string?> GetCoverImageByNameAsync(string name);
|
||||
Task<IEnumerable<PersonRole>> GetRolesForPersonByName(string name, int userId);
|
||||
Task<IEnumerable<PersonRole>> GetRolesForPersonByName(int personId, int userId);
|
||||
Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams);
|
||||
Task<Person?> GetPersonById(int personId);
|
||||
Task<PersonDto?> GetPersonDtoByName(string name, int userId);
|
||||
|
@ -145,18 +145,28 @@ public class PersonRepository : IPersonRepository
|
|||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<PersonRole>> GetRolesForPersonByName(string name, int userId)
|
||||
public async Task<IEnumerable<PersonRole>> GetRolesForPersonByName(int personId, int userId)
|
||||
{
|
||||
// TODO: This will need to check both series and chapters (in cases where komf only updates series)
|
||||
var normalized = name.ToNormalized();
|
||||
var ageRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
|
||||
return await _context.Person
|
||||
.Where(p => p.NormalizedName == normalized)
|
||||
// Query roles from ChapterPeople
|
||||
var chapterRoles = await _context.Person
|
||||
.Where(p => p.Id == personId)
|
||||
.RestrictAgainstAgeRestriction(ageRating)
|
||||
.SelectMany(p => p.ChapterPeople.Select(cp => cp.Role))
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
// Query roles from SeriesMetadataPeople
|
||||
var seriesRoles = await _context.Person
|
||||
.Where(p => p.Id == personId)
|
||||
.RestrictAgainstAgeRestriction(ageRating)
|
||||
.SelectMany(p => p.SeriesMetadataPeople.Select(smp => smp.Role))
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
// Combine and return distinct roles
|
||||
return chapterRoles.Union(seriesRoles).Distinct();
|
||||
}
|
||||
|
||||
public async Task<PagedList<BrowsePersonDto>> GetAllWritersAndSeriesCount(int userId, UserParams userParams)
|
||||
|
|
|
@ -1046,8 +1046,6 @@ public class SeriesRepository : ISeriesRepository
|
|||
.Select(u => u.CollapseSeriesRelationships)
|
||||
.SingleOrDefaultAsync();
|
||||
|
||||
|
||||
|
||||
query ??= _context.Series
|
||||
.AsNoTracking();
|
||||
|
||||
|
@ -1064,7 +1062,6 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
query = ApplyWantToReadFilter(filter, query, userId);
|
||||
|
||||
|
||||
query = await ApplyCollectionFilter(filter, query, userId, userRating);
|
||||
|
||||
|
||||
|
@ -1136,6 +1133,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
var seriesIds = _context.AppUser.Where(u => u.Id == userId)
|
||||
.SelectMany(u => u.WantToRead)
|
||||
.Select(s => s.SeriesId);
|
||||
|
||||
if (bool.Parse(wantToReadStmt.Value))
|
||||
{
|
||||
query = query.Where(s => seriesIds.Contains(s.Id));
|
||||
|
@ -1152,6 +1150,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
var filterIncludeLibs = new List<int>();
|
||||
var filterExcludeLibs = new List<int>();
|
||||
|
||||
if (filter.Statements != null)
|
||||
{
|
||||
foreach (var stmt in filter.Statements.Where(stmt => stmt.Field == FilterField.Libraries))
|
||||
|
@ -1993,17 +1992,25 @@ public class SeriesRepository : ISeriesRepository
|
|||
public async Task<PagedList<SeriesDto>> GetWantToReadForUserV2Async(int userId, UserParams userParams, FilterV2Dto filter)
|
||||
{
|
||||
var libraryIds = await _context.Library.GetUserLibraries(userId).ToListAsync();
|
||||
var query = _context.AppUser
|
||||
var seriesIds = await _context.AppUser
|
||||
.Where(user => user.Id == userId)
|
||||
.SelectMany(u => u.WantToRead)
|
||||
.Where(s => libraryIds.Contains(s.Series.LibraryId))
|
||||
.Select(w => w.Series)
|
||||
.Select(w => w.Series.Id)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
var query = await CreateFilteredSearchQueryableV2(userId, filter, QueryContext.None);
|
||||
|
||||
// Apply the Want to Read filtering
|
||||
query = query.Where(s => seriesIds.Contains(s.Id));
|
||||
|
||||
var retSeries = query
|
||||
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking();
|
||||
|
||||
var filteredQuery = await CreateFilteredSearchQueryableV2(userId, filter, QueryContext.None, query);
|
||||
|
||||
return await PagedList<SeriesDto>.CreateAsync(filteredQuery.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider), userParams.PageNumber, userParams.PageSize);
|
||||
return await PagedList<SeriesDto>.CreateAsync(retSeries, userParams.PageNumber, userParams.PageSize);
|
||||
}
|
||||
|
||||
public async Task<IList<Series>> GetWantToReadForUserAsync(int userId)
|
||||
|
|
|
@ -259,8 +259,7 @@ public static class SeriesFilter
|
|||
.Where(p => p != null && p.AppUserId == userId)
|
||||
.Sum(p => p != null ? (p.PagesRead * 1.0f / s.Pages) : 0) * 100
|
||||
})
|
||||
.AsSplitQuery()
|
||||
.AsEnumerable();
|
||||
.AsSplitQuery();
|
||||
|
||||
switch (comparison)
|
||||
{
|
||||
|
|
|
@ -79,7 +79,6 @@ public static class QueryableExtensions
|
|||
.Include(l => l.AppUsers)
|
||||
.Where(lib => lib.AppUsers.Any(user => user.Id == userId))
|
||||
.IsRestricted(queryContext)
|
||||
.AsNoTracking()
|
||||
.AsSplitQuery()
|
||||
.Select(lib => lib.Id);
|
||||
}
|
||||
|
|
|
@ -585,6 +585,7 @@ public class ImageService : IImageService
|
|||
/// <inheritdoc />
|
||||
public string CreateThumbnailFromBase64(string encodedImage, string fileName, EncodeFormat encodeFormat, int thumbnailWidth = ThumbnailWidth)
|
||||
{
|
||||
// TODO: This code has no concept of cropping nor Thumbnail Size
|
||||
try
|
||||
{
|
||||
using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), thumbnailWidth);
|
||||
|
|
|
@ -334,7 +334,10 @@ public class SeriesService : ISeriesService
|
|||
private async Task HandlePeopleUpdateAsync(SeriesMetadata metadata, ICollection<PersonDto> peopleDtos, PersonRole role)
|
||||
{
|
||||
// Normalize all names from the DTOs
|
||||
var normalizedNames = peopleDtos.Select(p => Parser.Normalize(p.Name)).ToList();
|
||||
var normalizedNames = peopleDtos
|
||||
.Select(p => Parser.Normalize(p.Name))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
// Bulk select people who already exist in the database
|
||||
var existingPeople = await _unitOfWork.PersonRepository.GetPeopleByNames(normalizedNames);
|
||||
|
|
|
@ -83,6 +83,7 @@ public class TaskScheduler : ITaskScheduler
|
|||
|
||||
public static readonly ImmutableArray<string> ScanTasks =
|
||||
["ScannerService", "ScanLibrary", "ScanLibraries", "ScanFolder", "ScanSeries"];
|
||||
private static readonly ImmutableArray<string> NonCronOptions = ["disabled", "daily", "weekly"];
|
||||
|
||||
private static readonly Random Rnd = new Random();
|
||||
|
||||
|
@ -122,10 +123,10 @@ public class TaskScheduler : ITaskScheduler
|
|||
public async Task ScheduleTasks()
|
||||
{
|
||||
_logger.LogInformation("Scheduling reoccurring tasks");
|
||||
var nonCronOptions = new List<string>(["disabled", "daily", "weekly"]);
|
||||
|
||||
|
||||
var setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).Value;
|
||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
||||
if (IsInvalidCronSetting(setting))
|
||||
{
|
||||
_logger.LogError("Scan Task has invalid cron, defaulting to Daily");
|
||||
RecurringJob.AddOrUpdate(ScanLibrariesTaskId, () => ScanLibraries(false),
|
||||
|
@ -141,9 +142,9 @@ public class TaskScheduler : ITaskScheduler
|
|||
|
||||
|
||||
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Value;
|
||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
||||
if (IsInvalidCronSetting(setting))
|
||||
{
|
||||
_logger.LogError("Backup Task has invalid cron, defaulting to Daily");
|
||||
_logger.LogError("Backup Task has invalid cron, defaulting to Weekly");
|
||||
RecurringJob.AddOrUpdate(BackupTaskId, () => _backupService.BackupDatabase(),
|
||||
Cron.Weekly, RecurringJobOptions);
|
||||
}
|
||||
|
@ -161,18 +162,18 @@ public class TaskScheduler : ITaskScheduler
|
|||
}
|
||||
|
||||
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskCleanup)).Value;
|
||||
if (setting == null || (!nonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting)))
|
||||
{
|
||||
_logger.LogDebug("Scheduling Cleanup Task for {Setting}", setting);
|
||||
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
||||
CronConverter.ConvertToCronNotation(setting), RecurringJobOptions);
|
||||
}
|
||||
else
|
||||
if (IsInvalidCronSetting(setting))
|
||||
{
|
||||
_logger.LogError("Cleanup Task has invalid cron, defaulting to Daily");
|
||||
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
||||
Cron.Daily, RecurringJobOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("Scheduling Cleanup Task for {Setting}", setting);
|
||||
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(),
|
||||
CronConverter.ConvertToCronNotation(setting), RecurringJobOptions);
|
||||
}
|
||||
|
||||
|
||||
RecurringJob.AddOrUpdate(RemoveFromWantToReadTaskId, () => _cleanupService.CleanupWantToRead(),
|
||||
|
@ -186,6 +187,11 @@ public class TaskScheduler : ITaskScheduler
|
|||
await ScheduleKavitaPlusTasks();
|
||||
}
|
||||
|
||||
private static bool IsInvalidCronSetting(string setting)
|
||||
{
|
||||
return setting == null || (!NonCronOptions.Contains(setting) && !CronHelper.IsValidCron(setting));
|
||||
}
|
||||
|
||||
public async Task ScheduleKavitaPlusTasks()
|
||||
{
|
||||
// KavitaPlus based (needs license check)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue