Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix Prep #2484

Merged
merged 18 commits into from
Dec 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d2c3bd7
Moved some cleanup tasks within another task to ensure everything is …
majora2007 Dec 5, 2023
3c486e7
Backup files now show the version of Kavita in the filename.
majora2007 Dec 5, 2023
65bc378
v0.7.11.1 - Hotfix (#2480)
majora2007 Dec 5, 2023
2dbaf55
Changed the readme to point to the correct type of projects.
majora2007 Dec 5, 2023
89452cc
Fixed invalid date showing on tasks screen
majora2007 Dec 5, 2023
0a2604d
Corrected some regex for a long standing annoyance where there are 2 …
majora2007 Dec 6, 2023
7b35990
Same case now works for Volumes.
majora2007 Dec 6, 2023
47ec5f0
Added ability to send MangaDex Id to Kavita+ if present
majora2007 Dec 7, 2023
da13d0d
Removed debug code from the release
majora2007 Dec 7, 2023
c6da752
Fixed unit tests
majora2007 Dec 7, 2023
d48e593
Don't use image complete for loader on webtoon mode as it's not appli…
majora2007 Dec 9, 2023
63bc25f
Fixed a bug where fresh installs inviting a new users would get their…
majora2007 Dec 9, 2023
d5128b9
Removed a file not supposed to be in repo
majora2007 Dec 9, 2023
b45e254
Revert a log change which could be exploited by a malicious jwt
majora2007 Dec 10, 2023
494b1cb
Merge branch 'develop' of https://github.com/Kareadita/Kavita into fe…
majora2007 Dec 10, 2023
b25faec
Fixed a decoding bug in the smart filters which wasn't handling isAsc…
majora2007 Dec 10, 2023
d119f6a
Fixed a bug where progress bar on an image could read out the wrong p…
majora2007 Dec 10, 2023
db6d1df
Reverted a code fix in one component
majora2007 Dec 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading