mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Stat hotfix (#1748)
* Fixed a bug where a divide by 0 could occur * Email change now requires a password
This commit is contained in:
parent
7e55134e6b
commit
3e1d0f39f0
@ -289,7 +289,15 @@ public class AccountController : BaseApiController
|
|||||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||||
if (user == null) return Unauthorized("You do not have permission");
|
if (user == null) return Unauthorized("You do not have permission");
|
||||||
|
|
||||||
if (dto == null || string.IsNullOrEmpty(dto.Email)) return BadRequest("Invalid payload");
|
if (dto == null || string.IsNullOrEmpty(dto.Email) || string.IsNullOrEmpty(dto.Password)) return BadRequest("Invalid payload");
|
||||||
|
|
||||||
|
|
||||||
|
// Validate this user's password
|
||||||
|
if (! await _userManager.CheckPasswordAsync(user, dto.Password))
|
||||||
|
{
|
||||||
|
_logger.LogCritical("A user tried to change {UserName}'s email, but password didn't validate", user.UserName);
|
||||||
|
return BadRequest("You do not have permission");
|
||||||
|
}
|
||||||
|
|
||||||
// Validate no other users exist with this email
|
// Validate no other users exist with this email
|
||||||
if (user.Email.Equals(dto.Email)) return Ok("Nothing to do");
|
if (user.Email.Equals(dto.Email)) return Ok("Nothing to do");
|
||||||
|
@ -3,4 +3,5 @@
|
|||||||
public class UpdateEmailDto
|
public class UpdateEmailDto
|
||||||
{
|
{
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -207,24 +207,28 @@ public class StatsService : IStatsService
|
|||||||
private async Task<float> GetPercentageOfLibrariesWithFolderWatchingEnabled()
|
private async Task<float> GetPercentageOfLibrariesWithFolderWatchingEnabled()
|
||||||
{
|
{
|
||||||
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
||||||
|
if (libraries.Count == 0) return 0.0f;
|
||||||
return libraries.Count(l => l.FolderWatching) / (1.0f * libraries.Count);
|
return libraries.Count(l => l.FolderWatching) / (1.0f * libraries.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<float> GetPercentageOfLibrariesIncludedInRecommended()
|
private async Task<float> GetPercentageOfLibrariesIncludedInRecommended()
|
||||||
{
|
{
|
||||||
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
||||||
|
if (libraries.Count == 0) return 0.0f;
|
||||||
return libraries.Count(l => l.IncludeInRecommended) / (1.0f * libraries.Count);
|
return libraries.Count(l => l.IncludeInRecommended) / (1.0f * libraries.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<float> GetPercentageOfLibrariesIncludedInDashboard()
|
private async Task<float> GetPercentageOfLibrariesIncludedInDashboard()
|
||||||
{
|
{
|
||||||
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
||||||
|
if (libraries.Count == 0) return 0.0f;
|
||||||
return libraries.Count(l => l.IncludeInDashboard) / (1.0f * libraries.Count);
|
return libraries.Count(l => l.IncludeInDashboard) / (1.0f * libraries.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<float> GetPercentageOfLibrariesIncludedInSearch()
|
private async Task<float> GetPercentageOfLibrariesIncludedInSearch()
|
||||||
{
|
{
|
||||||
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesAsync()).ToList();
|
||||||
|
if (libraries.Count == 0) return 0.0f;
|
||||||
return libraries.Count(l => l.IncludeInSearch) / (1.0f * libraries.Count);
|
return libraries.Count(l => l.IncludeInSearch) / (1.0f * libraries.Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,8 +204,8 @@ export class AccountService implements OnDestroy {
|
|||||||
return this.httpClient.post(this.baseUrl + 'account/update', model);
|
return this.httpClient.post(this.baseUrl + 'account/update', model);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateEmail(email: string) {
|
updateEmail(email: string, password: string) {
|
||||||
return this.httpClient.post<UpdateEmailResponse>(this.baseUrl + 'account/update/email', {email});
|
return this.httpClient.post<UpdateEmailResponse>(this.baseUrl + 'account/update/email', {email, password});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAgeRestriction(ageRating: AgeRating, includeUnknowns: boolean) {
|
updateAgeRestriction(ageRating: AgeRating, includeUnknowns: boolean) {
|
||||||
|
@ -39,6 +39,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="password" class="form-label">Current Password</label>
|
||||||
|
<input class="form-control custom-input" type="password" id="password" formControlName="password"
|
||||||
|
[class.is-invalid]="form.get('password')?.invalid && form.get('password')?.touched">
|
||||||
|
<div id="password-validations" class="invalid-feedback" *ngIf="form.dirty || form.touched">
|
||||||
|
<div *ngIf="form.get('password')?.errors?.required">
|
||||||
|
This field is required
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end mb-3">
|
||||||
<button type="button" class="flex-fill btn btn-secondary me-2" aria-describedby="email-card" (click)="resetForm()">Reset</button>
|
<button type="button" class="flex-fill btn btn-secondary me-2" aria-describedby="email-card" (click)="resetForm()">Reset</button>
|
||||||
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="email-card" (click)="saveForm()" [disabled]="!form.valid || !(form.dirty || form.touched)">Save</button>
|
<button type="submit" class="flex-fill btn btn-primary" aria-describedby="email-card" (click)="saveForm()" [disabled]="!form.valid || !(form.dirty || form.touched)">Save</button>
|
||||||
|
@ -34,6 +34,7 @@ export class ChangeEmailComponent implements OnInit, OnDestroy {
|
|||||||
this.accountService.currentUser$.pipe(takeUntil(this.onDestroy), shareReplay(), take(1)).subscribe(user => {
|
this.accountService.currentUser$.pipe(takeUntil(this.onDestroy), shareReplay(), take(1)).subscribe(user => {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.form.addControl('email', new FormControl(user?.email, [Validators.required, Validators.email]));
|
this.form.addControl('email', new FormControl(user?.email, [Validators.required, Validators.email]));
|
||||||
|
this.form.addControl('password', new FormControl('', [Validators.required]));
|
||||||
this.cdRef.markForCheck();
|
this.cdRef.markForCheck();
|
||||||
this.accountService.isEmailConfirmed().subscribe((confirmed) => {
|
this.accountService.isEmailConfirmed().subscribe((confirmed) => {
|
||||||
this.emailConfirmed = confirmed;
|
this.emailConfirmed = confirmed;
|
||||||
@ -60,7 +61,7 @@ export class ChangeEmailComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
const model = this.form.value;
|
const model = this.form.value;
|
||||||
this.errors = [];
|
this.errors = [];
|
||||||
this.accountService.updateEmail(model.email).subscribe((updateEmailResponse: UpdateEmailResponse) => {
|
this.accountService.updateEmail(model.email, model.password).subscribe((updateEmailResponse: UpdateEmailResponse) => {
|
||||||
if (updateEmailResponse.emailSent) {
|
if (updateEmailResponse.emailSent) {
|
||||||
if (updateEmailResponse.hadNoExistingEmail) {
|
if (updateEmailResponse.hadNoExistingEmail) {
|
||||||
this.toastr.success('An email has been sent to ' + model.email + ' for confirmation.');
|
this.toastr.success('An email has been sent to ' + model.email + ' for confirmation.');
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"name": "GPL-3.0",
|
"name": "GPL-3.0",
|
||||||
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
"url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE"
|
||||||
},
|
},
|
||||||
"version": "0.6.1.27"
|
"version": "0.6.1.28"
|
||||||
},
|
},
|
||||||
"servers": [
|
"servers": [
|
||||||
{
|
{
|
||||||
@ -13690,6 +13690,10 @@
|
|||||||
"email": {
|
"email": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"nullable": true
|
"nullable": true
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string",
|
||||||
|
"nullable": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
Loading…
x
Reference in New Issue
Block a user