.NET 7 + Spring Cleaning (#1677)
* Updated to net7.0 * Updated GA to .net 7 * Updated System.IO.Abstractions to use New factory. * Converted Regex into SourceGenerator in Parser. * Updated more regex to source generators. * Enabled Nullability and more regex changes throughout codebase. * Parser is 100% GeneratedRegexified * Lots of nullability code * Enabled nullability for all repositories. * Fixed another unit test * Refactored some code around and took care of some todos. * Updating code for nullability and cleaning up methods that aren't used anymore. Refctored all uses of Parser.Normalize() to use new extension * More nullability exercises. 500 warnings to go. * Fixed a bug where custom file uploads for entities wouldn't save in webP. * Nullability is done for all DTOs * Fixed all unit tests and nullability for the project. Only OPDS is left which will be done with an upcoming OPDS enhancement. * Use localization in book service after validating * Code smells * Switched to preview build of swashbuckle for .net7 support * Fixed up merge issues * Disable emulate comic book when on single page reader * Fixed a regression where double page renderer wouldn't layout the images correctly * Updated to swashbuckle which support .net 7 * Fixed a bad GA action * Some code cleanup * More code smells * Took care of most of nullable issues * Fixed a broken test due to having more than one test run in parallel * I'm really not sure why the unit tests are failing or are so extremely slow on .net 7 * Updated all dependencies * Fixed up build and removed hardcoded framework from build scripts. (this merge removes Regex Source generators). Unit tests are completely busted. * Unit tests and code cleanup. Needs shakeout now. * Adjusted Series model since a few fields are not-nullable. Removed dead imports on the project. * Refactored to use Builder pattern for all unit tests. * Switched nullability down to warnings. It wasn't possible to switch due to constraint issues in DB Migration.
This commit is contained in:
parent
76fe3fd64a
commit
5d1dd7b3f0
283 changed files with 4221 additions and 4593 deletions
|
|
@ -78,7 +78,7 @@ public interface ISeriesRepository
|
|||
Task<SearchResultGroupDto> SearchSeries(int userId, bool isAdmin, IList<int> libraryIds, string searchQuery);
|
||||
Task<IEnumerable<Series>> GetSeriesForLibraryIdAsync(int libraryId, SeriesIncludes includes = SeriesIncludes.None);
|
||||
Task<SeriesDto> GetSeriesDtoByIdAsync(int seriesId, int userId);
|
||||
Task<Series> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata);
|
||||
Task<Series?> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata);
|
||||
Task<IList<Series>> GetSeriesByIdsAsync(IList<int> seriesIds);
|
||||
Task<int[]> GetChapterIdsForSeriesAsync(IList<int> seriesIds);
|
||||
Task<IDictionary<int, IList<int>>> GetChapterIdWithSeriesIdForSeriesAsync(int[] seriesIds);
|
||||
|
|
@ -89,20 +89,19 @@ public interface ISeriesRepository
|
|||
/// <param name="series"></param>
|
||||
/// <returns></returns>
|
||||
Task AddSeriesModifiers(int userId, List<SeriesDto> series);
|
||||
Task<string> GetSeriesCoverImageAsync(int seriesId);
|
||||
Task<string?> GetSeriesCoverImageAsync(int seriesId);
|
||||
Task<PagedList<SeriesDto>> GetOnDeck(int userId, int libraryId, UserParams userParams, FilterDto filter);
|
||||
Task<PagedList<SeriesDto>> GetRecentlyAdded(int libraryId, int userId, UserParams userParams, FilterDto filter);
|
||||
Task<SeriesMetadataDto> GetSeriesMetadata(int seriesId);
|
||||
Task<SeriesMetadataDto?> GetSeriesMetadata(int seriesId);
|
||||
Task<PagedList<SeriesDto>> GetSeriesDtoForCollectionAsync(int collectionId, int userId, UserParams userParams);
|
||||
Task<IList<MangaFile>> GetFilesForSeries(int seriesId);
|
||||
Task<IEnumerable<SeriesDto>> GetSeriesDtoForIdsAsync(IEnumerable<int> seriesIds, int userId);
|
||||
Task<IList<string>> GetAllCoverImagesAsync();
|
||||
Task<IEnumerable<string>> GetLockedCoverImagesAsync();
|
||||
Task<PagedList<Series>> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams);
|
||||
Task<Series> GetFullSeriesForSeriesIdAsync(int seriesId);
|
||||
Task<Series?> GetFullSeriesForSeriesIdAsync(int seriesId);
|
||||
Task<Chunk> GetChunkInfo(int libraryId = 0);
|
||||
Task<IList<SeriesMetadata>> GetSeriesMetadataForIdsAsync(IEnumerable<int> seriesIds);
|
||||
|
||||
Task<IEnumerable<GroupedSeriesDto>> GetRecentlyUpdatedSeries(int userId, int pageSize = 30);
|
||||
Task<RelatedSeriesDto> GetRelatedSeries(int userId, int seriesId);
|
||||
Task<IEnumerable<SeriesDto>> GetSeriesForRelationKind(int userId, int seriesId, RelationKind kind);
|
||||
|
|
@ -111,20 +110,19 @@ public interface ISeriesRepository
|
|||
Task<PagedList<SeriesDto>> GetHighlyRated(int userId, int libraryId, UserParams userParams);
|
||||
Task<PagedList<SeriesDto>> GetMoreIn(int userId, int libraryId, int genreId, UserParams userParams);
|
||||
Task<PagedList<SeriesDto>> GetRediscover(int userId, int libraryId, UserParams userParams);
|
||||
Task<SeriesDto> GetSeriesForMangaFile(int mangaFileId, int userId);
|
||||
Task<SeriesDto> GetSeriesForChapter(int chapterId, int userId);
|
||||
Task<SeriesDto?> GetSeriesForMangaFile(int mangaFileId, int userId);
|
||||
Task<SeriesDto?> GetSeriesForChapter(int chapterId, int userId);
|
||||
Task<PagedList<SeriesDto>> GetWantToReadForUserAsync(int userId, UserParams userParams, FilterDto filter);
|
||||
Task<bool> IsSeriesInWantToRead(int userId, int seriesId);
|
||||
Task<Series> GetSeriesByFolderPath(string folder, SeriesIncludes includes = SeriesIncludes.None);
|
||||
|
||||
Task<Series?> GetSeriesByFolderPath(string folder, SeriesIncludes includes = SeriesIncludes.None);
|
||||
Task<IEnumerable<Series>> GetAllSeriesByNameAsync(IList<string> normalizedNames,
|
||||
int userId, SeriesIncludes includes = SeriesIncludes.None);
|
||||
Task<IEnumerable<SeriesDto>> GetAllSeriesDtosByNameAsync(IEnumerable<string> normalizedNames,
|
||||
int userId, SeriesIncludes includes = SeriesIncludes.None);
|
||||
Task<Series> GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format, bool withFullIncludes = true);
|
||||
Task<Series?> GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format, bool withFullIncludes = true);
|
||||
Task<IList<Series>> RemoveSeriesNotInList(IList<ParsedSeries> seenSeries, int libraryId);
|
||||
Task<IDictionary<string, IList<SeriesModified>>> GetFolderPathMap(int libraryId);
|
||||
Task<AgeRating> GetMaxAgeRatingFromSeriesAsync(IEnumerable<int> seriesIds);
|
||||
Task<AgeRating?> GetMaxAgeRatingFromSeriesAsync(IEnumerable<int> seriesIds);
|
||||
/// <summary>
|
||||
/// This is only used for <see cref="MigrateUserProgressLibraryId"/>
|
||||
/// </summary>
|
||||
|
|
@ -138,6 +136,12 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
|
||||
// [GeneratedRegex(@"\d{4}", RegexOptions.Compiled, 50000)]
|
||||
// private static partial Regex YearRegex();
|
||||
private readonly Regex _yearRegex = new Regex(@"\d{4}", RegexOptions.Compiled, Services.Tasks.Scanner.Parser.Parser.RegexTimeout);
|
||||
|
||||
public SeriesRepository(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
|
|
@ -202,6 +206,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// <returns></returns>
|
||||
public async Task<PagedList<Series>> GetFullSeriesForLibraryIdAsync(int libraryId, UserParams userParams)
|
||||
{
|
||||
#nullable disable
|
||||
var query = _context.Series
|
||||
.Where(s => s.LibraryId == libraryId)
|
||||
|
||||
|
|
@ -229,11 +234,12 @@ public class SeriesRepository : ISeriesRepository
|
|||
.ThenInclude(v => v.Chapters)
|
||||
.ThenInclude(c => c.Tags)
|
||||
|
||||
.Include(s => s.Volumes)
|
||||
.ThenInclude(v => v.Chapters)
|
||||
.Include(s => s.Volumes)!
|
||||
.ThenInclude(v => v.Chapters)!
|
||||
.ThenInclude(c => c.Files)
|
||||
.AsSplitQuery()
|
||||
.OrderBy(s => s.SortName.ToLower());
|
||||
#nullable enable
|
||||
|
||||
return await PagedList<Series>.CreateAsync(query, userParams.PageNumber, userParams.PageSize);
|
||||
}
|
||||
|
|
@ -243,8 +249,9 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// </summary>
|
||||
/// <param name="seriesId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Series> GetFullSeriesForSeriesIdAsync(int seriesId)
|
||||
public async Task<Series?> GetFullSeriesForSeriesIdAsync(int seriesId)
|
||||
{
|
||||
#nullable disable
|
||||
return await _context.Series
|
||||
.Where(s => s.Id == seriesId)
|
||||
.Include(s => s.Relations)
|
||||
|
|
@ -274,6 +281,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
.ThenInclude(c => c.Files)
|
||||
.AsSplitQuery()
|
||||
.SingleOrDefaultAsync();
|
||||
#nullable enable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -313,7 +321,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
const int maxRecords = 15;
|
||||
var result = new SearchResultGroupDto();
|
||||
var searchQueryNormalized = Services.Tasks.Scanner.Parser.Parser.Normalize(searchQuery);
|
||||
var searchQueryNormalized = searchQuery.ToNormalized();
|
||||
var userRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
|
||||
var seriesIds = _context.Series
|
||||
|
|
@ -332,20 +340,20 @@ public class SeriesRepository : ISeriesRepository
|
|||
.ProjectTo<LibraryDto>(_mapper.ConfigurationProvider)
|
||||
.ToListAsync();
|
||||
|
||||
var justYear = Regex.Match(searchQuery, @"\d{4}", RegexOptions.None, Services.Tasks.Scanner.Parser.Parser.RegexTimeout).Value;
|
||||
var justYear = _yearRegex.Match(searchQuery).Value;
|
||||
var hasYearInQuery = !string.IsNullOrEmpty(justYear);
|
||||
var yearComparison = hasYearInQuery ? int.Parse(justYear) : 0;
|
||||
|
||||
result.Series = _context.Series
|
||||
.Where(s => libraryIds.Contains(s.LibraryId))
|
||||
.Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%")
|
||||
|| EF.Functions.Like(s.OriginalName, $"%{searchQuery}%")
|
||||
|| EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%")
|
||||
|| EF.Functions.Like(s.NormalizedName, $"%{searchQueryNormalized}%")
|
||||
|| (hasYearInQuery && s.Metadata.ReleaseYear == yearComparison))
|
||||
.Where(s => (EF.Functions.Like(s.Name, $"%{searchQuery}%")
|
||||
|| (s.OriginalName != null && EF.Functions.Like(s.OriginalName, $"%{searchQuery}%"))
|
||||
|| (s.LocalizedName != null && EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%"))
|
||||
|| (EF.Functions.Like(s.NormalizedName, $"%{searchQueryNormalized}%"))
|
||||
|| (hasYearInQuery && s.Metadata.ReleaseYear == yearComparison)))
|
||||
.RestrictAgainstAgeRestriction(userRating)
|
||||
.Include(s => s.Library)
|
||||
.OrderBy(s => s.SortName.ToLower())
|
||||
.OrderBy(s => s.SortName!.ToLower())
|
||||
.AsNoTracking()
|
||||
.AsSplitQuery()
|
||||
.Take(maxRecords)
|
||||
|
|
@ -362,8 +370,8 @@ public class SeriesRepository : ISeriesRepository
|
|||
.ToListAsync();
|
||||
|
||||
result.Collections = await _context.CollectionTag
|
||||
.Where(c => EF.Functions.Like(c.Title, $"%{searchQuery}%")
|
||||
|| EF.Functions.Like(c.NormalizedTitle, $"%{searchQueryNormalized}%"))
|
||||
.Where(c => (EF.Functions.Like(c.Title, $"%{searchQuery}%"))
|
||||
|| (EF.Functions.Like(c.NormalizedTitle, $"%{searchQueryNormalized}%")))
|
||||
.Where(c => c.Promoted || isAdmin)
|
||||
.RestrictAgainstAgeRestriction(userRating)
|
||||
.OrderBy(s => s.NormalizedTitle)
|
||||
|
|
@ -376,7 +384,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
result.Persons = await _context.SeriesMetadata
|
||||
.Where(sm => seriesIds.Contains(sm.SeriesId))
|
||||
.SelectMany(sm => sm.People.Where(t => EF.Functions.Like(t.Name, $"%{searchQuery}%")))
|
||||
.SelectMany(sm => sm.People.Where(t => t.Name != null && EF.Functions.Like(t.Name, $"%{searchQuery}%")))
|
||||
.AsSplitQuery()
|
||||
.Take(maxRecords)
|
||||
.Distinct()
|
||||
|
|
@ -448,7 +456,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// <param name="seriesId"></param>
|
||||
/// <param name="includes"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Series> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata)
|
||||
public async Task<Series?> GetSeriesByIdAsync(int seriesId, SeriesIncludes includes = SeriesIncludes.Volumes | SeriesIncludes.Metadata)
|
||||
{
|
||||
return await _context.Series
|
||||
.Where(s => s.Id == seriesId)
|
||||
|
|
@ -581,12 +589,11 @@ public class SeriesRepository : ISeriesRepository
|
|||
}
|
||||
}
|
||||
|
||||
public async Task<string> GetSeriesCoverImageAsync(int seriesId)
|
||||
public async Task<string?> GetSeriesCoverImageAsync(int seriesId)
|
||||
{
|
||||
return await _context.Series
|
||||
.Where(s => s.Id == seriesId)
|
||||
.Select(s => s.CoverImage)
|
||||
.AsNoTracking()
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
|
|
@ -711,7 +718,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
var cutoffProgressPoint = DateTime.Now - TimeSpan.FromDays(30);
|
||||
var cutoffLastAddedPoint = DateTime.Now - TimeSpan.FromDays(7);
|
||||
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Dashboard)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Dashboard)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
|
||||
|
|
@ -767,12 +774,12 @@ public class SeriesRepository : ISeriesRepository
|
|||
.WhereIf(hasAgeRating, s => filter.AgeRating.Contains(s.Metadata.AgeRating))
|
||||
.WhereIf(hasTagsFilter, s => s.Metadata.Tags.Any(t => filter.Tags.Contains(t.Id)))
|
||||
.WhereIf(hasLanguageFilter, s => filter.Languages.Contains(s.Metadata.Language))
|
||||
.WhereIf(hasReleaseYearMinFilter, s => s.Metadata.ReleaseYear >= filter.ReleaseYearRange.Min)
|
||||
.WhereIf(hasReleaseYearMaxFilter, s => s.Metadata.ReleaseYear <= filter.ReleaseYearRange.Max)
|
||||
.WhereIf(hasReleaseYearMinFilter, s => s.Metadata.ReleaseYear >= filter.ReleaseYearRange!.Min)
|
||||
.WhereIf(hasReleaseYearMaxFilter, s => s.Metadata.ReleaseYear <= filter.ReleaseYearRange!.Max)
|
||||
.WhereIf(hasPublicationFilter, s => filter.PublicationStatus.Contains(s.Metadata.PublicationStatus))
|
||||
.WhereIf(hasSeriesNameFilter, s => EF.Functions.Like(s.Name, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.OriginalName, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.LocalizedName, $"%{filter.SeriesNameQuery}%"))
|
||||
|| EF.Functions.Like(s.OriginalName!, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.LocalizedName!, $"%{filter.SeriesNameQuery}%"))
|
||||
|
||||
.WhereIf(onlyParentSeries,
|
||||
s => s.RelationOf.Count == 0 || s.RelationOf.All(p => p.RelationKind == RelationKind.Prequel))
|
||||
|
|
@ -841,12 +848,12 @@ public class SeriesRepository : ISeriesRepository
|
|||
.WhereIf(hasAgeRating, s => filter.AgeRating.Contains(s.Metadata.AgeRating))
|
||||
.WhereIf(hasTagsFilter, s => s.Metadata.Tags.Any(t => filter.Tags.Contains(t.Id)))
|
||||
.WhereIf(hasLanguageFilter, s => filter.Languages.Contains(s.Metadata.Language))
|
||||
.WhereIf(hasReleaseYearMinFilter, s => s.Metadata.ReleaseYear >= filter.ReleaseYearRange.Min)
|
||||
.WhereIf(hasReleaseYearMaxFilter, s => s.Metadata.ReleaseYear <= filter.ReleaseYearRange.Max)
|
||||
.WhereIf(hasReleaseYearMinFilter, s => s.Metadata.ReleaseYear >= filter.ReleaseYearRange!.Min)
|
||||
.WhereIf(hasReleaseYearMaxFilter, s => s.Metadata.ReleaseYear <= filter.ReleaseYearRange!.Max)
|
||||
.WhereIf(hasPublicationFilter, s => filter.PublicationStatus.Contains(s.Metadata.PublicationStatus))
|
||||
.WhereIf(hasSeriesNameFilter, s => EF.Functions.Like(s.Name, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.OriginalName, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.LocalizedName, $"%{filter.SeriesNameQuery}%"))
|
||||
|| EF.Functions.Like(s.OriginalName!, $"%{filter.SeriesNameQuery}%")
|
||||
|| EF.Functions.Like(s.LocalizedName!, $"%{filter.SeriesNameQuery}%"))
|
||||
.Where(s => userLibraries.Contains(s.LibraryId)
|
||||
&& formats.Contains(s.Format))
|
||||
.AsNoTracking();
|
||||
|
|
@ -862,7 +869,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
query = filter.SortOptions.SortField switch
|
||||
{
|
||||
SortField.SortName => query.OrderBy(s => s.SortName.ToLower()),
|
||||
SortField.SortName => query.OrderBy(s => s.SortName!.ToLower()),
|
||||
SortField.CreatedDate => query.OrderBy(s => s.Created),
|
||||
SortField.LastModifiedDate => query.OrderBy(s => s.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderBy(s => s.LastChapterAdded),
|
||||
|
|
@ -874,7 +881,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
{
|
||||
query = filter.SortOptions.SortField switch
|
||||
{
|
||||
SortField.SortName => query.OrderByDescending(s => s.SortName.ToLower()),
|
||||
SortField.SortName => query.OrderByDescending(s => s.SortName!.ToLower()),
|
||||
SortField.CreatedDate => query.OrderByDescending(s => s.Created),
|
||||
SortField.LastModifiedDate => query.OrderByDescending(s => s.LastModified),
|
||||
SortField.LastChapterAdded => query.OrderByDescending(s => s.LastChapterAdded),
|
||||
|
|
@ -886,7 +893,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
return query;
|
||||
}
|
||||
|
||||
public async Task<SeriesMetadataDto> GetSeriesMetadata(int seriesId)
|
||||
public async Task<SeriesMetadataDto?> GetSeriesMetadata(int seriesId)
|
||||
{
|
||||
var metadataDto = await _context.SeriesMetadata
|
||||
.Where(metadata => metadata.SeriesId == seriesId)
|
||||
|
|
@ -968,20 +975,18 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<IList<string>> GetAllCoverImagesAsync()
|
||||
{
|
||||
return await _context.Series
|
||||
return (await _context.Series
|
||||
.Select(s => s.CoverImage)
|
||||
.Where(t => !string.IsNullOrEmpty(t))
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
.ToListAsync())!;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<string>> GetLockedCoverImagesAsync()
|
||||
{
|
||||
return await _context.Series
|
||||
return (await _context.Series
|
||||
.Where(s => s.CoverImageLocked && !string.IsNullOrEmpty(s.CoverImage))
|
||||
.Select(s => s.CoverImage)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
.ToListAsync())!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -1061,31 +1066,35 @@ public class SeriesRepository : ISeriesRepository
|
|||
var items = (await GetRecentlyAddedChaptersQuery(userId));
|
||||
if (userRating.AgeRating != AgeRating.NotApplicable)
|
||||
{
|
||||
items = items.RestrictAgainstAgeRestriction(userRating);
|
||||
items = items.RestrictAgainstAgeRestriction(userRating);
|
||||
}
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (seriesMap.Keys.Count == pageSize) break;
|
||||
if (seriesMap.Keys.Count == pageSize) break;
|
||||
|
||||
if (seriesMap.ContainsKey(item.SeriesName))
|
||||
{
|
||||
seriesMap[item.SeriesName].Count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
seriesMap[item.SeriesName] = new GroupedSeriesDto()
|
||||
{
|
||||
LibraryId = item.LibraryId,
|
||||
LibraryType = item.LibraryType,
|
||||
SeriesId = item.SeriesId,
|
||||
SeriesName = item.SeriesName,
|
||||
Created = item.Created,
|
||||
Id = index,
|
||||
Format = item.Format,
|
||||
Count = 1,
|
||||
};
|
||||
index += 1;
|
||||
}
|
||||
if (item.SeriesName == null) continue;
|
||||
|
||||
|
||||
if (seriesMap.TryGetValue(item.SeriesName, out var value))
|
||||
{
|
||||
value.Count += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
seriesMap[item.SeriesName] = new GroupedSeriesDto()
|
||||
{
|
||||
LibraryId = item.LibraryId,
|
||||
LibraryType = item.LibraryType,
|
||||
SeriesId = item.SeriesId,
|
||||
SeriesName = item.SeriesName,
|
||||
Created = item.Created,
|
||||
Id = index,
|
||||
Format = item.Format,
|
||||
Count = 1,
|
||||
};
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return seriesMap.Values.AsEnumerable();
|
||||
|
|
@ -1093,7 +1102,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<IEnumerable<SeriesDto>> GetSeriesForRelationKind(int userId, int seriesId, RelationKind kind)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId);
|
||||
var libraryIds = GetLibraryIdsForUser(userId);
|
||||
var userRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
|
||||
var usersSeriesIds = _context.Series
|
||||
|
|
@ -1120,7 +1129,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<PagedList<SeriesDto>> GetMoreIn(int userId, int libraryId, int genreId, UserParams userParams)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Recommended)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Recommended)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
|
||||
|
|
@ -1148,7 +1157,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// <returns></returns>
|
||||
public async Task<PagedList<SeriesDto>> GetRediscover(int userId, int libraryId, UserParams userParams)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Recommended)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Recommended)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
var distinctSeriesIdsWithProgress = _context.AppUserProgresses
|
||||
|
|
@ -1166,9 +1175,9 @@ public class SeriesRepository : ISeriesRepository
|
|||
return await PagedList<SeriesDto>.CreateAsync(query, userParams.PageNumber, userParams.PageSize);
|
||||
}
|
||||
|
||||
public async Task<SeriesDto> GetSeriesForMangaFile(int mangaFileId, int userId)
|
||||
public async Task<SeriesDto?> GetSeriesForMangaFile(int mangaFileId, int userId)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Search);
|
||||
var libraryIds = GetLibraryIdsForUser(userId, 0, QueryContext.Search);
|
||||
var userRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
|
||||
return await _context.MangaFile
|
||||
|
|
@ -1183,9 +1192,9 @@ public class SeriesRepository : ISeriesRepository
|
|||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<SeriesDto> GetSeriesForChapter(int chapterId, int userId)
|
||||
public async Task<SeriesDto?> GetSeriesForChapter(int chapterId, int userId)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId);
|
||||
var libraryIds = GetLibraryIdsForUser(userId);
|
||||
var userRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
return await _context.Chapter
|
||||
.Where(m => m.Id == chapterId)
|
||||
|
|
@ -1204,11 +1213,11 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// <param name="folder">This will be normalized in the query</param>
|
||||
/// <param name="includes">Additional relationships to include with the base query</param>
|
||||
/// <returns></returns>
|
||||
public async Task<Series> GetSeriesByFolderPath(string folder, SeriesIncludes includes = SeriesIncludes.None)
|
||||
public async Task<Series?> GetSeriesByFolderPath(string folder, SeriesIncludes includes = SeriesIncludes.None)
|
||||
{
|
||||
var normalized = Services.Tasks.Scanner.Parser.Parser.NormalizePath(folder);
|
||||
return await _context.Series
|
||||
.Where(s => s.FolderPath.Equals(normalized))
|
||||
.Where(s => s.FolderPath != null && s.FolderPath.Equals(normalized))
|
||||
.Includes(includes)
|
||||
.SingleOrDefaultAsync();
|
||||
}
|
||||
|
|
@ -1220,7 +1229,8 @@ public class SeriesRepository : ISeriesRepository
|
|||
var userRating = await _context.AppUser.GetUserAgeRestriction(userId);
|
||||
|
||||
return await _context.Series
|
||||
.Where(s => normalizedNames.Contains(s.NormalizedName) || normalizedNames.Contains(s.NormalizedLocalizedName))
|
||||
.Where(s => normalizedNames.Contains(s.NormalizedName) ||
|
||||
normalizedNames.Contains(s.NormalizedLocalizedName))
|
||||
.Where(s => libraryIds.Contains(s.LibraryId))
|
||||
.RestrictAgainstAgeRestriction(userRating)
|
||||
.Includes(includes)
|
||||
|
|
@ -1252,21 +1262,23 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// <param name="format"></param>
|
||||
/// <param name="withFullIncludes">Defaults to true. This will query against all foreign keys (deep). If false, just the series will come back</param>
|
||||
/// <returns></returns>
|
||||
public Task<Series> GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format, bool withFullIncludes = true)
|
||||
public Task<Series?> GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format, bool withFullIncludes = true)
|
||||
{
|
||||
var normalizedSeries = Services.Tasks.Scanner.Parser.Parser.Normalize(seriesName);
|
||||
var normalizedLocalized = Services.Tasks.Scanner.Parser.Parser.Normalize(localizedName);
|
||||
var normalizedSeries = seriesName.ToNormalized();
|
||||
var normalizedLocalized = localizedName.ToNormalized();
|
||||
var query = _context.Series
|
||||
.Where(s => s.LibraryId == libraryId)
|
||||
.Where(s => s.Format == format && format != MangaFormat.Unknown)
|
||||
.Where(s => s.NormalizedName.Equals(normalizedSeries)
|
||||
|| (s.NormalizedLocalizedName.Equals(normalizedSeries) && s.NormalizedLocalizedName != string.Empty)
|
||||
|| s.OriginalName.Equals(seriesName));
|
||||
|| (s.NormalizedLocalizedName == normalizedSeries)
|
||||
|| (s.OriginalName == seriesName));
|
||||
|
||||
if (!string.IsNullOrEmpty(normalizedLocalized))
|
||||
{
|
||||
// TODO: Apply WhereIf
|
||||
query = query.Where(s =>
|
||||
s.NormalizedName.Equals(normalizedLocalized) || s.NormalizedLocalizedName.Equals(normalizedLocalized));
|
||||
s.NormalizedName.Equals(normalizedLocalized)
|
||||
|| (s.NormalizedLocalizedName != null && s.NormalizedLocalizedName.Equals(normalizedLocalized)));
|
||||
}
|
||||
|
||||
if (!withFullIncludes)
|
||||
|
|
@ -1274,10 +1286,13 @@ public class SeriesRepository : ISeriesRepository
|
|||
return query.SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
#nullable disable
|
||||
return query.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.People)
|
||||
|
||||
.Include(s => s.Metadata)
|
||||
.ThenInclude(m => m.Genres)
|
||||
|
||||
.Include(s => s.Library)
|
||||
.Include(s => s.Volumes)
|
||||
.ThenInclude(v => v.Chapters)
|
||||
|
|
@ -1300,6 +1315,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
.ThenInclude(c => c.Files)
|
||||
.AsSplitQuery()
|
||||
.SingleOrDefaultAsync();
|
||||
#nullable enable
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1356,7 +1372,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<PagedList<SeriesDto>> GetHighlyRated(int userId, int libraryId, UserParams userParams)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Recommended)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Recommended)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
var distinctSeriesIdsWithHighRating = _context.AppUserRating
|
||||
|
|
@ -1378,7 +1394,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<PagedList<SeriesDto>> GetQuickReads(int userId, int libraryId, UserParams userParams)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Recommended)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Recommended)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
var distinctSeriesIdsWithProgress = _context.AppUserProgresses
|
||||
|
|
@ -1405,7 +1421,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
|
||||
public async Task<PagedList<SeriesDto>> GetQuickCatchupReads(int userId, int libraryId, UserParams userParams)
|
||||
{
|
||||
var libraryIds = _context.Library.GetUserLibraries(userId, QueryContext.Recommended)
|
||||
var libraryIds = GetLibraryIdsForUser(userId, libraryId, QueryContext.Recommended)
|
||||
.Where(id => libraryId == 0 || id == libraryId);
|
||||
var usersSeriesIds = GetSeriesIdsForLibraryIds(libraryIds);
|
||||
var distinctSeriesIdsWithProgress = _context.AppUserProgresses
|
||||
|
|
@ -1581,6 +1597,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
var map = new Dictionary<string, IList<SeriesModified>>();
|
||||
foreach (var series in info)
|
||||
{
|
||||
if (series.FolderPath == null) continue;
|
||||
if (!map.ContainsKey(series.FolderPath))
|
||||
{
|
||||
map.Add(series.FolderPath, new List<SeriesModified>()
|
||||
|
|
@ -1603,7 +1620,7 @@ public class SeriesRepository : ISeriesRepository
|
|||
/// </summary>
|
||||
/// <param name="seriesIds"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<AgeRating> GetMaxAgeRatingFromSeriesAsync(IEnumerable<int> seriesIds)
|
||||
public async Task<AgeRating?> GetMaxAgeRatingFromSeriesAsync(IEnumerable<int> seriesIds)
|
||||
{
|
||||
return await _context.Series
|
||||
.Where(s => seriesIds.Contains(s.Id))
|
||||
|
|
@ -1612,4 +1629,32 @@ public class SeriesRepository : ISeriesRepository
|
|||
.OrderBy(s => s)
|
||||
.LastOrDefaultAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all library ids for a user
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="libraryId">0 for no library filter</param>
|
||||
/// <param name="queryContext">Defaults to None - The context behind this query, so appropriate restrictions can be placed</param>
|
||||
/// <returns></returns>
|
||||
private IQueryable<int> GetLibraryIdsForUser(int userId, int libraryId = 0, QueryContext queryContext = QueryContext.None)
|
||||
{
|
||||
var user = _context.AppUser
|
||||
.AsSplitQuery()
|
||||
.AsNoTracking()
|
||||
.Where(u => u.Id == userId)
|
||||
.AsSingleQuery();
|
||||
|
||||
if (libraryId == 0)
|
||||
{
|
||||
return user.SelectMany(l => l.Libraries)
|
||||
.IsRestricted(queryContext)
|
||||
.Select(lib => lib.Id);
|
||||
}
|
||||
|
||||
return user.SelectMany(l => l.Libraries)
|
||||
.Where(lib => lib.Id == libraryId)
|
||||
.IsRestricted(queryContext)
|
||||
.Select(lib => lib.Id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue