diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml
index c58c177b1..dafab4f2e 100644
--- a/.github/workflows/sonar-scan.yml
+++ b/.github/workflows/sonar-scan.yml
@@ -8,17 +8,25 @@ on:
types: [synchronize]
jobs:
+ check_pr:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check PR Body
+ uses: JJ/github-pr-contains-action@releases/v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ bodyDoesNotContain: "["|`]"
build:
name: Build .Net
runs-on: windows-latest
steps:
- name: Checkout Repo
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET Core
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
@@ -74,19 +82,18 @@ jobs:
- name: Test
run: dotnet test --no-restore --verbosity normal
-
version:
name: Bump version on Develop push
needs: [ build ]
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }}
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET Core
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
@@ -139,7 +146,7 @@ jobs:
echo "::set-output name=BODY::$body"
- name: Check Out Repo
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
ref: develop
@@ -176,7 +183,7 @@ jobs:
run: echo "${{steps.get-version.outputs.assembly-version}}"
- name: Compile dotnet app
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
@@ -253,7 +260,7 @@ jobs:
echo "::set-output name=BODY::$body"
- name: Check Out Repo
- uses: actions/checkout@v2
+ uses: actions/checkout@v3
with:
ref: main
@@ -293,7 +300,7 @@ jobs:
id: parse-version
- name: Compile dotnet app
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
- name: Install Swashbuckle CLI
diff --git a/API.Tests/API.Tests.csproj b/API.Tests/API.Tests.csproj
index 227d4c4df..1af28971f 100644
--- a/API.Tests/API.Tests.csproj
+++ b/API.Tests/API.Tests.csproj
@@ -6,11 +6,12 @@
-
+
-
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/API.Tests/Helpers/PersonHelperTests.cs b/API.Tests/Helpers/PersonHelperTests.cs
index d9f5cdb82..0f1c170ff 100644
--- a/API.Tests/Helpers/PersonHelperTests.cs
+++ b/API.Tests/Helpers/PersonHelperTests.cs
@@ -9,6 +9,7 @@ namespace API.Tests.Helpers;
public class PersonHelperTests
{
+ #region UpdatePeople
[Fact]
public void UpdatePeople_ShouldAddNewPeople()
{
@@ -47,7 +48,15 @@ public class PersonHelperTests
Assert.Equal(3, allPeople.Count);
}
+ #endregion
+ #region UpdatePeopleList
+
+
+
+ #endregion
+
+ #region RemovePeople
[Fact]
public void RemovePeople_ShouldRemovePeopleOfSameRole()
{
@@ -111,6 +120,10 @@ public class PersonHelperTests
Assert.Equal(2, peopleRemoved.Count);
}
+
+ #endregion
+
+ #region KeepOnlySamePeopleBetweenLists
[Fact]
public void KeepOnlySamePeopleBetweenLists()
{
@@ -135,6 +148,9 @@ public class PersonHelperTests
Assert.Equal(2, peopleRemoved.Count);
}
+ #endregion
+
+ #region AddPeople
[Fact]
public void AddPeople_ShouldAddOnlyNonExistingPeople()
@@ -157,4 +173,6 @@ public class PersonHelperTests
Assert.Equal(4, existingPeople.Count);
}
+ #endregion
+
}
diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs
index 608a08911..208ace3bc 100644
--- a/API.Tests/Parser/MangaParserTests.cs
+++ b/API.Tests/Parser/MangaParserTests.cs
@@ -81,6 +81,7 @@ public class MangaParserTests
[InlineData("몰?루 아카이브 7.5권", "7.5")]
[InlineData("63권#200", "63")]
[InlineData("시즌34삽화2", "34")]
+ [InlineData("Accel World Chapter 001 Volume 002", "2")]
public void ParseVolumeTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseVolume(filename));
@@ -195,6 +196,7 @@ public class MangaParserTests
[InlineData("Манга Том 1 3-4 Глава", "Манга")]
[InlineData("Esquire 6권 2021년 10월호", "Esquire")]
[InlineData("Accel World: Vol 1", "Accel World")]
+ [InlineData("Accel World Chapter 001 Volume 002", "Accel World")]
public void ParseSeriesTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename));
@@ -278,6 +280,7 @@ public class MangaParserTests
[InlineData("Манга Глава 2", "2")]
[InlineData("Манга 2 Глава", "2")]
[InlineData("Манга Том 1 2 Глава", "2")]
+ [InlineData("Accel World Chapter 001 Volume 002", "1")]
public void ParseChaptersTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename));
diff --git a/API.Tests/Services/CleanupServiceTests.cs b/API.Tests/Services/CleanupServiceTests.cs
index d174c6f44..bf243ccc1 100644
--- a/API.Tests/Services/CleanupServiceTests.cs
+++ b/API.Tests/Services/CleanupServiceTests.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Threading.Tasks;
@@ -16,7 +17,6 @@ using API.Helpers.Builders;
using API.Services;
using API.Services.Tasks;
using API.SignalR;
-using API.Tests.Helpers;
using Microsoft.Extensions.Logging;
using NSubstitute;
using Xunit;
@@ -437,7 +437,8 @@ public class CleanupServiceTests : AbstractDbTest
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+ var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For(),
+ Substitute.For(), new DirectoryService(Substitute.For>(), new MockFileSystem()));
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
await readerService.MarkChaptersUntilAsRead(user, 1, 5);
@@ -534,7 +535,8 @@ public class CleanupServiceTests : AbstractDbTest
await _unitOfWork.CommitAsync();
var readerService = new ReaderService(_unitOfWork, Substitute.For>(),
- Substitute.For());
+ Substitute.For(), Substitute.For(),
+ new DirectoryService(Substitute.For>(), new MockFileSystem()));
await readerService.MarkSeriesAsRead(user, s.Id);
await _unitOfWork.CommitAsync();
diff --git a/API.Tests/Services/ReaderServiceTests.cs b/API.Tests/Services/ReaderServiceTests.cs
index 19dc26d71..e74687e54 100644
--- a/API.Tests/Services/ReaderServiceTests.cs
+++ b/API.Tests/Services/ReaderServiceTests.cs
@@ -29,10 +29,9 @@ namespace API.Tests.Services;
public class ReaderServiceTests
{
private readonly ITestOutputHelper _testOutputHelper;
-
private readonly IUnitOfWork _unitOfWork;
-
private readonly DataContext _context;
+ private readonly ReaderService _readerService;
private const string CacheDirectory = "C:/kavita/config/cache/";
private const string CoverImageDirectory = "C:/kavita/config/covers/";
@@ -50,6 +49,9 @@ public class ReaderServiceTests
var config = new MapperConfiguration(cfg => cfg.AddProfile());
var mapper = config.CreateMapper();
_unitOfWork = new UnitOfWork(_context, mapper, null);
+ _readerService = new ReaderService(_unitOfWork, Substitute.For>(),
+ Substitute.For(), Substitute.For(),
+ new DirectoryService(Substitute.For>(), new MockFileSystem()));
}
#region Setup
@@ -147,10 +149,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- Assert.Equal(0, await readerService.CapPageToChapter(1, -1));
- Assert.Equal(1, await readerService.CapPageToChapter(1, 10));
+ Assert.Equal(0, await _readerService.CapPageToChapter(1, -1));
+ Assert.Equal(1, await _readerService.CapPageToChapter(1, 10));
}
#endregion
@@ -186,9 +187,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var successful = await readerService.SaveReadingProgress(new ProgressDto()
+
+ var successful = await _readerService.SaveReadingProgress(new ProgressDto()
{
ChapterId = 1,
PageNum = 1,
@@ -230,9 +231,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var successful = await readerService.SaveReadingProgress(new ProgressDto()
+
+ var successful = await _readerService.SaveReadingProgress(new ProgressDto()
{
ChapterId = 1,
PageNum = 1,
@@ -244,7 +245,7 @@ public class ReaderServiceTests
Assert.True(successful);
Assert.NotNull(await _unitOfWork.AppUserProgressRepository.GetUserProgressAsync(1, 1));
- Assert.True(await readerService.SaveReadingProgress(new ProgressDto()
+ Assert.True(await _readerService.SaveReadingProgress(new ProgressDto()
{
ChapterId = 1,
PageNum = 1,
@@ -294,10 +295,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var volumes = await _unitOfWork.VolumeRepository.GetVolumes(1);
- await readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
+ await _readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
await _context.SaveChangesAsync();
Assert.Equal(2, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count);
@@ -338,15 +339,15 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var volumes = (await _unitOfWork.VolumeRepository.GetVolumes(1)).ToList();
- await readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
+ await _readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
await _context.SaveChangesAsync();
Assert.Equal(2, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count);
- await readerService.MarkChaptersAsUnread(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
+ await _readerService.MarkChaptersAsUnread(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
await _context.SaveChangesAsync();
var progresses = (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses;
@@ -427,9 +428,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 1, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 1, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("2", actualChapter.Range);
}
@@ -475,10 +476,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("21", actualChapter.Range);
}
@@ -524,10 +525,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("21", actualChapter.Range);
}
@@ -566,10 +567,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 2, 4, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 2, 4, 1);
Assert.NotEqual(-1, nextChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("1", actualChapter.Range);
@@ -614,9 +615,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 2, 3, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 2, 3, 1);
Assert.NotEqual(-1, nextChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("0", actualChapter.Range);
@@ -658,10 +659,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 2, 4, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 2, 4, 1);
Assert.Equal(-1, nextChapter);
}
@@ -693,10 +694,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
Assert.Equal(-1, nextChapter);
}
@@ -735,10 +736,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
Assert.Equal(-1, nextChapter);
}
@@ -777,10 +778,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
Assert.NotEqual(-1, nextChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("A.cbz", actualChapter.Range);
@@ -815,10 +816,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 2, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 2, 1);
Assert.NotEqual(-1, nextChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("A.cbz", actualChapter.Range);
@@ -857,10 +858,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 1, 3, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 1, 3, 1);
Assert.Equal(-1, nextChapter);
}
@@ -898,10 +899,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetNextChapterIdAsync(1, 2, 3, 1);
+
+ var nextChapter = await _readerService.GetNextChapterIdAsync(1, 2, 3, 1);
Assert.NotEqual(-1, nextChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(nextChapter);
Assert.Equal("B.cbz", actualChapter.Range);
@@ -952,9 +953,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 2, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 2, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("1", actualChapter.Range);
}
@@ -998,9 +999,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 3, 5, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 3, 5, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("22", actualChapter.Range);
}
@@ -1044,10 +1045,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// prevChapter should be id from ch.21 from volume 2001
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 4, 7, 1);
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 4, 7, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.NotNull(actualChapter);
@@ -1091,10 +1092,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2, 3, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 2, 3, 1);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("2", actualChapter.Range);
}
@@ -1133,10 +1134,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2, 3, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 2, 3, 1);
Assert.Equal(2, prevChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("2", actualChapter.Range);
@@ -1170,10 +1171,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
Assert.Equal(-1, prevChapter);
}
@@ -1204,10 +1205,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
Assert.Equal(-1, prevChapter);
}
@@ -1244,10 +1245,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
Assert.Equal(-1, prevChapter);
}
@@ -1293,14 +1294,14 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2,5, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 2,5, 1);
var chapterInfoDto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(prevChapter);
Assert.Equal(1, float.Parse(chapterInfoDto.ChapterNumber));
// This is first chapter of first volume
- prevChapter = await readerService.GetPrevChapterIdAsync(1, 2,4, 1);
+ prevChapter = await _readerService.GetPrevChapterIdAsync(1, 2,4, 1);
Assert.Equal(-1, prevChapter);
}
@@ -1332,10 +1333,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
Assert.Equal(-1, prevChapter);
}
@@ -1374,10 +1375,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 2, 4, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 2, 4, 1);
Assert.NotEqual(-1, prevChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("A.cbz", actualChapter.Range);
@@ -1418,10 +1419,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var prevChapter = await readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
+
+ var prevChapter = await _readerService.GetPrevChapterIdAsync(1, 1, 1, 1);
Assert.NotEqual(-1, prevChapter);
var actualChapter = await _unitOfWork.ChapterRepository.GetChapterAsync(prevChapter);
Assert.Equal("22", actualChapter.Range);
@@ -1472,9 +1473,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("1", nextChapter.Range);
}
@@ -1511,15 +1512,15 @@ public class ReaderServiceTests
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- await readerService.SaveReadingProgress(new ProgressDto()
+
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 2,
ChapterId = 1,
SeriesId = 1,
VolumeId = 1
}, 1);
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("1", nextChapter.Range);
}
@@ -1560,24 +1561,24 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 1,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 2,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 3,
@@ -1587,7 +1588,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("22", nextChapter.Range);
@@ -1638,10 +1639,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume and 1st chapter of second volume
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 6, // Chapter 0 volume 1 id
@@ -1650,7 +1651,7 @@ public class ReaderServiceTests
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 7, // Chapter 21 volume 2 id
@@ -1660,7 +1661,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("22", nextChapter.Range);
@@ -1702,24 +1703,24 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 1,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 2,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 3,
@@ -1729,7 +1730,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("31", nextChapter.Range);
}
@@ -1769,8 +1770,8 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("1", nextChapter.Range);
}
@@ -1811,21 +1812,21 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Mark everything but chapter 101 as read
- await readerService.MarkSeriesAsRead(user, 1);
+ await _readerService.MarkSeriesAsRead(user, 1);
await _unitOfWork.CommitAsync();
// Unmark last chapter as read
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 0,
ChapterId = (await _unitOfWork.VolumeRepository.GetVolumeByIdAsync(1)).Chapters.ElementAt(1).Id,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 0,
ChapterId = (await _unitOfWork.VolumeRepository.GetVolumeByIdAsync(1)).Chapters.ElementAt(2).Id,
@@ -1834,7 +1835,7 @@ public class ReaderServiceTests
}, 1);
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("101", nextChapter.Range);
}
@@ -1869,24 +1870,24 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 1,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 2,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 3,
@@ -1896,7 +1897,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("1", nextChapter.Range);
}
@@ -1933,14 +1934,14 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress);
- await readerService.MarkSeriesAsRead(user, 1);
+ await _readerService.MarkSeriesAsRead(user, 1);
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("11", nextChapter.Range);
}
@@ -1973,24 +1974,24 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 1,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 2,
SeriesId = 1,
VolumeId = 1
}, 1);
- await readerService.SaveReadingProgress(new ProgressDto()
+ await _readerService.SaveReadingProgress(new ProgressDto()
{
PageNum = 1,
ChapterId = 3,
@@ -2000,7 +2001,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("Some Special Title", nextChapter.Range);
}
@@ -2041,9 +2042,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress);
- await readerService.MarkSeriesAsRead(user, 1);
+ await _readerService.MarkSeriesAsRead(user, 1);
await _context.SaveChangesAsync();
// Add 2 new unread series to the Series
@@ -2053,7 +2054,7 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
// This tests that if you add a series later to a volume and a loose leaf chapter, we continue from that volume, rather than loose leaf
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal("14.9", nextChapter.Range);
}
@@ -2104,18 +2105,18 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
// Save progress on first volume chapters and 1st of second volume
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress);
- await readerService.MarkChaptersAsRead(user, 1,
+ await _readerService.MarkChaptersAsRead(user, 1,
new List()
{
readChapter1, readChapter2
});
await _context.SaveChangesAsync();
- var nextChapter = await readerService.GetContinuePoint(1, 1);
+ var nextChapter = await _readerService.GetContinuePoint(1, 1);
Assert.Equal(4, nextChapter.VolumeId);
}
@@ -2152,10 +2153,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkChaptersUntilAsRead(user, 1, 5);
+ await _readerService.MarkChaptersUntilAsRead(user, 1, 5);
await _context.SaveChangesAsync();
// Validate correct chapters have read status
@@ -2194,10 +2195,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkChaptersUntilAsRead(user, 1, 2.5f);
+ await _readerService.MarkChaptersUntilAsRead(user, 1, 2.5f);
await _context.SaveChangesAsync();
// Validate correct chapters have read status
@@ -2236,10 +2237,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkChaptersUntilAsRead(user, 1, 2);
+ await _readerService.MarkChaptersUntilAsRead(user, 1, 2);
await _context.SaveChangesAsync();
// Validate correct chapters have read status
@@ -2289,12 +2290,12 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
const int markReadUntilNumber = 47;
- await readerService.MarkChaptersUntilAsRead(user, 1, markReadUntilNumber);
+ await _readerService.MarkChaptersUntilAsRead(user, 1, markReadUntilNumber);
await _context.SaveChangesAsync();
var volumes = await _unitOfWork.VolumeRepository.GetVolumesDtoAsync(1, 1);
@@ -2347,9 +2348,9 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- await readerService.MarkSeriesAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1);
+
+ await _readerService.MarkSeriesAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1);
await _context.SaveChangesAsync();
Assert.Equal(4, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count);
@@ -2386,15 +2387,15 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var volumes = (await _unitOfWork.VolumeRepository.GetVolumes(1)).ToList();
- await readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
+ await _readerService.MarkChaptersAsRead(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1, volumes.First().Chapters);
await _context.SaveChangesAsync();
Assert.Equal(2, (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses.Count);
- await readerService.MarkSeriesAsUnread(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1);
+ await _readerService.MarkSeriesAsUnread(await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress), 1);
await _context.SaveChangesAsync();
var progresses = (await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Progress)).Progresses;
@@ -2476,10 +2477,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkVolumesUntilAsRead(user, 1, 2002);
+ await _readerService.MarkVolumesUntilAsRead(user, 1, 2002);
await _context.SaveChangesAsync();
// Validate loose leaf chapters don't get marked as read
@@ -2534,10 +2535,10 @@ public class ReaderServiceTests
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkVolumesUntilAsRead(user, 1, 2002);
+ await _readerService.MarkVolumesUntilAsRead(user, 1, 2002);
await _context.SaveChangesAsync();
// Validate loose leaf chapters don't get marked as read
@@ -2577,9 +2578,9 @@ public class ReaderServiceTests
new [] {"0,0", "1,1", "2,1", "3,3", "4,3", "5,5", "6,6", "7,6", "8,8", "9,9"})]
public void GetPairs_ShouldReturnPairsForNoWideImages(string caseName, IList wides, IList expectedPairs)
{
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
+
var files = wides.Select((b, i) => new FileDimensionDto() {PageNumber = i, Height = 1, Width = 1, FileName = string.Empty, IsWide = b}).ToList();
- var pairs = readerService.GetPairs(files);
+ var pairs = _readerService.GetPairs(files);
var expectedDict = new Dictionary();
foreach (var pair in expectedPairs)
{
diff --git a/API.Tests/Services/ReadingListServiceTests.cs b/API.Tests/Services/ReadingListServiceTests.cs
index b76aee059..a2d5291fe 100644
--- a/API.Tests/Services/ReadingListServiceTests.cs
+++ b/API.Tests/Services/ReadingListServiceTests.cs
@@ -500,7 +500,8 @@ public class ReadingListServiceTests
Assert.Equal(3, readingList.Items.Count);
var readerService = new ReaderService(_unitOfWork, Substitute.For>(),
- Substitute.For());
+ Substitute.For(), Substitute.For(),
+ new DirectoryService(Substitute.For>(), new MockFileSystem()));
// Mark 2 as fully read
await readerService.MarkChaptersAsRead(user, 1,
(await _unitOfWork.ChapterRepository.GetChaptersByIdsAsync(new List() {2})).ToList());
diff --git a/API.Tests/Services/TachiyomiServiceTests.cs b/API.Tests/Services/TachiyomiServiceTests.cs
index ffa784da6..33088997e 100644
--- a/API.Tests/Services/TachiyomiServiceTests.cs
+++ b/API.Tests/Services/TachiyomiServiceTests.cs
@@ -27,6 +27,8 @@ public class TachiyomiServiceTests
private readonly IUnitOfWork _unitOfWork;
private readonly IMapper _mapper;
private readonly DataContext _context;
+ private readonly ReaderService _readerService;
+ private readonly TachiyomiService _tachiyomiService;
private const string CacheDirectory = "C:/kavita/config/cache/";
private const string CoverImageDirectory = "C:/kavita/config/covers/";
private const string BackupDirectory = "C:/kavita/config/backups/";
@@ -44,6 +46,10 @@ public class TachiyomiServiceTests
_mapper = config.CreateMapper();
_unitOfWork = new UnitOfWork(_context, _mapper, null);
+ _readerService = new ReaderService(_unitOfWork, Substitute.For>(),
+ Substitute.For(), Substitute.For(),
+ new DirectoryService(Substitute.For>(), new MockFileSystem()));
+ _tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), _readerService);
}
@@ -151,10 +157,7 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Null(latestChapter);
}
@@ -201,16 +204,14 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkSeriesAsRead(user,1);
+ await _readerService.MarkSeriesAsRead(user,1);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("96", latestChapter.Number);
}
@@ -257,16 +258,14 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await tachiyomiService.MarkChaptersUntilAsRead(user,1,21);
+ await _tachiyomiService.MarkChaptersUntilAsRead(user,1,21);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("21", latestChapter.Number);
}
@@ -312,17 +311,15 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await tachiyomiService.MarkChaptersUntilAsRead(user,1,1/10_000F);
+ await _tachiyomiService.MarkChaptersUntilAsRead(user,1,1/10_000F);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("0.0001", latestChapter.Number);
}
@@ -362,17 +359,15 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkSeriesAsRead(user, 1);
+ await _readerService.MarkSeriesAsRead(user, 1);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("0.0003", latestChapter.Number);
}
@@ -417,17 +412,14 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await tachiyomiService.MarkChaptersUntilAsRead(user,1,2002/10_000F);
+ await _tachiyomiService.MarkChaptersUntilAsRead(user,1,2002/10_000F);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("0.2002", latestChapter.Number);
}
@@ -478,10 +470,7 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Null(latestChapter);
}
@@ -527,16 +516,13 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await readerService.MarkSeriesAsRead(user,1);
+ await _readerService.MarkSeriesAsRead(user,1);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("96", latestChapter.Number);
}
@@ -583,16 +569,13 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await tachiyomiService.MarkChaptersUntilAsRead(user,1,21);
+ await _tachiyomiService.MarkChaptersUntilAsRead(user,1,21);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("21", latestChapter.Number);
}
@@ -637,17 +620,14 @@ public class TachiyomiServiceTests
});
await _context.SaveChangesAsync();
- var readerService = new ReaderService(_unitOfWork, Substitute.For>(), Substitute.For());
- var tachiyomiService = new TachiyomiService(_unitOfWork, _mapper, Substitute.For>(), readerService);
-
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.Progress);
- await tachiyomiService.MarkChaptersUntilAsRead(user,1,1/10_000F);
+ await _tachiyomiService.MarkChaptersUntilAsRead(user,1,1/10_000F);
await _context.SaveChangesAsync();
- var latestChapter = await tachiyomiService.GetLatestChapter(1, 1);
+ var latestChapter = await _tachiyomiService.GetLatestChapter(1, 1);
Assert.Equal("0.0001", latestChapter.Number);
}
diff --git a/API.Tests/Services/WordCountAnalysisTests.cs b/API.Tests/Services/WordCountAnalysisTests.cs
index c9e178665..39ae8848b 100644
--- a/API.Tests/Services/WordCountAnalysisTests.cs
+++ b/API.Tests/Services/WordCountAnalysisTests.cs
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.IO;
+using System.IO.Abstractions;
+using System.IO.Abstractions.TestingHelpers;
using System.Linq;
using System.Threading.Tasks;
using API.Entities;
@@ -26,7 +28,8 @@ public class WordCountAnalysisTests : AbstractDbTest
public WordCountAnalysisTests() : base()
{
_readerService = new ReaderService(_unitOfWork, Substitute.For>(),
- Substitute.For());
+ Substitute.For(), Substitute.For(),
+ new DirectoryService(Substitute.For>(), new MockFileSystem()));
}
protected override async Task ResetDb()
diff --git a/API/API.csproj b/API/API.csproj
index 0ddae489f..46d180742 100644
--- a/API/API.csproj
+++ b/API/API.csproj
@@ -67,15 +67,15 @@
-
-
-
+
+
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
@@ -92,14 +92,14 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/API/Controllers/AccountController.cs b/API/Controllers/AccountController.cs
index 5a6bf520e..badcd0eff 100644
--- a/API/Controllers/AccountController.cs
+++ b/API/Controllers/AccountController.cs
@@ -13,6 +13,7 @@ using API.Entities;
using API.Entities.Enums;
using API.Errors;
using API.Extensions;
+using API.Middleware.RateLimit;
using API.Services;
using API.SignalR;
using AutoMapper;
@@ -22,6 +23,7 @@ using Kavita.Common.EnvironmentInfo;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
+using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
@@ -769,6 +771,7 @@ public class AccountController : BaseApiController
///
[AllowAnonymous]
[HttpPost("forgot-password")]
+ [EnableRateLimiting("Authentication")]
public async Task> ForgotPassword([FromQuery] string email)
{
var user = await _unitOfWork.UserRepository.GetUserByEmailAsync(email);
@@ -847,6 +850,7 @@ public class AccountController : BaseApiController
///
///
[HttpPost("resend-confirmation-email")]
+ [EnableRateLimiting("Authentication")]
public async Task> ResendConfirmationSendEmail([FromQuery] int userId)
{
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
diff --git a/API/Controllers/OPDSController.cs b/API/Controllers/OPDSController.cs
index b6d3cb220..2a49c5a29 100644
--- a/API/Controllers/OPDSController.cs
+++ b/API/Controllers/OPDSController.cs
@@ -904,8 +904,11 @@ public class OpdsController : BaseApiController
var link = CreateLink(FeedLinkRelation.Stream, "image/jpeg",
$"{Prefix}{apiKey}/image?libraryId={libraryId}&seriesId={seriesId}&volumeId={volumeId}&chapterId={chapterId}&pageNumber=" + "{pageNumber}");
link.TotalPages = mangaFile.Pages;
- link.LastRead = progress.PageNum;
- link.LastReadDate = progress.LastModifiedUtc;
+ if (progress != null)
+ {
+ link.LastRead = progress.PageNum;
+ link.LastReadDate = progress.LastModifiedUtc;
+ }
link.IsPageStream = true;
return link;
}
diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs
index 469b69118..1581b60b2 100644
--- a/API/Controllers/ReaderController.cs
+++ b/API/Controllers/ReaderController.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -34,12 +34,14 @@ public class ReaderController : BaseApiController
private readonly IBookmarkService _bookmarkService;
private readonly IAccountService _accountService;
private readonly IEventHub _eventHub;
+ private readonly IImageService _imageService;
+ private readonly IDirectoryService _directoryService;
///
public ReaderController(ICacheService cacheService,
IUnitOfWork unitOfWork, ILogger logger,
IReaderService readerService, IBookmarkService bookmarkService,
- IAccountService accountService, IEventHub eventHub)
+ IAccountService accountService, IEventHub eventHub, IImageService imageService, IDirectoryService directoryService)
{
_cacheService = cacheService;
_unitOfWork = unitOfWork;
@@ -48,6 +50,8 @@ public class ReaderController : BaseApiController
_bookmarkService = bookmarkService;
_accountService = accountService;
_eventHub = eventHub;
+ _imageService = imageService;
+ _directoryService = directoryService;
}
///
@@ -114,6 +118,20 @@ public class ReaderController : BaseApiController
}
}
+ [HttpGet("thumbnail")]
+ [ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour)]
+ [AllowAnonymous]
+ public async Task GetThumbnail(int chapterId, int pageNum)
+ {
+ var chapter = await _cacheService.Ensure(chapterId, true);
+ if (chapter == null) return BadRequest("There was an issue extracting images from chapter");
+ var images = _cacheService.GetCachedPages(chapterId);
+
+ var path = await _readerService.GetThumbnail(chapter, pageNum, images);
+ var format = Path.GetExtension(path).Replace(".", string.Empty); // TODO: Make this an extension
+ return PhysicalFile(path, "image/" + format, Path.GetFileName(path), true);
+ }
+
///
/// Returns an image for a given bookmark series. Side effect: This will cache the bookmark images for reading.
///
@@ -172,13 +190,14 @@ public class ReaderController : BaseApiController
///
/// Returns various information about a Chapter. Side effect: This will cache the chapter images for reading.
///
+ /// This is generally the first call when attempting to read to allow pre-generation of assets needed for reading
///
/// Should Kavita extract pdf into images. Defaults to false.
/// Include file dimensions. Only useful for image based reading
///
[HttpGet("chapter-info")]
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId", "extractPdf", "includeDimensions"})]
- public async Task> GetChapterInfo(int chapterId, bool extractPdf = false, bool includeDimensions = false)
+ public async Task> GetChapterInfo(int chapterId, bool extractPdf = false, bool includeDimensions = false)
{
if (chapterId <= 0) return Ok(null); // This can happen occasionally from UI, we should just ignore
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
diff --git a/API/Data/DataContext.cs b/API/Data/DataContext.cs
index 1e79d57d2..75e5f8b7d 100644
--- a/API/Data/DataContext.cs
+++ b/API/Data/DataContext.cs
@@ -47,6 +47,7 @@ public sealed class DataContext : IdentityDbContext FolderPath { get; set; } = null!;
public DbSet Device { get; set; } = null!;
public DbSet ServerStatistics { get; set; } = null!;
+ public DbSet SecurityEvent { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder builder)
diff --git a/API/Data/Migrations/20230316123908_SecurityEvent.Designer.cs b/API/Data/Migrations/20230316123908_SecurityEvent.Designer.cs
new file mode 100644
index 000000000..e0c1b3bfb
--- /dev/null
+++ b/API/Data/Migrations/20230316123908_SecurityEvent.Designer.cs
@@ -0,0 +1,1901 @@
+//
+using System;
+using API.Data;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace API.Data.Migrations
+{
+ [DbContext(typeof(DataContext))]
+ [Migration("20230316123908_SecurityEvent")]
+ partial class SecurityEvent
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder.HasAnnotation("ProductVersion", "7.0.4");
+
+ modelBuilder.Entity("API.Entities.AppRole", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedName")
+ .IsUnique()
+ .HasDatabaseName("RoleNameIndex");
+
+ b.ToTable("AspNetRoles", (string)null);
+ });
+
+ modelBuilder.Entity("API.Entities.AppUser", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AccessFailedCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRestriction")
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRestrictionIncludeUnknowns")
+ .HasColumnType("INTEGER");
+
+ b.Property("ApiKey")
+ .HasColumnType("TEXT");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .HasColumnType("TEXT");
+
+ b.Property("ConfirmationToken")
+ .HasColumnType("TEXT");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Email")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("EmailConfirmed")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastActive")
+ .HasColumnType("TEXT");
+
+ b.Property("LastActiveUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LockoutEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("LockoutEnd")
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedEmail")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedUserName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.Property("PasswordHash")
+ .HasColumnType("TEXT");
+
+ b.Property("PhoneNumber")
+ .HasColumnType("TEXT");
+
+ b.Property("PhoneNumberConfirmed")
+ .HasColumnType("INTEGER");
+
+ b.Property("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property("SecurityStamp")
+ .HasColumnType("TEXT");
+
+ b.Property("TwoFactorEnabled")
+ .HasColumnType("INTEGER");
+
+ b.Property("UserName")
+ .HasMaxLength(256)
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedEmail")
+ .HasDatabaseName("EmailIndex");
+
+ b.HasIndex("NormalizedUserName")
+ .IsUnique()
+ .HasDatabaseName("UserNameIndex");
+
+ b.ToTable("AspNetUsers", (string)null);
+ });
+
+ modelBuilder.Entity("API.Entities.AppUserBookmark", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ChapterId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("FileName")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Page")
+ .HasColumnType("INTEGER");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.Property("VolumeId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId");
+
+ b.ToTable("AppUserBookmark");
+ });
+
+ modelBuilder.Entity("API.Entities.AppUserPreferences", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("AutoCloseMenu")
+ .HasColumnType("INTEGER");
+
+ b.Property("BackgroundColor")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasDefaultValue("#000000");
+
+ b.Property("BlurUnreadSummaries")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderFontFamily")
+ .HasColumnType("TEXT");
+
+ b.Property("BookReaderFontSize")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderImmersiveMode")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderLayoutMode")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderLineSpacing")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderMargin")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderReadingDirection")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderTapToPaginate")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookReaderWritingStyle")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0);
+
+ b.Property("BookThemeName")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("TEXT")
+ .HasDefaultValue("Dark");
+
+ b.Property("CollapseSeriesRelationships")
+ .HasColumnType("INTEGER");
+
+ b.Property("EmulateBook")
+ .HasColumnType("INTEGER");
+
+ b.Property("GlobalPageLayoutMode")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(0);
+
+ b.Property("LayoutMode")
+ .HasColumnType("INTEGER");
+
+ b.Property("NoTransitions")
+ .HasColumnType("INTEGER");
+
+ b.Property("PageSplitOption")
+ .HasColumnType("INTEGER");
+
+ b.Property("PromptForDownloadSize")
+ .HasColumnType("INTEGER");
+
+ b.Property("ReaderMode")
+ .HasColumnType("INTEGER");
+
+ b.Property("ReadingDirection")
+ .HasColumnType("INTEGER");
+
+ b.Property("ScalingOption")
+ .HasColumnType("INTEGER");
+
+ b.Property("ShowScreenHints")
+ .HasColumnType("INTEGER");
+
+ b.Property("SwipeToPaginate")
+ .HasColumnType("INTEGER");
+
+ b.Property("ThemeId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId")
+ .IsUnique();
+
+ b.HasIndex("ThemeId");
+
+ b.ToTable("AppUserPreferences");
+ });
+
+ modelBuilder.Entity("API.Entities.AppUserProgress", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("BookScrollId")
+ .HasColumnType("TEXT");
+
+ b.Property("ChapterId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LibraryId")
+ .HasColumnType("INTEGER");
+
+ b.Property("PagesRead")
+ .HasColumnType("INTEGER");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.Property("VolumeId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId");
+
+ b.HasIndex("ChapterId");
+
+ b.HasIndex("SeriesId");
+
+ b.ToTable("AppUserProgresses");
+ });
+
+ modelBuilder.Entity("API.Entities.AppUserRating", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Rating")
+ .HasColumnType("INTEGER");
+
+ b.Property("Review")
+ .HasColumnType("TEXT");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId");
+
+ b.HasIndex("SeriesId");
+
+ b.ToTable("AppUserRating");
+ });
+
+ modelBuilder.Entity("API.Entities.AppUserRole", b =>
+ {
+ b.Property("UserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("RoleId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("UserId", "RoleId");
+
+ b.HasIndex("RoleId");
+
+ b.ToTable("AspNetUserRoles", (string)null);
+ });
+
+ modelBuilder.Entity("API.Entities.Chapter", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property("AlternateCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("AlternateNumber")
+ .HasColumnType("TEXT");
+
+ b.Property("AlternateSeries")
+ .HasColumnType("TEXT");
+
+ b.Property("AvgHoursToRead")
+ .HasColumnType("INTEGER");
+
+ b.Property("Count")
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverImage")
+ .HasColumnType("TEXT");
+
+ b.Property("CoverImageLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("IsSpecial")
+ .HasColumnType("INTEGER");
+
+ b.Property("Language")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("MaxHoursToRead")
+ .HasColumnType("INTEGER");
+
+ b.Property("MinHoursToRead")
+ .HasColumnType("INTEGER");
+
+ b.Property("Number")
+ .HasColumnType("TEXT");
+
+ b.Property("Pages")
+ .HasColumnType("INTEGER");
+
+ b.Property("Range")
+ .HasColumnType("TEXT");
+
+ b.Property("ReleaseDate")
+ .HasColumnType("TEXT");
+
+ b.Property("SeriesGroup")
+ .HasColumnType("TEXT");
+
+ b.Property("StoryArc")
+ .HasColumnType("TEXT");
+
+ b.Property("StoryArcNumber")
+ .HasColumnType("TEXT");
+
+ b.Property("Summary")
+ .HasColumnType("TEXT");
+
+ b.Property("Title")
+ .HasColumnType("TEXT");
+
+ b.Property("TitleName")
+ .HasColumnType("TEXT");
+
+ b.Property("TotalCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("VolumeId")
+ .HasColumnType("INTEGER");
+
+ b.Property("WordCount")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("VolumeId");
+
+ b.ToTable("Chapter");
+ });
+
+ modelBuilder.Entity("API.Entities.CollectionTag", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverImage")
+ .HasColumnType("TEXT");
+
+ b.Property("CoverImageLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("NormalizedTitle")
+ .HasColumnType("TEXT");
+
+ b.Property("Promoted")
+ .HasColumnType("INTEGER");
+
+ b.Property("RowVersion")
+ .HasColumnType("INTEGER");
+
+ b.Property("Summary")
+ .HasColumnType("TEXT");
+
+ b.Property("Title")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Id", "Promoted")
+ .IsUnique();
+
+ b.ToTable("CollectionTag");
+ });
+
+ modelBuilder.Entity("API.Entities.Device", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("EmailAddress")
+ .HasColumnType("TEXT");
+
+ b.Property("IpAddress")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LastUsed")
+ .HasColumnType("TEXT");
+
+ b.Property("LastUsedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("Platform")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId");
+
+ b.ToTable("Device");
+ });
+
+ modelBuilder.Entity("API.Entities.FolderPath", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("LastScanned")
+ .HasColumnType("TEXT");
+
+ b.Property("LibraryId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Path")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("LibraryId");
+
+ b.ToTable("FolderPath");
+ });
+
+ modelBuilder.Entity("API.Entities.Genre", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("NormalizedTitle")
+ .HasColumnType("TEXT");
+
+ b.Property("Title")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("NormalizedTitle")
+ .IsUnique();
+
+ b.ToTable("Genre");
+ });
+
+ modelBuilder.Entity("API.Entities.Library", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverImage")
+ .HasColumnType("TEXT");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("FolderWatching")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("IncludeInDashboard")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("IncludeInRecommended")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("IncludeInSearch")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LastScanned")
+ .HasColumnType("TEXT");
+
+ b.Property("ManageCollections")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER")
+ .HasDefaultValue(true);
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Library");
+ });
+
+ modelBuilder.Entity("API.Entities.MangaFile", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Bytes")
+ .HasColumnType("INTEGER");
+
+ b.Property("ChapterId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Extension")
+ .HasColumnType("TEXT");
+
+ b.Property("FilePath")
+ .HasColumnType("TEXT");
+
+ b.Property("Format")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastFileAnalysis")
+ .HasColumnType("TEXT");
+
+ b.Property("LastFileAnalysisUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("Pages")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChapterId");
+
+ b.ToTable("MangaFile");
+ });
+
+ modelBuilder.Entity("API.Entities.Metadata.SeriesMetadata", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRatingLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("CharacterLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("ColoristLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverArtistLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("EditorLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("GenresLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("InkerLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("Language")
+ .HasColumnType("TEXT");
+
+ b.Property("LanguageLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("LettererLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("MaxCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("PencillerLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("PublicationStatus")
+ .HasColumnType("INTEGER");
+
+ b.Property("PublicationStatusLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("PublisherLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("ReleaseYear")
+ .HasColumnType("INTEGER");
+
+ b.Property("ReleaseYearLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("RowVersion")
+ .IsConcurrencyToken()
+ .HasColumnType("INTEGER");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Summary")
+ .HasColumnType("TEXT");
+
+ b.Property("SummaryLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("TagsLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("TotalCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("TranslatorLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("WriterLocked")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SeriesId")
+ .IsUnique();
+
+ b.HasIndex("Id", "SeriesId")
+ .IsUnique();
+
+ b.ToTable("SeriesMetadata");
+ });
+
+ modelBuilder.Entity("API.Entities.Metadata.SeriesRelation", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("RelationKind")
+ .HasColumnType("INTEGER");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.Property("TargetSeriesId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("SeriesId");
+
+ b.HasIndex("TargetSeriesId");
+
+ b.ToTable("SeriesRelation");
+ });
+
+ modelBuilder.Entity("API.Entities.Person", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedName")
+ .HasColumnType("TEXT");
+
+ b.Property("Role")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.ToTable("Person");
+ });
+
+ modelBuilder.Entity("API.Entities.ReadingList", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AgeRating")
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverImage")
+ .HasColumnType("TEXT");
+
+ b.Property("CoverImageLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("EndingMonth")
+ .HasColumnType("INTEGER");
+
+ b.Property("EndingYear")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastModified")
+ .HasColumnType("TEXT");
+
+ b.Property("LastModifiedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("NormalizedTitle")
+ .HasColumnType("TEXT");
+
+ b.Property("Promoted")
+ .HasColumnType("INTEGER");
+
+ b.Property("StartingMonth")
+ .HasColumnType("INTEGER");
+
+ b.Property("StartingYear")
+ .HasColumnType("INTEGER");
+
+ b.Property("Summary")
+ .HasColumnType("TEXT");
+
+ b.Property("Title")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AppUserId");
+
+ b.ToTable("ReadingList");
+ });
+
+ modelBuilder.Entity("API.Entities.ReadingListItem", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("ChapterId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Order")
+ .HasColumnType("INTEGER");
+
+ b.Property("ReadingListId")
+ .HasColumnType("INTEGER");
+
+ b.Property("SeriesId")
+ .HasColumnType("INTEGER");
+
+ b.Property("VolumeId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("Id");
+
+ b.HasIndex("ChapterId");
+
+ b.HasIndex("ReadingListId");
+
+ b.HasIndex("SeriesId");
+
+ b.HasIndex("VolumeId");
+
+ b.ToTable("ReadingListItem");
+ });
+
+ modelBuilder.Entity("API.Entities.SecurityEvent", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("CreatedAt")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedAtUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("IpAddress")
+ .HasColumnType("TEXT");
+
+ b.Property("RequestMethod")
+ .HasColumnType("TEXT");
+
+ b.Property("RequestPath")
+ .HasColumnType("TEXT");
+
+ b.Property("UserAgent")
+ .HasColumnType("TEXT");
+
+ b.HasKey("Id");
+
+ b.ToTable("SecurityEvent");
+ });
+
+ modelBuilder.Entity("API.Entities.Series", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("AppUserId")
+ .HasColumnType("INTEGER");
+
+ b.Property("AvgHoursToRead")
+ .HasColumnType("INTEGER");
+
+ b.Property("CoverImage")
+ .HasColumnType("TEXT");
+
+ b.Property("CoverImageLocked")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("CreatedUtc")
+ .HasColumnType("TEXT");
+
+ b.Property("FolderPath")
+ .HasColumnType("TEXT");
+
+ b.Property