Co-authored-by: Hippari <iamtimscampi@gmail.com>
Co-authored-by: Gavin Mogan <github@gavinmogan.com>
This commit is contained in:
Joe Milazzo 2024-12-09 13:06:28 -06:00 committed by GitHub
parent 0407d75d91
commit bfbcb4b741
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 551 additions and 364 deletions

View file

@ -509,6 +509,21 @@ public class AccountController : BaseApiController
_unitOfWork.UserRepository.Update(user);
}
// Check if email is changing for a non-admin user
var isUpdatingAnotherAccount = user.Id != adminUser.Id;
if (isUpdatingAnotherAccount && !string.IsNullOrEmpty(dto.Email) && user.Email != dto.Email)
{
// Validate username change
var errors = await _accountService.ValidateEmail(dto.Email);
if (errors.Any()) return BadRequest(await _localizationService.Translate(User.GetUserId(), "email-taken"));
user.Email = dto.Email;
user.EmailConfirmed = true; // When an admin performs the flow, we assume the email address is able to receive data
await _userManager.UpdateNormalizedEmailAsync(user);
_unitOfWork.UserRepository.Update(user);
}
// Update roles
var existingRoles = await _userManager.GetRolesAsync(user);
var hasAdminRole = dto.Roles.Contains(PolicyConstants.AdminRole);
@ -612,8 +627,7 @@ public class AccountController : BaseApiController
if (adminUser == null) return Unauthorized(await _localizationService.Translate(userId, "permission-denied"));
dto.Email = dto.Email.Trim();
if (string.IsNullOrEmpty(dto.Email))
return BadRequest(await _localizationService.Translate(userId, "invalid-payload"));
if (string.IsNullOrEmpty(dto.Email)) return BadRequest(await _localizationService.Translate(userId, "invalid-payload"));
_logger.LogInformation("{User} is inviting {Email} to the server", adminUser.UserName, dto.Email);
@ -623,7 +637,7 @@ public class AccountController : BaseApiController
{
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-registered", invitedUser.UserName));
return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-registered", invitedUser!.UserName));
return BadRequest(await _localizationService.Translate(User.GetUserId(), "user-already-invited"));
}

View file

@ -18,4 +18,8 @@ public record UpdateUserDto
/// An Age Rating which will limit the account to seeing everything equal to or below said rating.
/// </summary>
public AgeRestrictionDto AgeRestriction { get; init; } = default!;
/// <summary>
/// Email of the user
/// </summary>
public string? Email { get; set; } = default!;
}

View file

@ -101,12 +101,15 @@ public static class RestrictByAgeExtensions
if (restriction.IncludeUnknowns)
{
return queryable.Where(c => c.SeriesMetadataPeople.All(sm =>
sm.SeriesMetadata.AgeRating <= restriction.AgeRating));
return queryable.Where(c =>
c.SeriesMetadataPeople.Any(sm => sm.SeriesMetadata.AgeRating <= restriction.AgeRating) ||
c.ChapterPeople.Any(cp => cp.Chapter.AgeRating <= restriction.AgeRating));
}
return queryable.Where(c => c.SeriesMetadataPeople.All(sm =>
sm.SeriesMetadata.AgeRating <= restriction.AgeRating && sm.SeriesMetadata.AgeRating > AgeRating.Unknown));
return queryable.Where(c =>
c.SeriesMetadataPeople.Any(sm => sm.SeriesMetadata.AgeRating <= restriction.AgeRating && sm.SeriesMetadata.AgeRating != AgeRating.Unknown) ||
c.ChapterPeople.Any(cp => cp.Chapter.AgeRating <= restriction.AgeRating && cp.Chapter.AgeRating != AgeRating.Unknown)
);
}
public static IQueryable<ReadingList> RestrictAgainstAgeRestriction(this IQueryable<ReadingList> queryable, AgeRestriction restriction)

View file

@ -18,6 +18,7 @@
"age-restriction-update": "There was an error updating the age restriction",
"no-user": "User does not exist",
"username-taken": "Username already taken",
"email-taken": "Email already in use",
"user-already-confirmed": "User is already confirmed",
"generic-user-update": "There was an exception when updating the user",
"manual-setup-fail": "Manual setup is unable to be completed. Please cancel and recreate the invite",

View file

@ -95,12 +95,12 @@ public class AccountService : IAccountService
public async Task<IEnumerable<ApiException>> ValidateEmail(string email)
{
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(email);
if (user == null) return Array.Empty<ApiException>();
if (user == null) return [];
return new List<ApiException>()
{
return
[
new ApiException(400, "Email is already registered")
};
];
}
/// <summary>

View file

@ -14,6 +14,7 @@ using API.DTOs.Stats.V3;
using API.Entities;
using API.Entities.Enums;
using API.Services.Plus;
using API.Services.Tasks.Scanner.Parser;
using Flurl.Http;
using Kavita.Common.EnvironmentInfo;
using Kavita.Common.Helpers;
@ -231,11 +232,12 @@ public class StatsService : IStatsService
{
// If first time flow, just return 0
if (!await _context.Chapter.AnyAsync()) return 0;
return await _context.Series
.AsNoTracking()
.AsSplitQuery()
.MaxAsync(s => s.Volumes!
.Where(v => v.MinNumber == 0)
.Where(v => v.MinNumber == Parser.LooseLeafVolumeNumber)
.SelectMany(v => v.Chapters!)
.Count());
}
@ -262,13 +264,13 @@ public class StatsService : IStatsService
dto.MaxSeriesInALibrary = await MaxSeriesInAnyLibrary();
dto.MaxVolumesInASeries = await MaxVolumesInASeries();
dto.MaxChaptersInASeries = await MaxChaptersInASeries();
dto.TotalFiles = await _unitOfWork.LibraryRepository.GetTotalFiles();
dto.TotalGenres = await _unitOfWork.GenreRepository.GetCountAsync();
dto.TotalPeople = await _unitOfWork.PersonRepository.GetCountAsync();
dto.TotalSeries = await _unitOfWork.SeriesRepository.GetCountAsync();
dto.TotalLibraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).Count();
dto.NumberOfCollections = (await _unitOfWork.CollectionTagRepository.GetAllCollectionsAsync()).Count();
dto.NumberOfReadingLists = await _unitOfWork.ReadingListRepository.Count();
dto.TotalFiles = await _context.MangaFile.CountAsync();
dto.TotalGenres = await _context.Genre.CountAsync();
dto.TotalPeople = await _context.Person.CountAsync();
dto.TotalSeries = await _context.Series.CountAsync();
dto.TotalLibraries = await _context.Library.CountAsync();
dto.NumberOfCollections = await _context.AppUserCollection.CountAsync();
dto.NumberOfReadingLists = await _context.ReadingList.CountAsync();
try
{
@ -314,6 +316,7 @@ public class StatsService : IStatsService
libDto.UsingFolderWatching = library.FolderWatching;
libDto.CreateCollectionsFromMetadata = library.ManageCollections;
libDto.CreateReadingListsFromMetadata = library.ManageReadingLists;
libDto.LibraryType = library.Type;
dto.Libraries.Add(libDto);
}