Skip to content

Commit

Permalink
Hotfix Prep (#2484)
Browse files Browse the repository at this point in the history
  • Loading branch information
majora2007 authored Dec 10, 2023
1 parent 8c16b87 commit bd4cbeb
Show file tree
Hide file tree
Showing 22 changed files with 114 additions and 87 deletions.
11 changes: 11 additions & 0 deletions API.Tests/Helpers/SmartFilterHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ public void Test_Decode()
AssertStatementSame(list[0], FilterField.Genres, FilterComparison.Equal, "95");
}

[Fact]
public void Test_Decode2()
{
const string encoded = """
name=Test%202&stmts=comparison%253D10%25C2%25A6field%253D1%25C2%25A6value%253DA%EF%BF%BDcomparison%253D0%25C2%25A6field%253D19%25C2%25A6value%253D11&sortOptions=sortField%3D1%C2%A6isAscending%3DTrue&limitTo=0&combination=1
""";

var filter = SmartFilterHelper.Decode(encoded);
Assert.True(filter.SortOptions.IsAscending);
}

[Fact]
public void Test_EncodeDecode()
{
Expand Down
2 changes: 2 additions & 0 deletions API.Tests/Parser/MangaParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ public MangaParserTests(ITestOutputHelper testOutputHelper)
[InlineData("시즌34삽화2", "34")]
[InlineData("Accel World Chapter 001 Volume 002", "2")]
[InlineData("Accel World Volume 2", "2")]
[InlineData("Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.31 Omake", "30")]
public void ParseVolumeTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
Expand Down Expand Up @@ -204,6 +205,7 @@ public void ParseVolumeTest(string filename, string expected)
[InlineData("죠시라쿠! 2년 후 1권", "죠시라쿠! 2년 후")]
[InlineData("test 2 years 1권", "test 2 years")]
[InlineData("test 2 years 1화", "test 2 years")]
[InlineData("Nagasarete Airantou - Vol. 30 Ch. 187.5 - Vol.30 Omake", "Nagasarete Airantou")]
public void ParseSeriesTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
Expand Down
14 changes: 12 additions & 2 deletions API.Tests/Services/ScrobblingServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,23 @@
using Xunit;

namespace API.Tests.Services;
#nullable enable

public class ScrobblingServiceTests
{
[Theory]
[InlineData("https://anilist.co/manga/35851/Byeontaega-Doeja/", 35851)]
public void CanParseWeblink(string link, long expectedId)
[InlineData("https://anilist.co/manga/30105", 30105)]
[InlineData("https://anilist.co/manga/30105/Kekkaishi/", 30105)]
public void CanParseWeblink_AniList(string link, int? expectedId)
{
Assert.Equal(ScrobblingService.ExtractId<long>(link, ScrobblingService.AniListWeblinkWebsite), expectedId);
Assert.Equal(ScrobblingService.ExtractId<int?>(link, ScrobblingService.AniListWeblinkWebsite), expectedId);
}

[Theory]
[InlineData("https://mangadex.org/title/316d3d09-bb83-49da-9d90-11dc7ce40967/honzuki-no-gekokujou-shisho-ni-naru-tame-ni-wa-shudan-wo-erandeiraremasen-dai-3-bu-ryouchi-ni-hon-o", "316d3d09-bb83-49da-9d90-11dc7ce40967")]
public void CanParseWeblink_MangaDex(string link, string expectedId)
{
Assert.Equal(ScrobblingService.ExtractId<string?>(link, ScrobblingService.MangaDexWeblinkWebsite), expectedId);
}
}
28 changes: 20 additions & 8 deletions API/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SharpCompress;

namespace API.Controllers;

Expand Down Expand Up @@ -137,8 +138,7 @@ public async Task<ActionResult<UserDto>> RegisterFirstUser(RegisterDto registerD
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"));
Expand Down Expand Up @@ -608,17 +608,16 @@ public async Task<ActionResult<string>> InviteUser(InviteUserDto dto)
}

// 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
{
var result = await _userManager.CreateAsync(user, AccountService.DefaultPassword);
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;
Expand Down Expand Up @@ -657,7 +656,6 @@ public async Task<ActionResult<string>> InviteUser(InviteUserDto dto)
user.CreateSideNavFromLibrary(lib);
}

_unitOfWork.UserRepository.Update(user);
user.AgeRestriction = hasAdminRole ? AgeRating.NotApplicable : dto.AgeRestriction.AgeRating;
user.AgeRestrictionIncludeUnknowns = hasAdminRole || dto.AgeRestriction.IncludeUnknowns;

Expand All @@ -669,6 +667,7 @@ public async Task<ActionResult<string>> InviteUser(InviteUserDto dto)
}

user.ConfirmationToken = token;
_unitOfWork.UserRepository.Update(user);
await _unitOfWork.CommitAsync();
}
catch (Exception ex)
Expand Down Expand Up @@ -702,7 +701,7 @@ public async Task<ActionResult<string>> InviteUser(InviteUserDto dto)
BackgroundJob.Enqueue(() => _emailService.SendConfirmationEmail(new ConfirmationEmailDto()
{
EmailAddress = dto.Email,
InvitingUser = adminUser.UserName!,
InvitingUser = adminUser.UserName,
ServerConfirmationLink = emailLink
}));
}
Expand All @@ -721,6 +720,19 @@ public async Task<ActionResult<string>> InviteUser(InviteUserDto dto)
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>
Expand Down
4 changes: 0 additions & 4 deletions API/Controllers/ReaderController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,6 @@ public async Task<ActionResult> GetImage(int chapterId, int page, string apiKey,

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);
Expand Down
76 changes: 35 additions & 41 deletions API/Data/Seed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,48 +76,42 @@ public static class Seed
},
}.ToArray());

public static readonly ImmutableArray<AppUserSideNavStream> DefaultSideNavStreams = ImmutableArray.Create(new[]
{
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
},
public static readonly ImmutableArray<AppUserSideNavStream> DefaultSideNavStreams = ImmutableArray.Create(
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
});


Expand Down
7 changes: 4 additions & 3 deletions API/Helpers/AutoMapperProfiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,10 @@ public AutoMapperProfiles()

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>();

}
}
2 changes: 2 additions & 0 deletions API/Helpers/Builders/PlusSeriesDtoBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public PlusSeriesDtoBuilder(Series series)
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
Expand Down
2 changes: 1 addition & 1 deletion API/Helpers/SmartFilterHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ private static SortOptions DecodeSortOptions(string encodedSortOptions)
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();
Expand Down
1 change: 1 addition & 0 deletions API/Services/Plus/RecommendationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
7 changes: 4 additions & 3 deletions API/Services/Plus/ScrobblingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -829,12 +830,12 @@ private static IList<ScrobbleProvider> GetUserProviders(AppUser appUser)
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;
Expand Down
12 changes: 0 additions & 12 deletions API/Services/TaskScheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public interface ITaskScheduler
void ScanSiteThemes();
void CovertAllCoversToEncoding();
Task CleanupDbEntries();
Task ScrobbleUpdates(int userId);

}
public class TaskScheduler : ITaskScheduler
Expand Down Expand Up @@ -141,7 +140,6 @@ public async Task ScheduleTasks()
}

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);

Expand Down Expand Up @@ -272,16 +270,6 @@ public async Task CleanupDbEntries()
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>
Expand Down
3 changes: 2 additions & 1 deletion API/Services/Tasks/BackupService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using API.Logging;
using API.SignalR;
using Hangfire;
using Kavita.Common.EnvironmentInfo;
using Microsoft.Extensions.Logging;

namespace API.Services.Tasks;
Expand Down Expand Up @@ -91,7 +92,7 @@ await _eventHub.SendMessageAsync(MessageFactory.Error,
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))
{
Expand Down
2 changes: 2 additions & 0 deletions API/Services/Tasks/CleanupService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
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");
}
Expand Down
Loading

0 comments on commit bd4cbeb

Please sign in to comment.