New Feature Stats (#1179)

* When searching, search against normalized names.

* Added new stat fields
This commit is contained in:
Joseph Milazzo 2022-03-27 08:16:43 -05:00 committed by GitHub
parent fbb8934eef
commit 0622d8a874
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 80 additions and 16 deletions

View File

@ -245,8 +245,7 @@ namespace API.Controllers
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername()); var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
var results = await _unitOfWork.SeriesRepository.GetOnDeck(userId, libraryId, userParams, filterDto); var results = await _unitOfWork.SeriesRepository.GetOnDeck(userId, libraryId, userParams, filterDto);
var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize) var listResults = results.DistinctBy(s => s.Name).Skip((userParams.PageNumber - 1) * userParams.PageSize).Take(userParams.PageSize).ToList();
.Take(userParams.PageSize).ToList();
var pagedList = new PagedList<SeriesDto>(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize); var pagedList = new PagedList<SeriesDto>(listResults, listResults.Count, userParams.PageNumber, userParams.PageSize);
await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, pagedList); await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, pagedList);

View File

@ -1,4 +1,6 @@
namespace API.DTOs.Stats using API.Entities.Enums;
namespace API.DTOs.Stats
{ {
public class ServerInfoDto public class ServerInfoDto
{ {
@ -10,5 +12,39 @@
public int NumOfCores { get; set; } public int NumOfCores { get; set; }
public int NumberOfLibraries { get; set; } public int NumberOfLibraries { get; set; }
public bool HasBookmarks { get; set; } public bool HasBookmarks { get; set; }
/// <summary>
/// The site theme the install is using
/// </summary>
public string ActiveSiteTheme { get; set; }
/// <summary>
/// The reading mode the main user has as a preference
/// </summary>
public ReaderMode MangaReaderMode { get; set; }
/// <summary>
/// Number of users on the install
/// </summary>
public int NumberOfUsers { get; set; }
/// <summary>
/// Number of collections on the install
/// </summary>
public int NumberOfCollections { get; set; }
/// <summary>
/// Number of reading lists on the install (Sum of all users)
/// </summary>
public int NumberOfReadingLists { get; set; }
/// <summary>
/// Is OPDS enabled
/// </summary>
public bool OPDSEnabled { get; set; }
/// <summary>
/// Total number of files in the instance
/// </summary>
public int TotalFiles { get; set; }
} }
} }

View File

@ -37,6 +37,7 @@ public interface ILibraryRepository
Task<IEnumerable<Library>> GetLibrariesForUserIdAsync(int userId); Task<IEnumerable<Library>> GetLibrariesForUserIdAsync(int userId);
Task<LibraryType> GetLibraryTypeAsync(int libraryId); Task<LibraryType> GetLibraryTypeAsync(int libraryId);
Task<IEnumerable<Library>> GetLibraryForIdsAsync(IList<int> libraryIds); Task<IEnumerable<Library>> GetLibraryForIdsAsync(IList<int> libraryIds);
Task<int> GetTotalFiles();
} }
public class LibraryRepository : ILibraryRepository public class LibraryRepository : ILibraryRepository
@ -116,6 +117,11 @@ public class LibraryRepository : ILibraryRepository
.ToListAsync(); .ToListAsync();
} }
public async Task<int> GetTotalFiles()
{
return await _context.MangaFile.CountAsync();
}
public async Task<IEnumerable<LibraryDto>> GetLibraryDtosAsync() public async Task<IEnumerable<LibraryDto>> GetLibraryDtosAsync()
{ {
return await _context.Library return await _context.Library

View File

@ -25,6 +25,7 @@ public interface IReadingListRepository
void Remove(ReadingListItem item); void Remove(ReadingListItem item);
void BulkRemove(IEnumerable<ReadingListItem> items); void BulkRemove(IEnumerable<ReadingListItem> items);
void Update(ReadingList list); void Update(ReadingList list);
Task<int> Count();
} }
public class ReadingListRepository : IReadingListRepository public class ReadingListRepository : IReadingListRepository
@ -43,6 +44,11 @@ public class ReadingListRepository : IReadingListRepository
_context.Entry(list).State = EntityState.Modified; _context.Entry(list).State = EntityState.Modified;
} }
public async Task<int> Count()
{
return await _context.ReadingList.CountAsync();
}
public void Remove(ReadingListItem item) public void Remove(ReadingListItem item)
{ {
_context.ReadingListItem.Remove(item); _context.ReadingListItem.Remove(item);

View File

@ -276,6 +276,7 @@ public class SeriesRepository : ISeriesRepository
{ {
var result = new SearchResultGroupDto(); var result = new SearchResultGroupDto();
var searchQueryNormalized = Parser.Parser.Normalize(searchQuery);
var seriesIds = _context.Series var seriesIds = _context.Series
.Where(s => libraryIds.Contains(s.LibraryId)) .Where(s => libraryIds.Contains(s.LibraryId))
@ -299,6 +300,7 @@ public class SeriesRepository : ISeriesRepository
.Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%") .Where(s => EF.Functions.Like(s.Name, $"%{searchQuery}%")
|| EF.Functions.Like(s.OriginalName, $"%{searchQuery}%") || EF.Functions.Like(s.OriginalName, $"%{searchQuery}%")
|| EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%") || EF.Functions.Like(s.LocalizedName, $"%{searchQuery}%")
|| EF.Functions.Like(s.NormalizedName, $"%{searchQueryNormalized}%")
|| (hasYearInQuery && s.Metadata.ReleaseYear == yearComparison)) || (hasYearInQuery && s.Metadata.ReleaseYear == yearComparison))
.Include(s => s.Library) .Include(s => s.Library)
.OrderBy(s => s.SortName) .OrderBy(s => s.SortName)
@ -317,7 +319,7 @@ public class SeriesRepository : ISeriesRepository
result.Collections = await _context.CollectionTag result.Collections = await _context.CollectionTag
.Where(s => EF.Functions.Like(s.Title, $"%{searchQuery}%") .Where(s => EF.Functions.Like(s.Title, $"%{searchQuery}%")
|| EF.Functions.Like(s.NormalizedTitle, $"%{searchQuery}%")) || EF.Functions.Like(s.NormalizedTitle, $"%{searchQueryNormalized}%"))
.Where(s => s.Promoted || isAdmin) .Where(s => s.Promoted || isAdmin)
.OrderBy(s => s.Title) .OrderBy(s => s.Title)
.AsNoTracking() .AsNoTracking()

View File

@ -35,6 +35,14 @@ namespace API.Entities
/// on next load /// on next load
/// </summary> /// </summary>
public string BookScrollId { get; set; } public string BookScrollId { get; set; }
/// <summary>
/// When this was first created
/// </summary>
public DateTime Created { get; set; }
/// <summary>
/// Last date this was updated
/// </summary>
public DateTime LastModified { get; set; }
// Relationships // Relationships
/// <summary> /// <summary>
@ -45,14 +53,5 @@ namespace API.Entities
/// User this progress belongs to /// User this progress belongs to
/// </summary> /// </summary>
public int AppUserId { get; set; } public int AppUserId { get; set; }
/// <summary>
/// When this was first created
/// </summary>
public DateTime Created { get; set; }
/// <summary>
/// Last date this was updated
/// </summary>
public DateTime LastModified { get; set; }
} }
} }

View File

@ -5,6 +5,7 @@ using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Data; using API.Data;
using API.DTOs.Stats; using API.DTOs.Stats;
using API.DTOs.Theme;
using API.Entities.Enums; using API.Entities.Enums;
using Flurl.Http; using Flurl.Http;
using Kavita.Common.EnvironmentInfo; using Kavita.Common.EnvironmentInfo;
@ -100,6 +101,12 @@ public class StatsService : IStatsService
{ {
var installId = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId); var installId = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId);
var installVersion = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion); var installVersion = await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion);
var firstAdminUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First();
var firstAdminUserPref = (await _unitOfWork.UserRepository.GetPreferencesAsync(firstAdminUser.UserName));
var activeTheme = firstAdminUserPref.Theme ?? Seed.DefaultThemes.First(t => t.IsDefault);
var serverInfo = new ServerInfoDto var serverInfo = new ServerInfoDto
{ {
InstallId = installId.Value, InstallId = installId.Value,
@ -109,7 +116,14 @@ public class StatsService : IStatsService
IsDocker = new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker, IsDocker = new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker,
NumOfCores = Math.Max(Environment.ProcessorCount, 1), NumOfCores = Math.Max(Environment.ProcessorCount, 1),
HasBookmarks = (await _unitOfWork.UserRepository.GetAllBookmarksAsync()).Any(), HasBookmarks = (await _unitOfWork.UserRepository.GetAllBookmarksAsync()).Any(),
NumberOfLibraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).Count() NumberOfLibraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).Count(),
ActiveSiteTheme = activeTheme.Name,
NumberOfCollections = (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).Count(),
NumberOfReadingLists = await _unitOfWork.ReadingListRepository.Count(),
OPDSEnabled = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).EnableOpds,
NumberOfUsers = (await _unitOfWork.UserRepository.GetAllUsers()).Count(),
TotalFiles = await _unitOfWork.LibraryRepository.GetTotalFiles(),
MangaReaderMode = firstAdminUserPref.ReaderMode
}; };
return serverInfo; return serverInfo;

View File

@ -10498,7 +10498,8 @@
"dependencies": { "dependencies": {
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true "dev": true
}, },
"strip-ansi": { "strip-ansi": {
@ -10703,7 +10704,8 @@
"dependencies": { "dependencies": {
"ansi-regex": { "ansi-regex": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
"dev": true "dev": true
}, },
"ansi-styles": { "ansi-styles": {