Hotfix Prep (#2484)

This commit is contained in:
Joe Milazzo 2023-12-10 12:47:25 -06:00 committed by GitHub
parent 8c16b87ff0
commit bd4cbeb393
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 114 additions and 87 deletions

View file

@ -26,6 +26,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SharpCompress;
namespace API.Controllers;
@ -137,8 +138,7 @@ public class AccountController : BaseApiController
if (!result.Succeeded) return BadRequest(result.Errors);
// Assign default streams
user.DashboardStreams = Seed.DefaultStreams.ToList();
user.SideNavStreams = Seed.DefaultSideNavStreams.ToList();
AddDefaultStreamsToUser(user);
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
if (string.IsNullOrEmpty(token)) return BadRequest(await _localizationService.Get("en", "confirm-token-gen"));
@ -608,7 +608,8 @@ public class AccountController : BaseApiController
}
// Create a new user
var user = new AppUserBuilder(dto.Email, dto.Email, await _unitOfWork.SiteThemeRepository.GetDefaultTheme()).Build();
var user = new AppUserBuilder(dto.Email, dto.Email,
await _unitOfWork.SiteThemeRepository.GetDefaultTheme()).Build();
_unitOfWork.UserRepository.Add(user);
try
{
@ -616,9 +617,7 @@ public class AccountController : BaseApiController
if (!result.Succeeded) return BadRequest(result.Errors);
// Assign default streams
user.DashboardStreams = Seed.DefaultStreams.ToList();
user.SideNavStreams = Seed.DefaultSideNavStreams.ToList();
AddDefaultStreamsToUser(user);
// Assign Roles
var roles = dto.Roles;
@ -657,7 +656,6 @@ public class AccountController : BaseApiController
user.CreateSideNavFromLibrary(lib);
}
_unitOfWork.UserRepository.Update(user);
user.AgeRestriction = hasAdminRole ? AgeRating.NotApplicable : dto.AgeRestriction.AgeRating;
user.AgeRestrictionIncludeUnknowns = hasAdminRole || dto.AgeRestriction.IncludeUnknowns;
@ -669,6 +667,7 @@ public class AccountController : BaseApiController
}
user.ConfirmationToken = token;
_unitOfWork.UserRepository.Update(user);
await _unitOfWork.CommitAsync();
}
catch (Exception ex)
@ -702,7 +701,7 @@ public class AccountController : BaseApiController
BackgroundJob.Enqueue(() => _emailService.SendConfirmationEmail(new ConfirmationEmailDto()
{
EmailAddress = dto.Email,
InvitingUser = adminUser.UserName!,
InvitingUser = adminUser.UserName,
ServerConfirmationLink = emailLink
}));
}
@ -721,6 +720,19 @@ public class AccountController : BaseApiController
return BadRequest(await _localizationService.Translate(User.GetUserId(), "generic-invite-user"));
}
private void AddDefaultStreamsToUser(AppUser user)
{
foreach (var newStream in Seed.DefaultStreams.Select(stream => _mapper.Map<AppUserDashboardStream, AppUserDashboardStream>(stream)))
{
user.DashboardStreams.Add(newStream);
}
foreach (var stream in Seed.DefaultSideNavStreams.Select(stream => _mapper.Map<AppUserSideNavStream, AppUserSideNavStream>(stream)))
{
user.SideNavStreams.Add(stream);
}
}
/// <summary>
/// Last step in authentication flow, confirms the email token for email
/// </summary>

View file

@ -115,10 +115,6 @@ public class ReaderController : BaseApiController
try
{
if (new Random().Next(1, 10) > 5)
{
await Task.Delay(1000);
}
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
if (chapter == null) return NoContent();
_logger.LogInformation("Fetching Page {PageNum} on Chapter {ChapterId}", page, chapterId);

View file

@ -76,48 +76,42 @@ public static class Seed
},
}.ToArray());
public static readonly ImmutableArray<AppUserSideNavStream> DefaultSideNavStreams = ImmutableArray.Create(new[]
public static readonly ImmutableArray<AppUserSideNavStream> DefaultSideNavStreams = ImmutableArray.Create(
new AppUserSideNavStream()
{
new AppUserSideNavStream()
{
Name = "want-to-read",
StreamType = SideNavStreamType.WantToRead,
Order = 1,
IsProvided = true,
Visible = true
},
new AppUserSideNavStream()
{
Name = "collections",
StreamType = SideNavStreamType.Collections,
Order = 2,
IsProvided = true,
Visible = true
},
new AppUserSideNavStream()
{
Name = "reading-lists",
StreamType = SideNavStreamType.ReadingLists,
Order = 3,
IsProvided = true,
Visible = true
},
new AppUserSideNavStream()
{
Name = "bookmarks",
StreamType = SideNavStreamType.Bookmarks,
Order = 4,
IsProvided = true,
Visible = true
},
new AppUserSideNavStream()
{
Name = "all-series",
StreamType = SideNavStreamType.AllSeries,
Order = 5,
IsProvided = true,
Visible = true
}
Name = "want-to-read",
StreamType = SideNavStreamType.WantToRead,
Order = 1,
IsProvided = true,
Visible = true
}, new AppUserSideNavStream()
{
Name = "collections",
StreamType = SideNavStreamType.Collections,
Order = 2,
IsProvided = true,
Visible = true
}, new AppUserSideNavStream()
{
Name = "reading-lists",
StreamType = SideNavStreamType.ReadingLists,
Order = 3,
IsProvided = true,
Visible = true
}, new AppUserSideNavStream()
{
Name = "bookmarks",
StreamType = SideNavStreamType.Bookmarks,
Order = 4,
IsProvided = true,
Visible = true
}, new AppUserSideNavStream()
{
Name = "all-series",
StreamType = SideNavStreamType.AllSeries,
Order = 5,
IsProvided = true,
Visible = true
});

View file

@ -240,9 +240,10 @@ public class AutoMapperProfiles : Profile
CreateMap<AppUserSmartFilter, SmartFilterDto>();
CreateMap<AppUserDashboardStream, DashboardStreamDto>();
// CreateMap<AppUserDashboardStream, DashboardStreamDto>()
// .ForMember(dest => dest.SmartFilterEncoded,
// opt => opt.MapFrom(src => src.SmartFilter));
// This is for cloning to ensure the records don't get overwritten when setting from SeedData
CreateMap<AppUserDashboardStream, AppUserDashboardStream>();
CreateMap<AppUserSideNavStream, AppUserSideNavStream>();
}
}

View file

@ -27,6 +27,8 @@ public class PlusSeriesDtoBuilder : IEntityBuilder<PlusSeriesDto>
ScrobblingService.MalWeblinkWebsite),
GoogleBooksId = ScrobblingService.ExtractId<string?>(series.Metadata.WebLinks,
ScrobblingService.GoogleBooksWeblinkWebsite),
MangaDexId = ScrobblingService.ExtractId<string?>(series.Metadata.WebLinks,
ScrobblingService.MangaDexWeblinkWebsite),
VolumeCount = series.Volumes.Count,
ChapterCount = series.Volumes.SelectMany(v => v.Chapters).Count(c => !c.IsSpecial),
Year = series.Metadata.ReleaseYear

View file

@ -133,7 +133,7 @@ public static class SmartFilterHelper
var sortFieldPart = parts.FirstOrDefault(part => part.StartsWith(SortFieldKey));
var isAscendingPart = parts.FirstOrDefault(part => part.StartsWith(IsAscendingKey));
var isAscending = isAscendingPart?.Substring(11).Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
var isAscending = isAscendingPart?.Trim().Replace(IsAscendingKey, string.Empty).Equals("true", StringComparison.OrdinalIgnoreCase) ?? false;
if (sortFieldPart == null)
{
return new SortOptions();

View file

@ -25,6 +25,7 @@ public record PlusSeriesDto
public int? AniListId { get; set; }
public long? MalId { get; set; }
public string? GoogleBooksId { get; set; }
public string? MangaDexId { get; set; }
public string SeriesName { get; set; }
public string? AltSeriesName { get; set; }
public MediaFormat MediaFormat { get; set; }

View file

@ -67,13 +67,14 @@ public class ScrobblingService : IScrobblingService
public const string AniListWeblinkWebsite = "https://anilist.co/manga/";
public const string MalWeblinkWebsite = "https://myanimelist.net/manga/";
public const string GoogleBooksWeblinkWebsite = "https://books.google.com/books?id=";
public const string MangaDexWeblinkWebsite = "https://mangadex.org/title/";
private static readonly IDictionary<string, int> WeblinkExtractionMap = new Dictionary<string, int>()
{
{AniListWeblinkWebsite, 0},
{MalWeblinkWebsite, 0},
{GoogleBooksWeblinkWebsite, 0},
{MangaDexWeblinkWebsite, 0},
};
private const int ScrobbleSleepTime = 700; // We can likely tie this to AniList's 90 rate / min ((60 * 1000) / 90)
@ -829,12 +830,12 @@ public class ScrobblingService : IScrobblingService
if (!webLink.StartsWith(website)) continue;
var tokens = webLink.Split(website)[1].Split('/');
var value = tokens[index];
if (typeof(T) == typeof(int))
if (typeof(T) == typeof(int?))
{
if (int.TryParse(value, out var intValue))
return (T)(object)intValue;
}
else if (typeof(T) == typeof(long))
else if (typeof(T) == typeof(long?))
{
if (long.TryParse(value, out var longValue))
return (T)(object)longValue;

View file

@ -34,7 +34,6 @@ public interface ITaskScheduler
void ScanSiteThemes();
void CovertAllCoversToEncoding();
Task CleanupDbEntries();
Task ScrobbleUpdates(int userId);
}
public class TaskScheduler : ITaskScheduler
@ -141,7 +140,6 @@ public class TaskScheduler : ITaskScheduler
}
RecurringJob.AddOrUpdate(CleanupTaskId, () => _cleanupService.Cleanup(), Cron.Daily, RecurringJobOptions);
RecurringJob.AddOrUpdate(CleanupDbTaskId, () => _cleanupService.CleanupDbEntries(), Cron.Daily, RecurringJobOptions);
RecurringJob.AddOrUpdate(RemoveFromWantToReadTaskId, () => _cleanupService.CleanupWantToRead(), Cron.Daily, RecurringJobOptions);
RecurringJob.AddOrUpdate(UpdateYearlyStatsTaskId, () => _statisticService.UpdateServerStatistics(), Cron.Monthly, RecurringJobOptions);
@ -272,16 +270,6 @@ public class TaskScheduler : ITaskScheduler
await _cleanupService.CleanupDbEntries();
}
/// <summary>
/// TODO: Remove this for Release
/// </summary>
/// <returns></returns>
public async Task ScrobbleUpdates(int userId)
{
if (!await _licenseService.HasActiveLicense()) return;
BackgroundJob.Enqueue(() => _scrobblingService.ProcessUpdatesSinceLastSync());
}
/// <summary>
/// Attempts to call ScanLibraries on ScannerService, but if another scan task is in progress, will reschedule the invocation for 3 hours in future.
/// </summary>

View file

@ -9,6 +9,7 @@ using API.Entities.Enums;
using API.Logging;
using API.SignalR;
using Hangfire;
using Kavita.Common.EnvironmentInfo;
using Microsoft.Extensions.Logging;
namespace API.Services.Tasks;
@ -91,7 +92,7 @@ public class BackupService : IBackupService
await SendProgress(0.1F, "Copying core files");
var dateString = $"{DateTime.UtcNow.ToShortDateString()}_{DateTime.UtcNow.ToLongTimeString()}".Replace("/", "_").Replace(":", "_");
var zipPath = _directoryService.FileSystem.Path.Join(backupDirectory, $"kavita_backup_{dateString}.zip");
var zipPath = _directoryService.FileSystem.Path.Join(backupDirectory, $"kavita_backup_{dateString}_v{BuildInfo.Version}.zip");
if (File.Exists(zipPath))
{

View file

@ -92,6 +92,8 @@ public class CleanupService : ICleanupService
await CleanupLogs();
await SendProgress(0.9F, "Cleaning progress events that exceed 100%");
await EnsureChapterProgressIsCapped();
await SendProgress(0.95F, "Cleaning abandoned database rows");
await CleanupDbEntries();
await SendProgress(1F, "Cleanup finished");
_logger.LogInformation("Cleanup finished");
}

View file

@ -109,9 +109,9 @@ public static class Parser
new Regex(
@"(?<Series>.*)(\b|_)v(?<Volume>\d+-?\d+)( |_)",
MatchOptions, RegexTimeout),
// NEEDLESS_Vol.4_-Simeon_6_v2[SugoiSugoi].rar
// Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.31 Omake
new Regex(
@"(?<Series>.*)(\b|_)(?!\[)(vol\.?)(?<Volume>\d+(-\d+)?)(?!\])",
@"^(?<Series>.+?)(\s*Chapter\s*\d+)?(\s|_|\-\s)+(Vol(ume)?\.?(\s|_)?)(?<Volume>\d+(\.\d+)?)(.+?|$)",
MatchOptions, RegexTimeout),
// Historys Strongest Disciple Kenichi_v11_c90-98.zip or Dance in the Vampire Bund v16-17
new Regex(
@ -137,6 +137,7 @@ public static class Parser
new Regex(
@"(vol_)(?<Volume>\d+(\.\d)?)",
MatchOptions, RegexTimeout),
// Chinese Volume: 第n卷 -> Volume n, 第n册 -> Volume n, 幽游白书完全版 第03卷 天下 or 阿衰online 第1册
new Regex(
@"第(?<Volume>\d+)(卷|册)",
@ -197,16 +198,17 @@ public static class Parser
new Regex(
@"(?<Series>.*)(\b|_|-|\s)(?:sp)\d",
MatchOptions, RegexTimeout),
// [SugoiSugoi]_NEEDLESS_Vol.2_-_Disk_The_Informant_5_[ENG].rar, Yuusha Ga Shinda! - Vol.tbd Chapter 27.001 V2 Infection ①.cbz
new Regex(
@"^(?<Series>.*)( |_)Vol\.?(\d+|tbd)",
MatchOptions, RegexTimeout),
// Mad Chimera World - Volume 005 - Chapter 026.cbz (couldn't figure out how to get Volume negative lookaround working on below regex),
// The Duke of Death and His Black Maid - Vol. 04 Ch. 054.5 - V4 Omake
new Regex(
@"(?<Series>.+?)(\s|_|-)+(?:Vol(ume|\.)?(\s|_|-)+\d+)(\s|_|-)+(?:(Ch|Chapter|Ch)\.?)(\s|_|-)+(?<Chapter>\d+)",
MatchOptions,
RegexTimeout),
// [SugoiSugoi]_NEEDLESS_Vol.2_-_Disk_The_Informant_5_[ENG].rar, Yuusha Ga Shinda! - Vol.tbd Chapter 27.001 V2 Infection ①.cbz,
// Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.30 Omake
new Regex(
@"^(?<Series>.+?)(\s*Chapter\s*\d+)?(\s|_|\-\s)+Vol(ume)?\.?(\d+|tbd|\s\d).+?",
MatchOptions, RegexTimeout),
// Ichiban_Ushiro_no_Daimaou_v04_ch34_[VISCANS].zip, VanDread-v01-c01.zip
new Regex(
@"(?<Series>.*)(\b|_)v(?<Volume>\d+-?\d*)(\s|_|-)",
@ -233,6 +235,7 @@ public static class Parser
@"(?<Series>.+?):?(\s|\b|_|-)Chapter(\s|\b|_|-)\d+(\s|\b|_|-)(vol)(ume)",
MatchOptions,
RegexTimeout),
// [xPearse] Kyochuu Rettou Volume 1 [English] [Manga] [Volume Scans]
new Regex(
@"(?<Series>.+?):? (\b|_|-)(vol)(ume)",

Binary file not shown.