From 00b759e532ef7fd4d7c06414271f35f4741f6e01 Mon Sep 17 00:00:00 2001 From: DieselTech <30128380+DieselTech@users.noreply.github.com> Date: Wed, 16 Apr 2025 08:21:29 -0400 Subject: [PATCH 1/9] [skip ci] Update bug_report.yml Updated release version --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8740c4e13..f52d914e5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -28,7 +28,7 @@ body: label: Kavita Version Number - If you don't see your version number listed, please update Kavita and see if your issue still persists. multiple: false options: - - 0.8.5.11 - Stable + - 0.8.6.0 - Stable - Nightly Testing Branch validations: required: true From ad152aa26aa1f9788bd6000a53b0ead19e945702 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Fri, 18 Apr 2025 05:48:37 -0600 Subject: [PATCH 2/9] v0.8.6.1 - A few small issues Hotfix (#3744) Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com> Co-authored-by: Weblate (bot) Co-authored-by: Lyrq --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- API/Controllers/VolumeController.cs | 29 ++++++++++++++++- API/Data/Repositories/VolumeRepository.cs | 15 +++++++++ API/I18N/pl.json | 6 ++-- UI/Web/src/app/_services/action.service.ts | 13 +++++++- UI/Web/src/app/_services/volume.service.ts | 4 +++ .../manage-email-settings.component.ts | 12 +++++-- .../manage-media-settings.component.ts | 10 ++++-- .../manage-settings.component.ts | 21 ++++++++++-- .../manage-tasks-settings.component.ts | 21 ++++++++++-- .../volume-card/volume-card.component.html | 29 ++++++++--------- .../draggable-ordered-list.component.ts | 2 +- .../series-detail/series-detail.component.ts | 32 +++++++++++++++---- UI/Web/src/assets/langs/en.json | 1 + 14 files changed, 159 insertions(+), 38 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f52d914e5..a7eca3f96 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -28,7 +28,7 @@ body: label: Kavita Version Number - If you don't see your version number listed, please update Kavita and see if your issue still persists. multiple: false options: - - 0.8.6.0 - Stable + - 0.8.6.1 - Stable - Nightly Testing Branch validations: required: true diff --git a/API/Controllers/VolumeController.cs b/API/Controllers/VolumeController.cs index 7181f6eef..db1381d9d 100644 --- a/API/Controllers/VolumeController.cs +++ b/API/Controllers/VolumeController.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; +using API.Constants; using API.Data; using API.Data.Repositories; using API.DTOs; @@ -54,4 +56,29 @@ public class VolumeController : BaseApiController return Ok(false); } + + [Authorize(Policy = "RequireAdminRole")] + [HttpPost("multiple")] + public async Task> DeleteMultipleVolumes(int[] volumesIds) + { + var volumes = await _unitOfWork.VolumeRepository.GetVolumesById(volumesIds); + if (volumes.Count != volumesIds.Length) + { + return BadRequest(_localizationService.Translate(User.GetUserId(), "volume-doesnt-exist")); + } + + _unitOfWork.VolumeRepository.Remove(volumes); + + if (!await _unitOfWork.CommitAsync()) + { + return Ok(false); + } + + foreach (var volume in volumes) + { + await _eventHub.SendMessageAsync(MessageFactory.VolumeRemoved, MessageFactory.VolumeRemovedEvent(volume.Id, volume.SeriesId), false); + } + + return Ok(true); + } } diff --git a/API/Data/Repositories/VolumeRepository.cs b/API/Data/Repositories/VolumeRepository.cs index cb0783a89..4b07ade96 100644 --- a/API/Data/Repositories/VolumeRepository.cs +++ b/API/Data/Repositories/VolumeRepository.cs @@ -35,6 +35,7 @@ public interface IVolumeRepository void Add(Volume volume); void Update(Volume volume); void Remove(Volume volume); + void Remove(IList volumes); Task> GetFilesForVolume(int volumeId); Task GetVolumeCoverImageAsync(int volumeId); Task> GetChapterIdsByVolumeIds(IReadOnlyList volumeIds); @@ -43,6 +44,7 @@ public interface IVolumeRepository Task GetVolumeDtoAsync(int volumeId, int userId); Task> GetVolumesForSeriesAsync(IList seriesIds, bool includeChapters = false); Task> GetVolumes(int seriesId); + Task> GetVolumesById(IList volumeIds, VolumeIncludes includes = VolumeIncludes.None); Task GetVolumeByIdAsync(int volumeId); Task> GetAllWithCoversInDifferentEncoding(EncodeFormat encodeFormat); Task> GetCoverImagesForLockedVolumesAsync(); @@ -72,6 +74,10 @@ public class VolumeRepository : IVolumeRepository { _context.Volume.Remove(volume); } + public void Remove(IList volumes) + { + _context.Volume.RemoveRange(volumes); + } /// /// Returns a list of non-tracked files for a given volume. @@ -180,6 +186,15 @@ public class VolumeRepository : IVolumeRepository .OrderBy(vol => vol.MinNumber) .ToListAsync(); } + public async Task> GetVolumesById(IList volumeIds, VolumeIncludes includes = VolumeIncludes.None) + { + return await _context.Volume + .Where(vol => volumeIds.Contains(vol.Id)) + .Includes(includes) + .AsSplitQuery() + .OrderBy(vol => vol.MinNumber) + .ToListAsync(); + } /// /// Returns a single volume with Chapter and Files diff --git a/API/I18N/pl.json b/API/I18N/pl.json index db3fa5063..68a4a1a4f 100644 --- a/API/I18N/pl.json +++ b/API/I18N/pl.json @@ -204,8 +204,8 @@ "person-image-doesnt-exist": "Osoba nie istnieje w CoversDB", "email-taken": "Adres e-mail jest już używany", "kavitaplus-restricted": "Jest to dostępne tylko dla Kavita+", - "smart-filter-name-required": "Strona internetowa", - "sidenav-stream-only-delete-smart-filter": "Jedynie filtry filtrowe mogą zostać usunięte z SideNav", - "dashboard-stream-only-delete-smart-filter": "Tylko inteligentne strumienie filtrów mogą zostać usunięte z rozdzielczości", + "smart-filter-name-required": "Inteligentny filtr wymaga nazwy", + "sidenav-stream-only-delete-smart-filter": "Tylko inteligentne filtry mogą zostać usunięte z panelu bocznego", + "dashboard-stream-only-delete-smart-filter": "Tylko inteligentne strumienie filtrów może zostać usunięte z głównego panelu", "smart-filter-system-name": "Nie można użyć nazwy systemu dostarczanego strumieniem" } diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 8bf6cdacd..1cf4e448e 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -472,8 +472,19 @@ export class ActionService { }); } + async deleteMultipleVolumes(volumes: Array, callback?: BooleanActionCallback) { + // TODO: Change translation key back to "toasts.confirm-delete-multiple-volumes" + if (!await this.confirmService.confirm(translate('toasts.confirm-delete-multiple-chapters', {count: volumes.length}))) return; + + this.volumeService.deleteMultipleVolumes(volumes.map(v => v.id)).subscribe((success) => { + if (callback) { + callback(success); + } + }) + } + async deleteMultipleChapters(seriesId: number, chapterIds: Array, callback?: BooleanActionCallback) { - if (!await this.confirmService.confirm(translate('toasts.confirm-delete-multiple-chapters'))) return; + if (!await this.confirmService.confirm(translate('toasts.confirm-delete-multiple-chapters', {count: chapterIds.length}))) return; this.chapterService.deleteMultipleChapters(seriesId, chapterIds.map(c => c.id)).subscribe(() => { if (callback) { diff --git a/UI/Web/src/app/_services/volume.service.ts b/UI/Web/src/app/_services/volume.service.ts index 16857b3d2..f53a20543 100644 --- a/UI/Web/src/app/_services/volume.service.ts +++ b/UI/Web/src/app/_services/volume.service.ts @@ -21,6 +21,10 @@ export class VolumeService { return this.httpClient.delete(this.baseUrl + 'volume?volumeId=' + volumeId); } + deleteMultipleVolumes(volumeIds: number[]) { + return this.httpClient.post(this.baseUrl + "volume/multiple", volumeIds) + } + updateVolume(volume: any) { return this.httpClient.post(this.baseUrl + 'volume/update', volume, TextResonse); } diff --git a/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts b/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts index d9aa1decb..8546ad921 100644 --- a/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts +++ b/UI/Web/src/app/admin/manage-email-settings/manage-email-settings.component.ts @@ -1,7 +1,7 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject, OnInit} from '@angular/core'; import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; import {ToastrService} from 'ngx-toastr'; -import {debounceTime, distinctUntilChanged, filter, switchMap, tap} from 'rxjs'; +import {catchError, debounceTime, distinctUntilChanged, filter, of, switchMap, tap} from 'rxjs'; import {SettingsService} from '../settings.service'; import {ServerSettings} from '../_models/server-settings'; import {translate, TranslocoModule} from "@jsverse/transloco"; @@ -46,15 +46,21 @@ export class ManageEmailSettingsComponent implements OnInit { // Automatically save settings as we edit them this.settingsForm.valueChanges.pipe( - debounceTime(300), distinctUntilChanged(), + debounceTime(300), filter(_ => this.settingsForm.valid), takeUntilDestroyed(this.destroyRef), switchMap(_ => { const data = this.packData(); - return this.settingsService.updateServerSettings(data); + return this.settingsService.updateServerSettings(data).pipe(catchError(err => { + console.error(err); + return of(null); + })); }), tap(settings => { + if (!settings) { + return; + } this.serverSettings = settings; this.cdRef.markForCheck(); }) diff --git a/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts b/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts index fbfb256dc..ac62e2038 100644 --- a/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts +++ b/UI/Web/src/app/admin/manage-media-settings/manage-media-settings.component.ts @@ -1,7 +1,7 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject, OnInit} from '@angular/core'; import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; import {ToastrService} from 'ngx-toastr'; -import {debounceTime, distinctUntilChanged, filter, switchMap, take, tap} from 'rxjs'; +import {catchError, debounceTime, distinctUntilChanged, filter, of, switchMap, take, tap} from 'rxjs'; import {SettingsService} from '../settings.service'; import {ServerSettings} from '../_models/server-settings'; import {DirectoryPickerComponent, DirectoryPickerResult} from '../_modals/directory-picker/directory-picker.component'; @@ -55,9 +55,15 @@ export class ManageMediaSettingsComponent implements OnInit { takeUntilDestroyed(this.destroyRef), switchMap(_ => { const data = this.packData(); - return this.settingsService.updateServerSettings(data); + return this.settingsService.updateServerSettings(data).pipe(catchError(err => { + console.error(err); + return of(null); + })); }), tap(settings => { + if (!settings) { + return; + } const encodingChanged = this.serverSettings.encodeMediaAs !== settings.encodeMediaAs; if (encodingChanged) { diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts index 33941f768..7c669e651 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts @@ -10,7 +10,7 @@ import {WikiLink} from "../../_models/wiki"; import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component"; import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component"; import {ConfirmService} from "../../shared/confirm.service"; -import {debounceTime, distinctUntilChanged, filter, switchMap, tap} from "rxjs"; +import {catchError, debounceTime, distinctUntilChanged, filter, of, switchMap, tap} from "rxjs"; import {takeUntilDestroyed} from "@angular/core/rxjs-interop"; import {DefaultValuePipe} from "../../_pipes/default-value.pipe"; import {EnterBlurDirective} from "../../_directives/enter-blur.directive"; @@ -40,6 +40,7 @@ export class ManageSettingsComponent implements OnInit { settingsForm: FormGroup = new FormGroup({}); taskFrequencies: Array = []; logLevels: Array = []; + isDocker: boolean = false; allowStatsTooltip = translate('manage-settings.allow-stats-tooltip-part-1') + ' - -
- @if (libraryType === LibraryType.LightNovel || libraryType === LibraryType.Book) { - {{volume.name}} - } @else { - {{volume.chapters[0].titleName}} - } -
- - @if (actions && actions.length > 0) { - - - + @if ((libraryType === LibraryType.LightNovel || libraryType === LibraryType.Book)) { + @if (volume.name) { +
+
+ {{volume.name}} +
+
} - + } @else if (volume.chapters[0].titleName) { +
+
+ {{volume.chapters[0].titleName}} +
+
+ } }
diff --git a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts index 3a3087632..22405364f 100644 --- a/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts +++ b/UI/Web/src/app/reading-list/_components/draggable-ordered-list/draggable-ordered-list.component.ts @@ -82,7 +82,7 @@ export class DraggableOrderedListComponent { get BufferAmount() { - return Math.min(this.items.length / 20, 20); + return Math.floor(Math.min(this.items.length / 20, 20)); } constructor() { diff --git a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts index 890237be4..68d2ac4dd 100644 --- a/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts +++ b/UI/Web/src/app/series-detail/_components/series-detail/series-detail.component.ts @@ -115,6 +115,7 @@ import {CoverImageComponent} from "../../../_single-module/cover-image/cover-ima import {DefaultModalOptions} from "../../../_models/default-modal-options"; import {LicenseService} from "../../../_services/license.service"; import {PageBookmark} from "../../../_models/readers/page-bookmark"; +import {VolumeRemovedEvent} from "../../../_models/events/volume-removed-event"; enum TabID { @@ -353,11 +354,25 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked { this.cdRef.markForCheck(); break; case Action.Delete: - await this.actionService.deleteMultipleChapters(seriesId, chapters, () => { - // No need to update the page as the backend will spam volume/chapter deletions - this.bulkSelectionService.deselectAll(); - this.cdRef.markForCheck(); - }); + if (chapters.length > 0) { + await this.actionService.deleteMultipleChapters(seriesId, chapters, () => { + // No need to update the page as the backend will spam volume/chapter deletions + this.bulkSelectionService.deselectAll(); + this.cdRef.markForCheck(); + }); + + // It's not possible to select both chapters and volumes + break; + } + + if (selectedVolumeIds.length > 0) { + await this.actionService.deleteMultipleVolumes(selectedVolumeIds, () => { + // No need to update the page as the backend will spam volume deletions + this.bulkSelectionService.deselectAll(); + this.cdRef.markForCheck(); + }); + } + break; } } @@ -486,6 +501,11 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked { const removedEvent = event.payload as ChapterRemovedEvent; if (removedEvent.seriesId !== this.seriesId) return; this.loadPageSource.next(false); + } else if (event.event === EVENTS.VolumeRemoved) { + const volumeRemoveEvent = event.payload as VolumeRemovedEvent; + if (volumeRemoveEvent.seriesId === this.seriesId) { + this.loadPageSource.next(false); + } } }); @@ -660,7 +680,7 @@ export class SeriesDetailComponent implements OnInit, AfterContentChecked { case (Action.Delete): await this.actionService.deleteChapter(chapter.id, (success) => { if (!success) return; - + this.chapters = this.chapters.filter(c => c.id != chapter.id); this.cdRef.markForCheck(); }); diff --git a/UI/Web/src/assets/langs/en.json b/UI/Web/src/assets/langs/en.json index 4d8a07210..dc409848f 100644 --- a/UI/Web/src/assets/langs/en.json +++ b/UI/Web/src/assets/langs/en.json @@ -2628,6 +2628,7 @@ "alert-long-running": "This is a long running process. Please give it the time to complete before invoking again.", "confirm-delete-multiple-series": "Are you sure you want to delete {{count}} series? It will not modify files on disk.", "confirm-delete-multiple-chapters": "Are you sure you want to delete {{count}} chapter/volumes? It will not modify files on disk.", + "confirm-delete-multiple-volumes": "Are you sure you want to delete {{count}} volumes? It will not modify files on disk.", "confirm-delete-series": "Are you sure you want to delete this series? It will not modify files on disk.", "confirm-delete-chapter": "Are you sure you want to delete this chapter? It will not modify files on disk.", "confirm-delete-volume": "Are you sure you want to delete this volume? It will not modify files on disk.", From 925ae83baf5677d36f30ce6a94705b9837f784c6 Mon Sep 17 00:00:00 2001 From: majora2007 Date: Fri, 18 Apr 2025 11:49:19 +0000 Subject: [PATCH 3/9] Bump versions by dotnet-bump-version. --- Kavita.Common/Kavita.Common.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 419748032..766f142e2 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -3,7 +3,7 @@ net9.0 kavitareader.com Kavita - 0.8.6.0 + 0.8.6.1 en true @@ -20,4 +20,4 @@ - + \ No newline at end of file From e76a7152db40c78887792c31fc89007169656361 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 18 Apr 2025 11:50:31 +0000 Subject: [PATCH 4/9] Update OpenAPI documentation --- openapi.json | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/openapi.json b/openapi.json index db02f4511..8a95924d4 100644 --- a/openapi.json +++ b/openapi.json @@ -14508,6 +14508,66 @@ } } }, + "/api/Volume/multiple": { + "post": { + "tags": [ + "Volume" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + "text/json": { + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + "application/*+json": { + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain": { + "schema": { + "type": "boolean" + } + }, + "application/json": { + "schema": { + "type": "boolean" + } + }, + "text/json": { + "schema": { + "type": "boolean" + } + } + } + } + } + } + }, "/api/want-to-read": { "post": { "tags": [ From a1264cb5e85d5a5690bcb5ad905001a24146334d Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Fri, 18 Apr 2025 06:32:42 -0600 Subject: [PATCH 5/9] v0.8.6.1 - A few small issues Hotfix (#3749) --- API/Services/Tasks/StatsService.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs index 2e3a0f43c..5d5df6647 100644 --- a/API/Services/Tasks/StatsService.cs +++ b/API/Services/Tasks/StatsService.cs @@ -178,7 +178,6 @@ public class StatsService : IStatsService var sw = Stopwatch.StartNew(); var response = await (Configuration.StatsApiUrl + "/api/health/") .WithBasicHeaders(ApiKey) - .WithTimeout(TimeSpan.FromSeconds(30)) .GetAsync(); if (response.StatusCode == StatusCodes.Status200OK) @@ -197,7 +196,7 @@ public class StatsService : IStatsService private async Task MaxSeriesInAnyLibrary() { - // If first time flow, just return 0 + // If first time flow, return 0 if (!await _context.Series.AnyAsync()) return 0; return await _context.Series .Select(s => _context.Library.Where(l => l.Id == s.LibraryId).SelectMany(l => l.Series!).Count()) From d3f8a503c21480bedb5f8d05b500dd21d2eb211b Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Fri, 18 Apr 2025 12:34:41 +0000 Subject: [PATCH 6/9] Update OpenAPI documentation --- openapi.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openapi.json b/openapi.json index 8a95924d4..e71ecfd55 100644 --- a/openapi.json +++ b/openapi.json @@ -1,8 +1,8 @@ { "openapi": "3.0.4", "info": { - "title": "Kavita (v0.8.6.0)", - "description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.6.0", + "title": "Kavita (v0.8.6.1)", + "description": "Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v0.8.6.1", "license": { "name": "GPL-3.0", "url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE" From 14bf4400a9faec6c165ca332acd5b3580a825a00 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Sun, 20 Apr 2025 10:46:33 -0600 Subject: [PATCH 7/9] v0.8.6.2 - General Settings Hotfix (#3756) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com> Co-authored-by: Weblate (bot) Co-authored-by: Lyrq Co-authored-by: Ricky Tigg Co-authored-by: 無情天 --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- .github/workflows/codeql.yml | 2 +- API/API.csproj | 1 + API/Services/CacheService.cs | 1 + API/config/appsettings.Development.json | 2 +- .../manage-settings.component.html | 4 ++-- .../manage-settings.component.ts | 20 +++++++++++++++++-- UI/Web/src/assets/langs/fi.json | 2 +- UI/Web/src/assets/langs/zh_Hans.json | 4 ++-- 9 files changed, 28 insertions(+), 10 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index a7eca3f96..cdd72de1c 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -28,7 +28,7 @@ body: label: Kavita Version Number - If you don't see your version number listed, please update Kavita and see if your issue still persists. multiple: false options: - - 0.8.6.1 - Stable + - 0.8.6.2 - Stable - Nightly Testing Branch validations: required: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a77338866..7ce4276bc 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -13,7 +13,7 @@ name: "CodeQL" on: push: - branches: [ "develop", "main" ] + branches: [ "develop"] pull_request: # The branches below must be a subset of the branches above branches: [ "develop" ] diff --git a/API/API.csproj b/API/API.csproj index 52c390f4e..80f371b7a 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -115,6 +115,7 @@ + diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index d008ab5f5..a2acc538b 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -186,6 +186,7 @@ public class CacheService : ICacheService } else { + // Potential BUG: If the folder is left here and there are no files within, this could theoretically return without proper cache return chapter; } } diff --git a/API/config/appsettings.Development.json b/API/config/appsettings.Development.json index 0c6352d06..ad2d89fa5 100644 --- a/API/config/appsettings.Development.json +++ b/API/config/appsettings.Development.json @@ -1,7 +1,7 @@ { "TokenKey": "super secret unguessable key that is longer because we require it", "Port": 5000, - "IpAddresses": "0.0.0.0,::", + "IpAddresses": "", "BaseUrl": "/", "Cache": 75, "AllowIFraming": false diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html index d7a2e8c6c..7e0b86f87 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.html +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.html @@ -64,7 +64,7 @@ @if (settingsForm.get('ipAddresses'); as formControl) { - {{formControl.value}} + {{formControl.value | defaultValue}}
@@ -75,7 +75,7 @@ @if(settingsForm.dirty || !settingsForm.untouched) {
- @if (formControl.errors?.pattern) { + @if (formControl.errors?.emptyOrPattern) {
{{t('ip-address-validation')}}
}
diff --git a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts index 7c669e651..8c5f3f17a 100644 --- a/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts +++ b/UI/Web/src/app/admin/manage-settings/manage-settings.component.ts @@ -1,5 +1,5 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject, OnInit} from '@angular/core'; -import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms'; +import {FormControl, FormGroup, ReactiveFormsModule, ValidatorFn, Validators} from '@angular/forms'; import {ToastrService} from 'ngx-toastr'; import {take} from 'rxjs/operators'; import {ServerService} from 'src/app/_services/server.service'; @@ -62,7 +62,7 @@ export class ManageSettingsComponent implements OnInit { this.settingsForm.addControl('taskScan', new FormControl(this.serverSettings.taskScan, [Validators.required])); this.settingsForm.addControl('taskBackup', new FormControl(this.serverSettings.taskBackup, [Validators.required])); this.settingsForm.addControl('taskCleanup', new FormControl(this.serverSettings.taskCleanup, [Validators.required])); - this.settingsForm.addControl('ipAddresses', new FormControl(this.serverSettings.ipAddresses, [Validators.required, Validators.pattern(ValidIpAddress)])); + this.settingsForm.addControl('ipAddresses', new FormControl(this.serverSettings.ipAddresses, [this.emptyOrPattern(ValidIpAddress)])); this.settingsForm.addControl('port', new FormControl(this.serverSettings.port, [Validators.required])); this.settingsForm.addControl('loggingLevel', new FormControl(this.serverSettings.loggingLevel, [Validators.required])); this.settingsForm.addControl('allowStatCollection', new FormControl(this.serverSettings.allowStatCollection, [Validators.required])); @@ -77,6 +77,7 @@ export class ManageSettingsComponent implements OnInit { this.settingsForm.addControl('onDeckProgressDays', new FormControl(this.serverSettings.onDeckProgressDays, [Validators.required])); this.settingsForm.addControl('onDeckUpdateDays', new FormControl(this.serverSettings.onDeckUpdateDays, [Validators.required])); + // Automatically save settings as we edit them this.settingsForm.valueChanges.pipe( distinctUntilChanged(), @@ -186,4 +187,19 @@ export class ManageSettingsComponent implements OnInit { console.error('error: ', err); }); } + + emptyOrPattern(pattern: RegExp): ValidatorFn { + return (control) => { + if (!control.value || control.value.length === 0) { + return null; + } + + if (pattern.test(control.value)) { + return null; + } + + return { 'emptyOrPattern': { 'requiredPattern': pattern.toString(), 'actualValue': control.value } }; + } + } + } diff --git a/UI/Web/src/assets/langs/fi.json b/UI/Web/src/assets/langs/fi.json index edcd8166f..9a316f77a 100644 --- a/UI/Web/src/assets/langs/fi.json +++ b/UI/Web/src/assets/langs/fi.json @@ -10,7 +10,7 @@ "devices-tab": "{{tabs.devices-tab}}", "smart-filters-tab": "{{tabs.smart-filters-tab}}", "success-toast": "Käyttäjäasetukset päivitetty", - "global-settings-title": "Laajamittaiset asetukset", + "global-settings-title": "Yleisesti pätevät asetukset", "page-layout-mode-label": "Sivun asettelutila", "page-layout-mode-tooltip": "Näytä kohteet kortteina tai luettelonäkymänä Sarjojen yksityiskohdat -sivulla.", "locale-label": "Kieliasetus", diff --git a/UI/Web/src/assets/langs/zh_Hans.json b/UI/Web/src/assets/langs/zh_Hans.json index d3a8496e0..a81869f69 100644 --- a/UI/Web/src/assets/langs/zh_Hans.json +++ b/UI/Web/src/assets/langs/zh_Hans.json @@ -2219,12 +2219,12 @@ "delete-device": "您确定要删除该设备吗?", "confirm-regen-covers": "刷新封面将强制重新生成所有封面图片。这是一项繁重的运算。您确定执行,而不想使用扫描操作代替吗?", "alert-long-running": "这是一个长时间运行的任务。请等待其完成后再次进行操作。", - "confirm-delete-multiple-series": "您确定要删除{{count}}个系列吗?这不会修改磁盘上的文件。", + "confirm-delete-multiple-series": "您确定要删除这 {{count}} 个系列吗?这不会修改磁盘上的文件。", "confirm-delete-series": "您确定要删除此系列吗?这不会修改磁盘上的文件。", "confirm-delete-chapter": "您确定要删除此章节吗?它不会修改磁盘上的文件。", "confirm-delete-volume": "您确定要删除此卷吗?它不会修改磁盘上的文件。", "alert-bad-theme": "主题中存在无效或不安全的CSS。请联系管理员进行修正。将默认为暗色主题。", - "confirm-library-delete": "您确定要删除{{name}}资料库吗?此操作无法撤销。", + "confirm-library-delete": "您确定要删除 {{name}} 资料库吗?此操作无法撤销。", "confirm-library-type-change": "更改资料库类型将触发具有不同解析规则的新扫描,并可能导致重新创建系列,因此您可能会丢失进度和书签。您应该在执行此操作之前进行备份。您确定要继续吗?", "confirm-download-size": "{{entityType}}的大小为{{size}}。确定要继续吗?", "confirm-download-size-ios": "iOS 在下载大于 200MB 的文件时出现问题,此下载可能无法完成。", From 9bb741a81bbbf3c86f053dd7e85b498f2740546f Mon Sep 17 00:00:00 2001 From: majora2007 Date: Sun, 20 Apr 2025 16:47:15 +0000 Subject: [PATCH 8/9] Bump versions by dotnet-bump-version. --- Kavita.Common/Kavita.Common.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Kavita.Common/Kavita.Common.csproj b/Kavita.Common/Kavita.Common.csproj index 766f142e2..8b6730ba3 100644 --- a/Kavita.Common/Kavita.Common.csproj +++ b/Kavita.Common/Kavita.Common.csproj @@ -3,7 +3,7 @@ net9.0 kavitareader.com Kavita - 0.8.6.1 + 0.8.6.2 en true From 06a6d9e03b4b5c0d90b74c6190190aa720299e56 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Sun, 20 Apr 2025 11:00:56 -0600 Subject: [PATCH 9/9] v0.8.6.2 - General Settings Hotfix (#3761) --- CONTRIBUTING.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 43cd2e208..292217862 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ Setup guides, FAQ, the more information we have on the [wiki](https://wiki.kavit - HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc) - [Git](https://git-scm.com/downloads) - [NodeJS](https://nodejs.org/en/download/) (Node 18.13.X or higher) -- .NET 8.0+ +- .NET 9.0+ - dotnet tool install -g Swashbuckle.AspNetCore.Cli ### Getting started ### diff --git a/README.md b/README.md index 1ea5a94ca..bff8f0f5c 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ your reading collection with your friends and family! ## Demo If you want to try out Kavita, a demo is available: -[https://demo.kavitareader.com/](https://demo.kavitareader.com/) +[https://demo.kavitareader.com/](https://demo.kavitareader.com/login?apiKey=9003cf99-9213-4206-a787-af2fe4cc5f1f) ``` Username: demouser Password: Demouser64