Fixes v0.4.19! (#855)

* Fixed OPDS urls to work with new Filtering schema

* Fixed a rendering issue with Language tag when it's null

* Fixed a bug where locked covers were resetting during refresh metadata.

* Redid all the migrations and put some extra checks due to a bad migration from previous release (EF Core was producing an error).

* Fixed a bug which didn't take sort direction when not changing sort field

* Default installs now backup daily
This commit is contained in:
Joseph Milazzo 2021-12-17 12:46:01 -06:00 committed by GitHub
parent 036aa331d2
commit 12889be788
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 110 additions and 2648 deletions

View File

@ -49,13 +49,13 @@
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.1">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.2.0" />
<PackageReference Include="NetVips" Version="2.1.0" />

View File

@ -34,7 +34,26 @@ public class OpdsController : BaseApiController
private const string Prefix = "/api/opds/";
private readonly FilterDto _filterDto = new FilterDto()
{
Formats = new List<MangaFormat>()
Formats = new List<MangaFormat>(),
Character = new List<int>(),
Colorist = new List<int>(),
Editor = new List<int>(),
Genres = new List<int>(),
Inker = new List<int>(),
Languages = new List<string>(),
Letterer = new List<int>(),
Penciller = new List<int>(),
Libraries = new List<int>(),
Publisher = new List<int>(),
Rating = 0,
Tags = new List<int>(),
Translators = new List<int>(),
Writers = new List<int>(),
AgeRating = new List<AgeRating>(),
CollectionTags = new List<int>(),
CoverArtist = new List<int>(),
ReadStatus = new ReadStatus(),
SortOptions = null
};
private readonly ChapterSortComparer _chapterSortComparer = new ChapterSortComparer();

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace API.Data.Migrations
{
public partial class SeriesIncludes : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_AppUserRating_SeriesId",
table: "AppUserRating",
column: "SeriesId");
migrationBuilder.CreateIndex(
name: "IX_AppUserProgresses_SeriesId",
table: "AppUserProgresses",
column: "SeriesId");
migrationBuilder.AddForeignKey(
name: "FK_AppUserProgresses_Series_SeriesId",
table: "AppUserProgresses",
column: "SeriesId",
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AppUserRating_Series_SeriesId",
table: "AppUserRating",
column: "SeriesId",
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AppUserProgresses_Series_SeriesId",
table: "AppUserProgresses");
migrationBuilder.DropForeignKey(
name: "FK_AppUserRating_Series_SeriesId",
table: "AppUserRating");
migrationBuilder.DropIndex(
name: "IX_AppUserRating_SeriesId",
table: "AppUserRating");
migrationBuilder.DropIndex(
name: "IX_AppUserProgresses_SeriesId",
table: "AppUserProgresses");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace API.Data.Migrations
{
public partial class seriesLanguage : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Language",
table: "SeriesMetadata",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Language",
table: "SeriesMetadata");
}
}
}

View File

@ -11,13 +11,13 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
namespace API.Data.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20211216191436_seriesLanguage")]
partial class seriesLanguage
[Migration("20211217180457_filteringChanges")]
partial class filteringChanges
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
modelBuilder.Entity("API.Entities.AppRole", b =>
{

View File

@ -4,10 +4,16 @@
namespace API.Data.Migrations
{
public partial class seriesAndChapterTags : Migration
public partial class filteringChanges : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Language",
table: "SeriesMetadata",
type: "TEXT",
nullable: true);
migrationBuilder.CreateTable(
name: "Tag",
columns: table => new
@ -71,6 +77,16 @@ namespace API.Data.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_AppUserRating_SeriesId",
table: "AppUserRating",
column: "SeriesId");
migrationBuilder.CreateIndex(
name: "IX_AppUserProgresses_SeriesId",
table: "AppUserProgresses",
column: "SeriesId");
migrationBuilder.CreateIndex(
name: "IX_ChapterTag_TagsId",
table: "ChapterTag",
@ -86,10 +102,34 @@ namespace API.Data.Migrations
table: "Tag",
columns: new[] { "NormalizedTitle", "ExternalTag" },
unique: true);
migrationBuilder.AddForeignKey(
name: "FK_AppUserProgresses_Series_SeriesId",
table: "AppUserProgresses",
column: "SeriesId",
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_AppUserRating_Series_SeriesId",
table: "AppUserRating",
column: "SeriesId",
principalTable: "Series",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_AppUserProgresses_Series_SeriesId",
table: "AppUserProgresses");
migrationBuilder.DropForeignKey(
name: "FK_AppUserRating_Series_SeriesId",
table: "AppUserRating");
migrationBuilder.DropTable(
name: "ChapterTag");
@ -98,6 +138,18 @@ namespace API.Data.Migrations
migrationBuilder.DropTable(
name: "Tag");
migrationBuilder.DropIndex(
name: "IX_AppUserRating_SeriesId",
table: "AppUserRating");
migrationBuilder.DropIndex(
name: "IX_AppUserProgresses_SeriesId",
table: "AppUserProgresses");
migrationBuilder.DropColumn(
name: "Language",
table: "SeriesMetadata");
}
}
}

View File

@ -15,7 +15,7 @@ namespace API.Data.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "6.0.1");
modelBuilder.HasAnnotation("ProductVersion", "6.0.0");
modelBuilder.Entity("API.Entities.AppRole", b =>
{

View File

@ -44,7 +44,7 @@ namespace API.Data
new () {Key = ServerSettingKey.CacheDirectory, Value = directoryService.CacheDirectory},
new () {Key = ServerSettingKey.TaskScan, Value = "daily"},
new () {Key = ServerSettingKey.LoggingLevel, Value = "Information"}, // Not used from DB, but DB is sync with appSettings.json
new () {Key = ServerSettingKey.TaskBackup, Value = "weekly"},
new () {Key = ServerSettingKey.TaskBackup, Value = "daily"},
new () {Key = ServerSettingKey.BackupDirectory, Value = Path.GetFullPath(DirectoryService.BackupDirectory)},
new () {Key = ServerSettingKey.Port, Value = "5000"}, // Not used from DB, but DB is sync with appSettings.json
new () {Key = ServerSettingKey.AllowStatCollection, Value = "true"},

View File

@ -56,6 +56,7 @@ namespace API.Extensions
services.AddDbContext<DataContext>(options =>
{
options.UseSqlite(config.GetConnectionString("DefaultConnection"));
options.EnableDetailedErrors();
options.EnableSensitiveDataLogging(env.IsDevelopment() || Configuration.LogLevel.Equals("Debug"));
});
}

View File

@ -38,7 +38,7 @@ public class CacheHelper : ICacheHelper
public bool ShouldUpdateCoverImage(string coverPath, MangaFile firstFile, DateTime chapterCreated, bool forceUpdate = false,
bool isCoverLocked = false)
{
if (firstFile == null) return true;
if (firstFile == null) return false;
var fileExists = !string.IsNullOrEmpty(coverPath) && _fileService.Exists(coverPath);
if (isCoverLocked && fileExists) return false;

View File

@ -1,11 +1,13 @@
using System;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using API.Data;
using API.Entities;
using API.Services;
using API.Services.Tasks;
using Kavita.Common;
using Kavita.Common.EnvironmentInfo;
using Microsoft.AspNetCore.Hosting;
@ -64,12 +66,6 @@ namespace API
return;
}
// This doesn't work either
//var directoryService = services.GetRequiredService<DirectoryService>();
var requiresCoverImageMigration = !Directory.Exists(directoryService.CoverImageDirectory);
try
{
@ -85,6 +81,16 @@ namespace API
}
// Apply all migrations on startup
// If we have pending migrations, make a backup first
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
if (pendingMigrations.Any())
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogInformation("Performing backup as migrations are needed");
// var backupService = services.GetRequiredService<BackupService>();
// await backupService.BackupDatabase();
}
await context.Database.MigrateAsync();
if (requiresCoverImageMigration)
@ -99,7 +105,7 @@ namespace API
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred during migration");
logger.LogCritical(ex, "An error occurred during migration");
}
await host.RunAsync();

View File

@ -20,7 +20,7 @@ namespace API.Services.HostedServices
using var scope = _provider.CreateScope();
var taskScheduler = scope.ServiceProvider.GetRequiredService<ITaskScheduler>();
taskScheduler.ScheduleTasks();
await taskScheduler.ScheduleTasks();
taskScheduler.ScheduleUpdaterTasks();
try

View File

@ -12,7 +12,7 @@ namespace API.Services;
public interface ITaskScheduler
{
void ScheduleTasks();
Task ScheduleTasks();
Task ScheduleStatsTasks();
void ScheduleUpdaterTasks();
void ScanLibrary(int libraryId, bool forceUpdate = false);
@ -58,11 +58,11 @@ public class TaskScheduler : ITaskScheduler
_directoryService = directoryService;
}
public void ScheduleTasks()
public async Task ScheduleTasks()
{
_logger.LogInformation("Scheduling reoccurring tasks");
var setting = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).GetAwaiter().GetResult().Value;
var setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskScan)).Value;
if (setting != null)
{
var scanLibrarySetting = setting;
@ -75,7 +75,7 @@ public class TaskScheduler : ITaskScheduler
RecurringJob.AddOrUpdate("scan-libraries", () => _scannerService.ScanLibraries(), Cron.Daily, TimeZoneInfo.Local);
}
setting = Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Result.Value;
setting = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.TaskBackup)).Value;
if (setting != null)
{
_logger.LogDebug("Scheduling Backup Task for {Setting}", setting);

View File

@ -529,9 +529,14 @@ export class CardDetailLayoutComponent implements OnInit, OnDestroy {
updateSortOrder() {
this.isAscendingSort = !this.isAscendingSort;
if (this.filter.sortOptions !== null) {
this.filter.sortOptions.isAscending = this.isAscendingSort;
if (this.filter.sortOptions === null) {
this.filter.sortOptions = {
isAscending: this.isAscendingSort,
sortField: SortField.SortName
}
}
this.filter.sortOptions.isAscending = this.isAscendingSort;
}
getPersonsSettings(role: PersonRole) {

View File

@ -1,5 +1,5 @@
<app-bulk-operations [actionCallback]="bulkActionCallback"></app-bulk-operations>
<app-card-detail-layout header="{{libraryName}}"
<app-card-detail-layout [header]="libraryName"
[isLoading]="loadingSeries"
[items]="series"
[actions]="actions"

View File

@ -9,7 +9,7 @@
<!-- Maybe we can put the library this resides in to make it easier to get back -->
<!-- tooltip here explaining how this is year of first issue -->
<app-tag-badge *ngIf="seriesMetadata.releaseYear > 0" title="Release date">{{seriesMetadata.releaseYear}}</app-tag-badge>
<app-tag-badge *ngIf="seriesMetadata.language !== ''" title="Language">{{seriesMetadata.language}}</app-tag-badge>
<app-tag-badge *ngIf="seriesMetadata.language !== null && seriesMetadata.language !== ''" title="Language">{{seriesMetadata.language}}</app-tag-badge>
<app-tag-badge [selectionMode]="TagBadgeCursor.NotAllowed">
<app-series-format [format]="series.format">{{utilityService.mangaFormat(series.format)}}</app-series-format>
</app-tag-badge>