mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
.NET 7 + Spring Cleaning (#1677)
* Updated to net7.0 * Updated GA to .net 7 * Updated System.IO.Abstractions to use New factory. * Converted Regex into SourceGenerator in Parser. * Updated more regex to source generators. * Enabled Nullability and more regex changes throughout codebase. * Parser is 100% GeneratedRegexified * Lots of nullability code * Enabled nullability for all repositories. * Fixed another unit test * Refactored some code around and took care of some todos. * Updating code for nullability and cleaning up methods that aren't used anymore. Refctored all uses of Parser.Normalize() to use new extension * More nullability exercises. 500 warnings to go. * Fixed a bug where custom file uploads for entities wouldn't save in webP. * Nullability is done for all DTOs * Fixed all unit tests and nullability for the project. Only OPDS is left which will be done with an upcoming OPDS enhancement. * Use localization in book service after validating * Code smells * Switched to preview build of swashbuckle for .net7 support * Fixed up merge issues * Disable emulate comic book when on single page reader * Fixed a regression where double page renderer wouldn't layout the images correctly * Updated to swashbuckle which support .net 7 * Fixed a bad GA action * Some code cleanup * More code smells * Took care of most of nullable issues * Fixed a broken test due to having more than one test run in parallel * I'm really not sure why the unit tests are failing or are so extremely slow on .net 7 * Updated all dependencies * Fixed up build and removed hardcoded framework from build scripts. (this merge removes Regex Source generators). Unit tests are completely busted. * Unit tests and code cleanup. Needs shakeout now. * Adjusted Series model since a few fields are not-nullable. Removed dead imports on the project. * Refactored to use Builder pattern for all unit tests. * Switched nullability down to warnings. It wasn't possible to switch due to constraint issues in DB Migration.
This commit is contained in:
parent
76fe3fd64a
commit
5d1dd7b3f0
16
.github/workflows/sonar-scan.yml
vendored
16
.github/workflows/sonar-scan.yml
vendored
@ -20,11 +20,11 @@ jobs:
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
dotnet-version: 7.0.x
|
||||
|
||||
- name: Install Swashbuckle CLI
|
||||
shell: powershell
|
||||
run: dotnet tool install -g --version 6.4.0 Swashbuckle.AspNetCore.Cli
|
||||
run: dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli
|
||||
|
||||
- name: Install dependencies
|
||||
run: dotnet restore
|
||||
@ -88,10 +88,10 @@ jobs:
|
||||
- name: Setup .NET Core
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
dotnet-version: 7.0.x
|
||||
|
||||
- name: Install Swashbuckle CLI
|
||||
run: dotnet tool install -g --version 6.4.0 Swashbuckle.AspNetCore.Cli
|
||||
run: dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli
|
||||
|
||||
- name: Install dependencies
|
||||
run: dotnet restore
|
||||
@ -178,10 +178,10 @@ jobs:
|
||||
- name: Compile dotnet app
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
dotnet-version: 7.0.x
|
||||
|
||||
- name: Install Swashbuckle CLI
|
||||
run: dotnet tool install -g --version 6.4.0 Swashbuckle.AspNetCore.Cli
|
||||
run: dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli
|
||||
|
||||
- run: ./monorepo-build.sh
|
||||
|
||||
@ -295,9 +295,9 @@ jobs:
|
||||
- name: Compile dotnet app
|
||||
uses: actions/setup-dotnet@v2
|
||||
with:
|
||||
dotnet-version: 6.0.x
|
||||
dotnet-version: 7.0.x
|
||||
- name: Install Swashbuckle CLI
|
||||
run: dotnet tool install -g --version 6.4.0 Swashbuckle.AspNetCore.Cli
|
||||
run: dotnet tool install -g --version 6.5.0 Swashbuckle.AspNetCore.Cli
|
||||
|
||||
- run: ./monorepo-build.sh
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -10,9 +10,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
|
||||
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.2" />
|
||||
<PackageReference Include="NSubstitute" Version="4.4.0" />
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.13.5" />
|
||||
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.5" />
|
||||
<PackageReference Include="NSubstitute" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -16,7 +16,7 @@ namespace API.Benchmark;
|
||||
[MemoryDiagnoser]
|
||||
[RankColumn]
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
[SimpleJob(launchCount: 1, warmupCount: 5, targetCount: 20)]
|
||||
[SimpleJob(launchCount: 1, warmupCount: 5, invocationCount: 20)]
|
||||
public class ArchiveServiceBenchmark
|
||||
{
|
||||
private readonly ArchiveService _archiveService;
|
||||
|
@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using BenchmarkDotNet.Order;
|
||||
|
||||
namespace API.Benchmark;
|
||||
|
||||
|
@ -14,23 +14,12 @@ namespace API.Benchmark;
|
||||
[MemoryDiagnoser]
|
||||
[RankColumn]
|
||||
[Orderer(SummaryOrderPolicy.FastestToSlowest)]
|
||||
[SimpleJob(launchCount: 1, warmupCount: 5, targetCount: 20)]
|
||||
[SimpleJob(launchCount: 1, warmupCount: 5, invocationCount: 20)]
|
||||
public class EpubBenchmark
|
||||
{
|
||||
private const string FilePath = @"E:\Books\Invaders of the Rokujouma\Invaders of the Rokujouma - Volume 01.epub";
|
||||
private readonly Regex WordRegex = new Regex(@"\b\w+\b", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
// [Benchmark]
|
||||
// public async Task GetWordCount_PassByString()
|
||||
// {
|
||||
// using var book = await EpubReader.OpenBookAsync(FilePath, BookService.BookReaderOptions);
|
||||
// foreach (var bookFile in book.Content.Html.Values)
|
||||
// {
|
||||
// GetBookWordCount_PassByString(await bookFile.ReadContentAsTextAsync());
|
||||
// ;
|
||||
// }
|
||||
// }
|
||||
|
||||
[Benchmark]
|
||||
public async Task GetWordCount_PassByRef()
|
||||
{
|
||||
|
@ -74,5 +74,24 @@ public class ParserBenchmarks
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Test_CharacterReplace()
|
||||
{
|
||||
foreach (var name in _names)
|
||||
{
|
||||
var d = name.Contains('a');
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void Test_StringReplace()
|
||||
{
|
||||
foreach (var name in _names)
|
||||
{
|
||||
|
||||
var d = name.Contains("a");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,39 +1,38 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
|
||||
<PackageReference Include="Moq" Version="4.18.4" />
|
||||
<PackageReference Include="NSubstitute" Version="4.4.0" />
|
||||
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="17.2.3" />
|
||||
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="19.2.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.2" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\API\API.csproj" />
|
||||
<ProjectReference Include="..\API\API.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\Test Data\ArchiveService\ComicInfos" />
|
||||
<Folder Include="Services\Test Data\ScannerService\Manga" />
|
||||
<Folder Include="Services\Test Data\ArchiveService\ComicInfos" />
|
||||
<Folder Include="Services\Test Data\ScannerService\Manga" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Extensions\Test Data\modified on run.txt" />
|
||||
<None Remove="Extensions\Test Data\modified on run.txt" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -29,6 +29,7 @@ public abstract class AbstractDbTest
|
||||
protected const string BackupDirectory = "C:/kavita/config/backups/";
|
||||
protected const string LogDirectory = "C:/kavita/config/logs/";
|
||||
protected const string BookmarkDirectory = "C:/kavita/config/bookmarks/";
|
||||
protected const string SiteThemeDirectory = "C:/kavita/config/themes/";
|
||||
protected const string TempDirectory = "C:/kavita/config/temp/";
|
||||
protected const string DataDirectory = "C:/data/";
|
||||
|
||||
@ -103,6 +104,7 @@ public abstract class AbstractDbTest
|
||||
fileSystem.AddDirectory(CoverImageDirectory);
|
||||
fileSystem.AddDirectory(BackupDirectory);
|
||||
fileSystem.AddDirectory(BookmarkDirectory);
|
||||
fileSystem.AddDirectory(SiteThemeDirectory);
|
||||
fileSystem.AddDirectory(LogDirectory);
|
||||
fileSystem.AddDirectory(TempDirectory);
|
||||
fileSystem.AddDirectory(DataDirectory);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using API.Data;
|
||||
using API.Extensions;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Entities;
|
||||
@ -12,7 +13,7 @@ public class SeriesTest
|
||||
[InlineData("Darker than Black")]
|
||||
public void CreateSeries(string name)
|
||||
{
|
||||
var key = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name);
|
||||
var key = name.ToNormalized();
|
||||
var series = DbFactory.Series(name);
|
||||
Assert.Equal(0, series.Id);
|
||||
Assert.Equal(0, series.Pages);
|
||||
|
@ -27,7 +27,7 @@ public class ParserInfoListExtensions
|
||||
[InlineData(new[] {"1", "1", "3-5", "5", "8", "0", "0"}, new[] {"1", "3-5", "5", "8", "0"})]
|
||||
public void DistinctVolumesTest(string[] volumeNumbers, string[] expectedNumbers)
|
||||
{
|
||||
var infos = volumeNumbers.Select(n => new ParserInfo() {Volumes = n}).ToList();
|
||||
var infos = volumeNumbers.Select(n => new ParserInfo() {Series = "", Volumes = n}).ToList();
|
||||
Assert.Equal(expectedNumbers, infos.DistinctVolumes());
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Data;
|
||||
using API.Data.Misc;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Extensions;
|
||||
@ -18,27 +20,24 @@ public class QueryableExtensionsTests
|
||||
{
|
||||
var items = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Metadata = new SeriesMetadata()
|
||||
new SeriesBuilder("Test 1")
|
||||
.WithMetadata( new SeriesMetadata()
|
||||
{
|
||||
AgeRating = AgeRating.Teen,
|
||||
}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Metadata = new SeriesMetadata()
|
||||
})
|
||||
.Build(),
|
||||
new SeriesBuilder("Test 2")
|
||||
.WithMetadata( new SeriesMetadata()
|
||||
{
|
||||
AgeRating = AgeRating.Unknown,
|
||||
}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Metadata = new SeriesMetadata()
|
||||
})
|
||||
.Build(),
|
||||
new SeriesBuilder("Test 3")
|
||||
.WithMetadata( new SeriesMetadata()
|
||||
{
|
||||
AgeRating = AgeRating.X18Plus,
|
||||
}
|
||||
},
|
||||
})
|
||||
.Build()
|
||||
};
|
||||
|
||||
var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
|
||||
@ -58,6 +57,8 @@ public class QueryableExtensionsTests
|
||||
{
|
||||
new CollectionTag()
|
||||
{
|
||||
Title = "Test",
|
||||
NormalizedTitle = "Test".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -68,6 +69,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new CollectionTag()
|
||||
{
|
||||
Title = "Test",
|
||||
NormalizedTitle = "Test".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -82,6 +85,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new CollectionTag()
|
||||
{
|
||||
Title = "Test",
|
||||
NormalizedTitle = "Test".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -109,6 +114,8 @@ public class QueryableExtensionsTests
|
||||
{
|
||||
new Genre()
|
||||
{
|
||||
Title = "A",
|
||||
NormalizedTitle = "A".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -119,6 +126,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new Genre()
|
||||
{
|
||||
Title = "B",
|
||||
NormalizedTitle = "B".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -133,6 +142,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new Genre()
|
||||
{
|
||||
Title = "C",
|
||||
NormalizedTitle = "C".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -160,6 +171,8 @@ public class QueryableExtensionsTests
|
||||
{
|
||||
new Tag()
|
||||
{
|
||||
Title = "Test 1",
|
||||
NormalizedTitle = "Test 1".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -170,6 +183,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new Tag()
|
||||
{
|
||||
Title = "Test 2",
|
||||
NormalizedTitle = "Test 2".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -184,6 +199,8 @@ public class QueryableExtensionsTests
|
||||
},
|
||||
new Tag()
|
||||
{
|
||||
Title = "Test 3",
|
||||
NormalizedTitle = "Test 3".ToNormalized(),
|
||||
SeriesMetadatas = new List<SeriesMetadata>()
|
||||
{
|
||||
new SeriesMetadata()
|
||||
@ -258,20 +275,12 @@ public class QueryableExtensionsTests
|
||||
[InlineData(false, 1)]
|
||||
public void RestrictAgainstAgeRestriction_ReadingList_ShouldRestrictEverythingAboveTeen(bool includeUnknowns, int expectedCount)
|
||||
{
|
||||
|
||||
var items = new List<ReadingList>()
|
||||
{
|
||||
new ReadingList()
|
||||
{
|
||||
AgeRating = AgeRating.Teen,
|
||||
},
|
||||
new ReadingList()
|
||||
{
|
||||
AgeRating = AgeRating.Unknown,
|
||||
},
|
||||
new ReadingList()
|
||||
{
|
||||
AgeRating = AgeRating.X18Plus
|
||||
},
|
||||
DbFactory.ReadingList("Test List", null, false, AgeRating.Teen),
|
||||
DbFactory.ReadingList("Test List", null, false, AgeRating.Unknown),
|
||||
DbFactory.ReadingList("Test List", null, false, AgeRating.X18Plus),
|
||||
};
|
||||
|
||||
var filtered = items.AsQueryable().RestrictAgainstAgeRestriction(new AgeRestriction()
|
||||
|
@ -3,124 +3,31 @@ using System.Linq;
|
||||
using API.Comparators;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Parser;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Extensions;
|
||||
|
||||
public class SeriesExtensionsTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, true)]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, true)]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, false)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, true)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, true)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, true)]
|
||||
// Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, true)]
|
||||
[InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, true)]
|
||||
public void NameInListTest(string[] seriesInput, string[] list, bool expected)
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Name = seriesInput[0],
|
||||
LocalizedName = seriesInput[1],
|
||||
OriginalName = seriesInput[2],
|
||||
NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
|
||||
Metadata = new SeriesMetadata()
|
||||
};
|
||||
|
||||
Assert.Equal(expected, series.NameInList(list));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker than Black"}, MangaFormat.Archive, true)]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker_than_Black"}, MangaFormat.Archive, true)]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, new [] {"Darker then Black!"}, MangaFormat.Archive, false)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"Salem's Lot"}, MangaFormat.Archive, true)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salems lot"}, MangaFormat.Archive, true)]
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
|
||||
// Different normalizations pass as we check normalization against an on-the-fly calculation so we don't delete series just because we change how normalization works
|
||||
[InlineData(new [] {"Salem's Lot", "Salem's Lot", "Salem's Lot", "salems lot"}, new [] {"salem's lot"}, MangaFormat.Archive, true)]
|
||||
[InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, new [] {"Kanojo, Okarishimasu"}, MangaFormat.Archive, true)]
|
||||
public void NameInListParserInfoTest(string[] seriesInput, string[] list, MangaFormat format, bool expected)
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Name = seriesInput[0],
|
||||
LocalizedName = seriesInput[1],
|
||||
OriginalName = seriesInput[2],
|
||||
NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
|
||||
Metadata = new SeriesMetadata(),
|
||||
};
|
||||
|
||||
var parserInfos = list.Select(s => new ParsedSeries()
|
||||
{
|
||||
Name = s,
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(s),
|
||||
}).ToList();
|
||||
|
||||
// This doesn't do any checks against format
|
||||
Assert.Equal(expected, series.NameInList(parserInfos));
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData(new [] {"Darker than Black", "Darker Than Black", "Darker than Black"}, "Darker than Black", true)]
|
||||
[InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Kanojo, Okarishimasu", true)]
|
||||
[InlineData(new [] {"Rent-a-Girlfriend", "Rent-a-Girlfriend", "Kanojo, Okarishimasu", "rentagirlfriend"}, "Rent", false)]
|
||||
public void NameInParserInfoTest(string[] seriesInput, string parserSeries, bool expected)
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Name = seriesInput[0],
|
||||
LocalizedName = seriesInput[1],
|
||||
OriginalName = seriesInput[2],
|
||||
NormalizedName = seriesInput.Length == 4 ? seriesInput[3] : API.Services.Tasks.Scanner.Parser.Parser.Normalize(seriesInput[0]),
|
||||
Metadata = new SeriesMetadata()
|
||||
};
|
||||
var info = new ParserInfo
|
||||
{
|
||||
Series = parserSeries
|
||||
};
|
||||
|
||||
Assert.Equal(expected, series.NameInParserInfo(info));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetCoverImage_MultipleSpecials_Comics()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 2",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
|
||||
.WithCoverImage("Special 1")
|
||||
.WithIsSpecial(true)
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
|
||||
.WithCoverImage("Special 2")
|
||||
.WithIsSpecial(true)
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
Assert.Equal("Special 1", series.GetCoverImage());
|
||||
|
||||
@ -129,33 +36,20 @@ public class SeriesExtensionsTests
|
||||
[Fact]
|
||||
public void GetCoverImage_MultipleSpecials_Books()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Epub,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 2",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
|
||||
.WithCoverImage("Special 1")
|
||||
.WithIsSpecial(true)
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder(API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter)
|
||||
.WithCoverImage("Special 2")
|
||||
.WithIsSpecial(true)
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
Assert.Equal("Special 1", series.GetCoverImage());
|
||||
}
|
||||
@ -163,33 +57,20 @@ public class SeriesExtensionsTests
|
||||
[Fact]
|
||||
public void GetCoverImage_JustChapters_Comics()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2.5",
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2",
|
||||
CoverImage = "Special 2",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder("2.5")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 1")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 2")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
foreach (var vol in series.Volumes)
|
||||
{
|
||||
@ -202,39 +83,24 @@ public class SeriesExtensionsTests
|
||||
[Fact]
|
||||
public void GetCoverImage_JustChaptersAndSpecials_Comics()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2.5",
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2",
|
||||
CoverImage = "Special 2",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 3",
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder("2.5")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 1")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 2")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.WithIsSpecial(true)
|
||||
.WithCoverImage("Special 3")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
foreach (var vol in series.Volumes)
|
||||
{
|
||||
@ -247,54 +113,31 @@ public class SeriesExtensionsTests
|
||||
[Fact]
|
||||
public void GetCoverImage_VolumesChapters_Comics()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2.5",
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2",
|
||||
CoverImage = "Special 2",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 3",
|
||||
}
|
||||
},
|
||||
},
|
||||
new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "1",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "0",
|
||||
CoverImage = "Volume 1",
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder("2.5")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 1")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 2")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.WithIsSpecial(true)
|
||||
.WithCoverImage("Special 3")
|
||||
.Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Volume 1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
foreach (var vol in series.Volumes)
|
||||
{
|
||||
@ -307,54 +150,31 @@ public class SeriesExtensionsTests
|
||||
[Fact]
|
||||
public void GetCoverImage_VolumesChaptersAndSpecials_Comics()
|
||||
{
|
||||
var series = new Series()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 0,
|
||||
Name = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume,
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2.5",
|
||||
CoverImage = "Special 1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "2",
|
||||
CoverImage = "Special 2",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = true,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter,
|
||||
CoverImage = "Special 3",
|
||||
}
|
||||
},
|
||||
},
|
||||
new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "1",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
IsSpecial = false,
|
||||
Number = "0",
|
||||
CoverImage = "Volume 1",
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
var series = new SeriesBuilder("Test 1")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithName(API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume)
|
||||
.WithChapter(new ChapterBuilder("2.5")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 1")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Special 2")
|
||||
.Build())
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.WithIsSpecial(true)
|
||||
.WithCoverImage("Special 3")
|
||||
.Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.WithIsSpecial(false)
|
||||
.WithCoverImage("Volume 1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
foreach (var vol in series.Volumes)
|
||||
{
|
||||
|
58
API.Tests/Helpers/Builders/ChapterBuilder.cs
Normal file
58
API.Tests/Helpers/Builders/ChapterBuilder.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
|
||||
namespace API.Tests.Helpers.Builders;
|
||||
|
||||
public class ChapterBuilder : IEntityBuilder<Chapter>
|
||||
{
|
||||
private Chapter _chapter;
|
||||
public Chapter Build() => _chapter;
|
||||
|
||||
public ChapterBuilder(string number, string? range=null)
|
||||
{
|
||||
_chapter = new Chapter()
|
||||
{
|
||||
Range = string.IsNullOrEmpty(range) ? number : range,
|
||||
Title = string.IsNullOrEmpty(range) ? number : range,
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(number) + string.Empty,
|
||||
Files = new List<MangaFile>(),
|
||||
Pages = 1
|
||||
};
|
||||
}
|
||||
|
||||
public ChapterBuilder WithAgeRating(AgeRating rating)
|
||||
{
|
||||
_chapter.AgeRating = rating;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChapterBuilder WithPages(int pages)
|
||||
{
|
||||
_chapter.Pages = pages;
|
||||
return this;
|
||||
}
|
||||
public ChapterBuilder WithCoverImage(string cover)
|
||||
{
|
||||
_chapter.CoverImage = cover;
|
||||
return this;
|
||||
}
|
||||
public ChapterBuilder WithIsSpecial(bool isSpecial)
|
||||
{
|
||||
_chapter.IsSpecial = isSpecial;
|
||||
return this;
|
||||
}
|
||||
public ChapterBuilder WithTitle(string title)
|
||||
{
|
||||
_chapter.Title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ChapterBuilder WithFile(MangaFile file)
|
||||
{
|
||||
_chapter.Files ??= new List<MangaFile>();
|
||||
_chapter.Files.Add(file);
|
||||
return this;
|
||||
}
|
||||
}
|
6
API.Tests/Helpers/Builders/EntityBuilder.cs
Normal file
6
API.Tests/Helpers/Builders/EntityBuilder.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace API.Tests.Helpers.Builders;
|
||||
|
||||
public interface IEntityBuilder<out T>
|
||||
{
|
||||
public T Build();
|
||||
}
|
71
API.Tests/Helpers/Builders/SeriesBuilder.cs
Normal file
71
API.Tests/Helpers/Builders/SeriesBuilder.cs
Normal file
@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
|
||||
namespace API.Tests.Helpers.Builders;
|
||||
|
||||
public class SeriesBuilder : IEntityBuilder<Series>
|
||||
{
|
||||
private readonly Series _series;
|
||||
public Series Build()
|
||||
{
|
||||
_series.Pages = _series.Volumes.Sum(v => v.Chapters.Sum(c => c.Pages));
|
||||
return _series;
|
||||
}
|
||||
|
||||
public SeriesBuilder(string name)
|
||||
{
|
||||
_series = new Series()
|
||||
{
|
||||
Name = name,
|
||||
LocalizedName = name.ToNormalized(),
|
||||
OriginalName = name,
|
||||
SortName = name,
|
||||
NormalizedName = name.ToNormalized(),
|
||||
NormalizedLocalizedName = name.ToNormalized(),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Volumes = new List<Volume>()
|
||||
};
|
||||
}
|
||||
|
||||
public SeriesBuilder WithLocalizedName(string localizedName)
|
||||
{
|
||||
_series.LocalizedName = localizedName;
|
||||
_series.NormalizedLocalizedName = localizedName.ToNormalized();
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeriesBuilder WithFormat(MangaFormat format)
|
||||
{
|
||||
_series.Format = format;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeriesBuilder WithVolume(Volume volume)
|
||||
{
|
||||
_series.Volumes ??= new List<Volume>();
|
||||
_series.Volumes.Add(volume);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeriesBuilder WithVolumes(List<Volume> volumes)
|
||||
{
|
||||
_series.Volumes = volumes;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeriesBuilder WithMetadata(SeriesMetadata metadata)
|
||||
{
|
||||
_series.Metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SeriesBuilder WithPages(int pages)
|
||||
{
|
||||
_series.Pages = pages;
|
||||
return this;
|
||||
}
|
||||
}
|
37
API.Tests/Helpers/Builders/SeriesMetadataBuilder.cs
Normal file
37
API.Tests/Helpers/Builders/SeriesMetadataBuilder.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Collections.Generic;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
|
||||
namespace API.Tests.Helpers.Builders;
|
||||
|
||||
public class SeriesMetadataBuilder : IEntityBuilder<SeriesMetadata>
|
||||
{
|
||||
private SeriesMetadata _seriesMetadata;
|
||||
public SeriesMetadata Build() => _seriesMetadata;
|
||||
|
||||
public SeriesMetadataBuilder()
|
||||
{
|
||||
_seriesMetadata = new SeriesMetadata()
|
||||
{
|
||||
CollectionTags = new List<CollectionTag>(),
|
||||
Genres = new List<Genre>(),
|
||||
Tags = new List<Tag>(),
|
||||
People = new List<Person>()
|
||||
};
|
||||
}
|
||||
|
||||
public SeriesMetadataBuilder WithCollectionTag(CollectionTag tag)
|
||||
{
|
||||
_seriesMetadata.CollectionTags ??= new List<API.Entities.CollectionTag>();
|
||||
_seriesMetadata.CollectionTags.Add(tag);
|
||||
return this;
|
||||
}
|
||||
public SeriesMetadataBuilder WithPublicationStatus(PublicationStatus status)
|
||||
{
|
||||
_seriesMetadata.PublicationStatus = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
43
API.Tests/Helpers/Builders/VolumeBuilder.cs
Normal file
43
API.Tests/Helpers/Builders/VolumeBuilder.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
|
||||
namespace API.Tests.Helpers.Builders;
|
||||
|
||||
public class VolumeBuilder : IEntityBuilder<Volume>
|
||||
{
|
||||
private readonly Volume _volume;
|
||||
public Volume Build() => _volume;
|
||||
|
||||
public VolumeBuilder(string volumeNumber)
|
||||
{
|
||||
_volume = DbFactory.Volume(volumeNumber);
|
||||
}
|
||||
|
||||
public VolumeBuilder WithName(string name)
|
||||
{
|
||||
_volume.Name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VolumeBuilder WithNumber(int number)
|
||||
{
|
||||
_volume.Number = number;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VolumeBuilder WithChapters(List<Chapter> chapters)
|
||||
{
|
||||
_volume.Chapters = chapters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public VolumeBuilder WithChapter(Chapter chapter)
|
||||
{
|
||||
_volume.Chapters ??= new List<Chapter>();
|
||||
_volume.Chapters.Add(chapter);
|
||||
_volume.Pages = _volume.Chapters.Sum(c => c.Pages);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -156,6 +156,8 @@ public class CacheHelperTests
|
||||
|
||||
var chapter = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Created = filesystemFile.LastWriteTime.DateTime,
|
||||
LastModified = filesystemFile.LastWriteTime.DateTime
|
||||
};
|
||||
@ -186,6 +188,8 @@ public class CacheHelperTests
|
||||
|
||||
var chapter = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Created = filesystemFile.LastWriteTime.DateTime,
|
||||
LastModified = filesystemFile.LastWriteTime.DateTime
|
||||
};
|
||||
@ -216,6 +220,8 @@ public class CacheHelperTests
|
||||
|
||||
var chapter = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Created = filesystemFile.LastWriteTime.DateTime,
|
||||
LastModified = filesystemFile.LastWriteTime.DateTime
|
||||
};
|
||||
@ -247,6 +253,8 @@ public class CacheHelperTests
|
||||
|
||||
var chapter = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Created = DateTime.Now.Subtract(TimeSpan.FromMinutes(10)),
|
||||
LastModified = DateTime.Now.Subtract(TimeSpan.FromMinutes(10))
|
||||
};
|
||||
@ -277,6 +285,8 @@ public class CacheHelperTests
|
||||
|
||||
var chapter = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Created = DateTime.Now.Subtract(TimeSpan.FromMinutes(10)),
|
||||
LastModified = DateTime.Now
|
||||
};
|
||||
|
@ -4,6 +4,7 @@ using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
|
||||
namespace API.Tests.Helpers;
|
||||
|
||||
@ -19,7 +20,9 @@ public static class EntityFactory
|
||||
Name = name,
|
||||
SortName = name,
|
||||
LocalizedName = name,
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(name),
|
||||
NormalizedName = name.ToNormalized(),
|
||||
OriginalName = name,
|
||||
NormalizedLocalizedName = name.ToNormalized(),
|
||||
Volumes = new List<Volume>(),
|
||||
Metadata = new SeriesMetadata()
|
||||
};
|
||||
@ -38,7 +41,7 @@ public static class EntityFactory
|
||||
};
|
||||
}
|
||||
|
||||
public static Chapter CreateChapter(string range, bool isSpecial, List<MangaFile> files = null, int pageCount = 0)
|
||||
public static Chapter CreateChapter(string range, bool isSpecial, List<MangaFile> files = null, int pageCount = 0, string title = null)
|
||||
{
|
||||
return new Chapter()
|
||||
{
|
||||
@ -47,7 +50,7 @@ public static class EntityFactory
|
||||
Number = API.Services.Tasks.Scanner.Parser.Parser.MinNumberFromRange(range) + string.Empty,
|
||||
Files = files ?? new List<MangaFile>(),
|
||||
Pages = pageCount,
|
||||
|
||||
Title = title ?? range
|
||||
};
|
||||
}
|
||||
|
||||
@ -66,3 +69,6 @@ public static class EntityFactory
|
||||
return DbFactory.CollectionTag(id, title, summary, promoted);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Parser;
|
||||
using API.Services.Tasks.Scanner;
|
||||
|
||||
@ -29,12 +30,12 @@ public static class ParserInfoFactory
|
||||
public static void AddToParsedInfo(IDictionary<ParsedSeries, IList<ParserInfo>> collectedSeries, ParserInfo info)
|
||||
{
|
||||
var existingKey = collectedSeries.Keys.FirstOrDefault(ps =>
|
||||
ps.Format == info.Format && ps.NormalizedName == API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series));
|
||||
ps.Format == info.Format && ps.NormalizedName == info.Series.ToNormalized());
|
||||
existingKey ??= new ParsedSeries()
|
||||
{
|
||||
Format = info.Format,
|
||||
Name = info.Series,
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(info.Series)
|
||||
NormalizedName = info.Series.ToNormalized()
|
||||
};
|
||||
if (collectedSeries.GetType() == typeof(ConcurrentDictionary<,>))
|
||||
{
|
||||
|
@ -2,9 +2,11 @@
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Parser;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Helpers;
|
||||
@ -21,23 +23,14 @@ public class ParserInfoHelperTests
|
||||
ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Archive});
|
||||
//AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Epub});
|
||||
|
||||
var series = new Series()
|
||||
{
|
||||
Name = "Darker Than Black",
|
||||
LocalizedName = "Darker Than Black",
|
||||
OriginalName = "Darker Than Black",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "1"
|
||||
}
|
||||
},
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker Than Black"),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Format = MangaFormat.Epub
|
||||
};
|
||||
var series = new SeriesBuilder("Darker Than Black")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithName("1")
|
||||
.Build())
|
||||
.WithLocalizedName("Darker Than Black")
|
||||
.Build();
|
||||
|
||||
Assert.False(ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(series, infos));
|
||||
}
|
||||
@ -50,23 +43,15 @@ public class ParserInfoHelperTests
|
||||
ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Archive});
|
||||
ParserInfoFactory.AddToParsedInfo(infos, new ParserInfo() {Series = "Darker than Black", Volumes = "1", Format = MangaFormat.Epub});
|
||||
|
||||
var series = new Series()
|
||||
{
|
||||
Name = "Darker Than Black",
|
||||
LocalizedName = "Darker Than Black",
|
||||
OriginalName = "Darker Than Black",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "1"
|
||||
}
|
||||
},
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker Than Black"),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Format = MangaFormat.Epub
|
||||
};
|
||||
|
||||
var series = new SeriesBuilder("Darker Than Black")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithName("1")
|
||||
.Build())
|
||||
.WithLocalizedName("Darker Than Black")
|
||||
.Build();
|
||||
|
||||
Assert.True(ParserInfoHelpers.SeriesHasMatchingParserInfoFormat(series, infos));
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using Xunit;
|
||||
@ -22,21 +23,35 @@ public class SeriesHelperTests
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "Darker than Black",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "Darker than Black".ToLower(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "Darker than Black".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindSeries_ShouldFind_NullName()
|
||||
{
|
||||
var series = DbFactory.Series("Darker than Black");
|
||||
series.OriginalName = null;
|
||||
series.Format = MangaFormat.Archive;
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "Darker than Black",
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
}
|
||||
|
||||
@ -50,21 +65,21 @@ public class SeriesHelperTests
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Darker than Black",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.False(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Darker than Black".ToLower(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.False(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Darker than Black".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker than Black")
|
||||
NormalizedName = "Darker than Black".ToNormalized()
|
||||
}));
|
||||
}
|
||||
|
||||
@ -78,28 +93,28 @@ public class SeriesHelperTests
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random".ToLower(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "SomethingRandom".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("SomethingRandom")
|
||||
NormalizedName = "SomethingRandom".ToNormalized()
|
||||
}));
|
||||
}
|
||||
|
||||
@ -113,28 +128,28 @@ public class SeriesHelperTests
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random".ToLower(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "Something Random".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something Random")
|
||||
NormalizedName = "Something Random".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Image,
|
||||
Name = "SomethingRandom".ToUpper(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("SomethingRandom")
|
||||
NormalizedName = "SomethingRandom".ToNormalized()
|
||||
}));
|
||||
}
|
||||
|
||||
@ -148,14 +163,14 @@ public class SeriesHelperTests
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "My Dress-Up Darling",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("My Dress-Up Darling")
|
||||
NormalizedName = "My Dress-Up Darling".ToNormalized()
|
||||
}));
|
||||
|
||||
Assert.True(SeriesHelper.FindSeries(series, new ParsedSeries()
|
||||
{
|
||||
Format = MangaFormat.Archive,
|
||||
Name = "Sono Bisque Doll wa Koi wo Suru".ToLower(),
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Sono Bisque Doll wa Koi wo Suru")
|
||||
NormalizedName = "Sono Bisque Doll wa Koi wo Suru".ToNormalized()
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using API.Parser;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -51,7 +51,7 @@ public class DefaultParserTests
|
||||
{
|
||||
const string rootDirectory = "/manga/";
|
||||
var tokens = expectedParseInfo.Split("~");
|
||||
var actual = new ParserInfo {Chapters = "0", Volumes = "0"};
|
||||
var actual = new ParserInfo {Series = "", Chapters = "0", Volumes = "0"};
|
||||
_defaultParser.ParseFromFallbackFolders(inputFile, rootDirectory, LibraryType.Manga, ref actual);
|
||||
Assert.Equal(tokens[0], actual.Series);
|
||||
Assert.Equal(tokens[1], actual.Volumes);
|
||||
|
@ -1,4 +1,3 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using API.Entities.Enums;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
@ -249,7 +249,7 @@ public class ParserTests
|
||||
[InlineData("The ()quick brown fox jumps over the lazy dog")]
|
||||
[InlineData("The (quick (brown)) fox jumps over the lazy dog")]
|
||||
[InlineData("The (quick (brown) fox jumps over the lazy dog)")]
|
||||
public void BalancedParenTestMatches(string input)
|
||||
public void BalancedParenTest_Matches(string input)
|
||||
{
|
||||
Assert.Matches($@"^{BalancedParen}$", input);
|
||||
}
|
||||
@ -261,7 +261,7 @@ public class ParserTests
|
||||
[InlineData("The quick (brown)) fox jumps over the lazy dog")]
|
||||
[InlineData("The quick (brown) fox jumps over the lazy dog)")]
|
||||
[InlineData("(The ))(quick (brown) fox jumps over the lazy dog")]
|
||||
public void BalancedParenTestDoesNotMatch(string input)
|
||||
public void BalancedParenTest_DoesNotMatch(string input)
|
||||
{
|
||||
Assert.DoesNotMatch($@"^{BalancedParen}$", input);
|
||||
}
|
||||
@ -273,9 +273,9 @@ public class ParserTests
|
||||
[InlineData("The []quick brown fox jumps over the lazy dog")]
|
||||
[InlineData("The [quick [brown]] fox jumps over the lazy dog")]
|
||||
[InlineData("The [quick [brown] fox jumps over the lazy dog]")]
|
||||
public void BalancedBrackTestMatches(string input)
|
||||
public void BalancedBracketTest_Matches(string input)
|
||||
{
|
||||
Assert.Matches($@"^{BalancedBrack}$", input);
|
||||
Assert.Matches($@"^{BalancedBracket}$", input);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@ -285,8 +285,8 @@ public class ParserTests
|
||||
[InlineData("The quick [brown]] fox jumps over the lazy dog")]
|
||||
[InlineData("The quick [brown] fox jumps over the lazy dog]")]
|
||||
[InlineData("[The ]][quick [brown] fox jumps over the lazy dog")]
|
||||
public void BalancedBrackTestDoesNotMatch(string input)
|
||||
public void BalancedBracketTest_DoesNotMatch(string input)
|
||||
{
|
||||
Assert.DoesNotMatch($@"^{BalancedBrack}$", input);
|
||||
Assert.DoesNotMatch($@"^{BalancedBracket}$", input);
|
||||
}
|
||||
}
|
||||
|
177
API.Tests/Repository/CollectionTagRepositoryTests.cs
Normal file
177
API.Tests/Repository/CollectionTagRepositoryTests.cs
Normal file
@ -0,0 +1,177 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using AutoMapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Repository;
|
||||
|
||||
public class CollectionTagRepositoryTests
|
||||
{
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
private readonly DbConnection _connection;
|
||||
private readonly DataContext _context;
|
||||
|
||||
private const string CacheDirectory = "C:/kavita/config/cache/";
|
||||
private const string CoverImageDirectory = "C:/kavita/config/covers/";
|
||||
private const string BackupDirectory = "C:/kavita/config/backups/";
|
||||
private const string DataDirectory = "C:/data/";
|
||||
|
||||
public CollectionTagRepositoryTests()
|
||||
{
|
||||
var contextOptions = new DbContextOptionsBuilder().UseSqlite(CreateInMemoryDatabase()).Options;
|
||||
_connection = RelationalOptionsExtension.Extract(contextOptions).Connection;
|
||||
|
||||
_context = new DataContext(contextOptions);
|
||||
Task.Run(SeedDb).GetAwaiter().GetResult();
|
||||
|
||||
var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperProfiles>());
|
||||
var mapper = config.CreateMapper();
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null);
|
||||
}
|
||||
|
||||
#region Setup
|
||||
|
||||
private static DbConnection CreateInMemoryDatabase()
|
||||
{
|
||||
var connection = new SqliteConnection("Filename=:memory:");
|
||||
|
||||
connection.Open();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private async Task<bool> SeedDb()
|
||||
{
|
||||
await _context.Database.MigrateAsync();
|
||||
var filesystem = CreateFileSystem();
|
||||
|
||||
await Seed.SeedSettings(_context,
|
||||
new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem));
|
||||
|
||||
var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync();
|
||||
setting.Value = CacheDirectory;
|
||||
|
||||
setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync();
|
||||
setting.Value = BackupDirectory;
|
||||
|
||||
_context.ServerSetting.Update(setting);
|
||||
|
||||
var lib = new Library()
|
||||
{
|
||||
Name = "Manga", Folders = new List<FolderPath>() {new FolderPath() {Path = "C:/data/"}}
|
||||
};
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007",
|
||||
Libraries = new List<Library>()
|
||||
{
|
||||
lib
|
||||
}
|
||||
});
|
||||
|
||||
return await _context.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
private async Task ResetDb()
|
||||
{
|
||||
_context.Series.RemoveRange(_context.Series.ToList());
|
||||
_context.AppUserRating.RemoveRange(_context.AppUserRating.ToList());
|
||||
_context.Genre.RemoveRange(_context.Genre.ToList());
|
||||
_context.CollectionTag.RemoveRange(_context.CollectionTag.ToList());
|
||||
_context.Person.RemoveRange(_context.Person.ToList());
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
private static MockFileSystem CreateFileSystem()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.Directory.SetCurrentDirectory("C:/kavita/");
|
||||
fileSystem.AddDirectory("C:/kavita/config/");
|
||||
fileSystem.AddDirectory(CacheDirectory);
|
||||
fileSystem.AddDirectory(CoverImageDirectory);
|
||||
fileSystem.AddDirectory(BackupDirectory);
|
||||
fileSystem.AddDirectory(DataDirectory);
|
||||
|
||||
return fileSystem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region RemoveTagsWithoutSeries
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveTagsWithoutSeries_ShouldRemoveTags()
|
||||
{
|
||||
var library = DbFactory.Library("Test", LibraryType.Manga);
|
||||
var series = DbFactory.Series("Test 1");
|
||||
var commonTag = DbFactory.CollectionTag(0, "Tag 1");
|
||||
series.Metadata.CollectionTags.Add(commonTag);
|
||||
series.Metadata.CollectionTags.Add(DbFactory.CollectionTag(0, "Tag 2"));
|
||||
|
||||
var series2 = DbFactory.Series("Test 1");
|
||||
series2.Metadata.CollectionTags.Add(commonTag);
|
||||
library.Series.Add(series);
|
||||
library.Series.Add(series2);
|
||||
_unitOfWork.LibraryRepository.Add(library);
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
Assert.Equal(2, series.Metadata.CollectionTags.Count);
|
||||
Assert.Single(series2.Metadata.CollectionTags);
|
||||
|
||||
// Delete both series
|
||||
_unitOfWork.SeriesRepository.Remove(series);
|
||||
_unitOfWork.SeriesRepository.Remove(series2);
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
// Validate that both tags exist
|
||||
Assert.Equal(2, (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).Count());
|
||||
|
||||
await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries();
|
||||
|
||||
Assert.Empty(await _unitOfWork.CollectionTagRepository.GetAllTagsAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RemoveTagsWithoutSeries_ShouldNotRemoveTags()
|
||||
{
|
||||
var library = DbFactory.Library("Test", LibraryType.Manga);
|
||||
var series = DbFactory.Series("Test 1");
|
||||
var commonTag = DbFactory.CollectionTag(0, "Tag 1");
|
||||
series.Metadata.CollectionTags.Add(commonTag);
|
||||
series.Metadata.CollectionTags.Add(DbFactory.CollectionTag(0, "Tag 2"));
|
||||
|
||||
var series2 = DbFactory.Series("Test 1");
|
||||
series2.Metadata.CollectionTags.Add(commonTag);
|
||||
library.Series.Add(series);
|
||||
library.Series.Add(series2);
|
||||
_unitOfWork.LibraryRepository.Add(library);
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
Assert.Equal(2, series.Metadata.CollectionTags.Count);
|
||||
Assert.Single(series2.Metadata.CollectionTags);
|
||||
|
||||
await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries();
|
||||
|
||||
// Validate that both tags exist
|
||||
Assert.Equal(2, (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync()).Count());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
@ -40,7 +40,7 @@ public class SeriesRepositoryTests
|
||||
|
||||
var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperProfiles>());
|
||||
var mapper = config.CreateMapper();
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null);
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null!);
|
||||
}
|
||||
|
||||
#region Setup
|
||||
@ -138,11 +138,13 @@ public class SeriesRepositoryTests
|
||||
}
|
||||
|
||||
|
||||
[InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Archive, "The Idaten Deities Know Only Peace")] // Matching on localized name in DB
|
||||
[InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Pdf, null)]
|
||||
// This test case isn't ready to go
|
||||
[InlineData("Heion Sedai no Idaten-tachi", MangaFormat.Archive, "", "The Idaten Deities Know Only Peace")] // Matching on localized name in DB
|
||||
[InlineData("Heion Sedai no Idaten-tachi", MangaFormat.Pdf, "", null)]
|
||||
public async Task GetFullSeriesByAnyName_Should(string seriesName, MangaFormat format, string localizedName, string? expected)
|
||||
{
|
||||
var firstSeries = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1);
|
||||
await ResetDb();
|
||||
await SetupSeriesData();
|
||||
var series =
|
||||
await _unitOfWork.SeriesRepository.GetFullSeriesByAnyName(seriesName, localizedName,
|
||||
1, format);
|
||||
@ -157,6 +159,4 @@ public class SeriesRepositoryTests
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//public async Task
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ using System.IO.Abstractions.TestingHelpers;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using API.Archive;
|
||||
using API.Data.Metadata;
|
||||
using API.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NetVips;
|
||||
|
@ -1,18 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using API.SignalR;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
@ -10,9 +9,12 @@ using API.Data.Repositories;
|
||||
using API.DTOs.Reader;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using AutoMapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -136,27 +138,22 @@ public class BookmarkServiceTests
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
|
||||
_context.Series.Add(new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
@ -194,27 +191,22 @@ public class BookmarkServiceTests
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
|
||||
_context.Series.Add(new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("0")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
_context.Series.Add(series);
|
||||
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
@ -270,28 +262,22 @@ public class BookmarkServiceTests
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
|
||||
_context.Series.Add(new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
@ -342,7 +328,7 @@ public class BookmarkServiceTests
|
||||
|
||||
|
||||
Assert.Equal(2, ds.GetFiles(BookmarkDirectory, searchOption:SearchOption.AllDirectories).Count());
|
||||
Assert.False(ds.FileSystem.FileInfo.FromFileName(Path.Join(BookmarkDirectory, "1/1/1/0001.jpg")).Exists);
|
||||
Assert.False(ds.FileSystem.FileInfo.New(Path.Join(BookmarkDirectory, "1/1/1/0001.jpg")).Exists);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -357,27 +343,23 @@ public class BookmarkServiceTests
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
|
||||
_context.Series.Add(new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
@ -419,28 +401,22 @@ public class BookmarkServiceTests
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
|
||||
_context.Series.Add(new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
@ -483,27 +459,19 @@ public class BookmarkServiceTests
|
||||
|
||||
// Delete all Series to reset state
|
||||
await ResetDB();
|
||||
var series = new Series()
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
@ -528,7 +496,7 @@ public class BookmarkServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(1, AppUserIncludes.Bookmarks);
|
||||
Assert.NotEmpty(user.Bookmarks);
|
||||
Assert.NotEmpty(user!.Bookmarks);
|
||||
|
||||
series.Volumes = new List<Volume>();
|
||||
_unitOfWork.SeriesRepository.Update(series);
|
||||
|
@ -171,6 +171,7 @@ public class CacheServiceTests
|
||||
var c = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
@ -272,6 +273,8 @@ public class CacheServiceTests
|
||||
|
||||
var c = new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
@ -303,6 +306,8 @@ public class CacheServiceTests
|
||||
var c = new Chapter()
|
||||
{
|
||||
Id = 1,
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
};
|
||||
|
||||
@ -340,6 +345,8 @@ public class CacheServiceTests
|
||||
var c = new Chapter()
|
||||
{
|
||||
Id = 1,
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
@ -392,6 +399,8 @@ public class CacheServiceTests
|
||||
var c = new Chapter()
|
||||
{
|
||||
Id = 1,
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
@ -440,6 +449,8 @@ public class CacheServiceTests
|
||||
var c = new Chapter()
|
||||
{
|
||||
Id = 1,
|
||||
Number = "1",
|
||||
Range = "1",
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Linq;
|
||||
@ -8,21 +7,16 @@ using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs.Filtering;
|
||||
using API.DTOs.Settings;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Helpers.Converters;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
@ -149,6 +143,8 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
var v = DbFactory.Volume("1");
|
||||
v.Chapters.Add(new Chapter()
|
||||
{
|
||||
Number = "0",
|
||||
Range = "0",
|
||||
CoverImage = "v01_c01.jpg"
|
||||
});
|
||||
v.CoverImage = "v01_c01.jpg";
|
||||
@ -161,6 +157,8 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
v = DbFactory.Volume("1");
|
||||
v.Chapters.Add(new Chapter()
|
||||
{
|
||||
Number = "0",
|
||||
Range = "0",
|
||||
CoverImage = "v01_c03.jpg"
|
||||
});
|
||||
v.CoverImage = "v01_c03jpg";
|
||||
@ -200,6 +198,7 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
s.Metadata.CollectionTags.Add(new CollectionTag()
|
||||
{
|
||||
Title = "Something",
|
||||
NormalizedTitle = "Something".ToNormalized(),
|
||||
CoverImage = $"{ImageService.GetCollectionTagFormat(1)}.jpg"
|
||||
});
|
||||
s.CoverImage = $"{ImageService.GetSeriesFormat(1)}.jpg";
|
||||
@ -211,6 +210,7 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
s.Metadata.CollectionTags.Add(new CollectionTag()
|
||||
{
|
||||
Title = "Something 2",
|
||||
NormalizedTitle = "Something 2".ToNormalized(),
|
||||
CoverImage = $"{ImageService.GetCollectionTagFormat(2)}.jpg"
|
||||
});
|
||||
s.CoverImage = $"{ImageService.GetSeriesFormat(3)}.jpg";
|
||||
@ -250,14 +250,16 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
new ReadingList()
|
||||
{
|
||||
Title = "Something",
|
||||
NormalizedTitle = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something"),
|
||||
CoverImage = $"{ImageService.GetReadingListFormat(1)}.jpg"
|
||||
NormalizedTitle = "Something".ToNormalized(),
|
||||
CoverImage = $"{ImageService.GetReadingListFormat(1)}.jpg",
|
||||
AgeRating = AgeRating.Unknown
|
||||
},
|
||||
new ReadingList()
|
||||
{
|
||||
Title = "Something 2",
|
||||
NormalizedTitle = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Something 2"),
|
||||
CoverImage = $"{ImageService.GetReadingListFormat(2)}.jpg"
|
||||
NormalizedTitle = "Something 2".ToNormalized(),
|
||||
CoverImage = $"{ImageService.GetReadingListFormat(2)}.jpg",
|
||||
AgeRating = AgeRating.Unknown
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -408,22 +410,25 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
[Fact]
|
||||
public async Task CleanupDbEntries_CleanupAbandonedChapters()
|
||||
{
|
||||
var c = EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1);
|
||||
_context.Series.Add(new Series()
|
||||
var c = new ChapterBuilder("0")
|
||||
.WithPages(1)
|
||||
.Build();
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithNumber(1)
|
||||
.WithChapter(c)
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
c,
|
||||
}),
|
||||
}
|
||||
});
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(series);
|
||||
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
@ -461,25 +466,19 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
{
|
||||
var c = new CollectionTag()
|
||||
{
|
||||
Title = "Test Tag"
|
||||
Title = "Test Tag",
|
||||
NormalizedTitle = "Test Tag".ToNormalized(),
|
||||
};
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadataBuilder().WithCollectionTag(c).Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>(),
|
||||
Metadata = new SeriesMetadata()
|
||||
{
|
||||
CollectionTags = new List<CollectionTag>()
|
||||
{
|
||||
c
|
||||
}
|
||||
}
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
_context.Series.Add(s);
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
@ -511,19 +510,14 @@ public class CleanupServiceTests : AbstractDbTest
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test CleanupWantToRead_ShouldRemoveFullyReadSeries")
|
||||
.WithMetadata(new SeriesMetadataBuilder().WithPublicationStatus(PublicationStatus.Completed).Build())
|
||||
.Build();
|
||||
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test CleanupWantToRead_ShouldRemoveFullyReadSeries",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>(),
|
||||
Metadata = new SeriesMetadata()
|
||||
{
|
||||
PublicationStatus = PublicationStatus.Completed
|
||||
}
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
_context.Series.Add(s);
|
||||
|
||||
|
@ -2,14 +2,13 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs.CollectionTags;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Metadata;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
@ -87,7 +86,7 @@ public class CollectionTagServiceTests : AbstractDbTest
|
||||
{
|
||||
await SeedSeries();
|
||||
var ids = new[] {1, 2};
|
||||
await _service.AddTagToSeries(await _unitOfWork.CollectionTagRepository.GetFullTagAsync(1), ids);
|
||||
await _service.AddTagToSeries(await _unitOfWork.CollectionTagRepository.GetTagAsync(1, CollectionTagIncludes.SeriesMetadata), ids);
|
||||
|
||||
var metadatas = await _unitOfWork.SeriesRepository.GetSeriesMetadataForIdsAsync(ids);
|
||||
Assert.True(metadatas.ElementAt(0).CollectionTags.Any(t => t.Title.Equals("Tag 1")));
|
||||
@ -99,7 +98,7 @@ public class CollectionTagServiceTests : AbstractDbTest
|
||||
{
|
||||
await SeedSeries();
|
||||
var ids = new[] {1, 2};
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetFullTagAsync(2);
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetTagAsync(2, CollectionTagIncludes.SeriesMetadata);
|
||||
await _service.AddTagToSeries(tag, ids);
|
||||
|
||||
await _service.RemoveTagFromSeries(tag, new[] {1});
|
||||
|
@ -5,7 +5,6 @@ using API.DTOs.Device;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums.Device;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
@ -152,7 +152,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory, API.Services.Tasks.Scanner.Parser.Parser.ArchiveFileExtensions).ToList();
|
||||
|
||||
Assert.Equal(10, files.Count());
|
||||
Assert.Equal(10, files.Count);
|
||||
Assert.All(files, s => fileSystem.Path.GetExtension(s).Equals(".zip"));
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory).ToList();
|
||||
|
||||
Assert.Equal(11, files.Count());
|
||||
Assert.Equal(11, files.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -189,7 +189,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory).ToList();
|
||||
|
||||
Assert.Equal(11, files.Count());
|
||||
Assert.Equal(11, files.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -207,7 +207,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory).ToList();
|
||||
|
||||
Assert.Equal(10, files.Count());
|
||||
Assert.Equal(10, files.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -225,7 +225,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory).ToList();
|
||||
|
||||
Assert.Equal(10, files.Count());
|
||||
Assert.Equal(10, files.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -243,7 +243,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
var files = ds.GetFiles(testDirectory).ToList();
|
||||
|
||||
Assert.Equal(10, files.Count());
|
||||
Assert.Equal(10, files.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -325,7 +325,7 @@ public class DirectoryServiceTests
|
||||
ds.CopyFileToDirectory($"{testDirectory}file/data-0.txt", "/manga/output/");
|
||||
Assert.True(fileSystem.FileExists("/manga/output/data-0.txt"));
|
||||
Assert.True(fileSystem.FileExists("/manga/file/data-0.txt"));
|
||||
Assert.True(fileSystem.FileInfo.FromFileName("/manga/file/data-0.txt").Length == fileSystem.FileInfo.FromFileName("/manga/output/data-0.txt").Length);
|
||||
Assert.True(fileSystem.FileInfo.New("/manga/file/data-0.txt").Length == fileSystem.FileInfo.New("/manga/output/data-0.txt").Length);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -353,7 +353,7 @@ public class DirectoryServiceTests
|
||||
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
ds.CopyDirectoryToDirectory($"{testDirectory}empty/", "/manga/output/");
|
||||
Assert.Empty(fileSystem.DirectoryInfo.FromDirectoryName("/manga/output/").GetFiles());
|
||||
Assert.Empty(fileSystem.DirectoryInfo.New("/manga/output/").GetFiles());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -427,7 +427,7 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
ds.ExistOrCreate("c:/manga/output/");
|
||||
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("c:/manga/output/").Exists);
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.New("c:/manga/output/").Exists);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -448,9 +448,9 @@ public class DirectoryServiceTests
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
ds.ClearAndDeleteDirectory($"{testDirectory}");
|
||||
Assert.Empty(ds.GetFiles("/manga/", searchOption: SearchOption.AllDirectories));
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").Exists);
|
||||
Assert.False(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/base").Exists);
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.New("/manga/").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.New("/manga/").Exists);
|
||||
Assert.False(ds.FileSystem.DirectoryInfo.New("/manga/base").Exists);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -470,9 +470,9 @@ public class DirectoryServiceTests
|
||||
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
ds.ClearDirectory($"{testDirectory}file/");
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName("/manga/").Exists);
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").Exists);
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.New($"{testDirectory}file/").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.New("/manga/").Exists);
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.New($"{testDirectory}file/").Exists);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -487,9 +487,9 @@ public class DirectoryServiceTests
|
||||
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
|
||||
ds.ClearDirectory($"{testDirectory}");
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.FromDirectoryName(testDirectory).Exists);
|
||||
Assert.False(ds.FileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}file/").Exists);
|
||||
Assert.Empty(ds.FileSystem.DirectoryInfo.New($"{testDirectory}").GetDirectories());
|
||||
Assert.True(ds.FileSystem.DirectoryInfo.New(testDirectory).Exists);
|
||||
Assert.False(ds.FileSystem.DirectoryInfo.New($"{testDirectory}file/").Exists);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -587,7 +587,7 @@ public class DirectoryServiceTests
|
||||
ds.CopyFilesToDirectory(new []{MockUnixSupport.Path($"{testDirectory}file.zip")}, "/manga/output/");
|
||||
ds.CopyFilesToDirectory(new []{MockUnixSupport.Path($"{testDirectory}file.zip")}, "/manga/output/");
|
||||
var outputFiles = ds.GetFiles("/manga/output/").Select(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath).ToList();
|
||||
Assert.Equal(4, outputFiles.Count()); // we have 2 already there and 2 copies
|
||||
Assert.Equal(4, outputFiles.Count); // we have 2 already there and 2 copies
|
||||
// For some reason, this has C:/ on directory even though everything is emulated (System.IO.Abstractions issue, not changing)
|
||||
// https://github.com/TestableIO/System.IO.Abstractions/issues/831
|
||||
Assert.True(outputFiles.Contains(API.Services.Tasks.Scanner.Parser.Parser.NormalizePath("/manga/output/file (3).zip"))
|
||||
@ -645,10 +645,10 @@ public class DirectoryServiceTests
|
||||
const string testDirectory = "/manga/";
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.AddDirectory($"{testDirectory}dir1");
|
||||
var di = fileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}dir1");
|
||||
var di = fileSystem.DirectoryInfo.New($"{testDirectory}dir1");
|
||||
di.Attributes |= FileAttributes.System;
|
||||
fileSystem.AddDirectory($"{testDirectory}dir2");
|
||||
di = fileSystem.DirectoryInfo.FromDirectoryName($"{testDirectory}dir2");
|
||||
di = fileSystem.DirectoryInfo.New($"{testDirectory}dir2");
|
||||
di.Attributes |= FileAttributes.Hidden;
|
||||
fileSystem.AddDirectory($"{testDirectory}dir3");
|
||||
fileSystem.AddFile($"{testDirectory}file_0.zip", new MockFileData(""));
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
@ -9,15 +8,13 @@ using API.Data;
|
||||
using API.Data.Metadata;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Parser;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using API.Services.Tasks.Scanner.Parser;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers;
|
||||
using AutoMapper;
|
||||
using DotNet.Globbing;
|
||||
using Flurl.Util;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
@ -254,7 +251,7 @@ public class ParseScannedFilesTests
|
||||
var foundParsedSeries = new ParsedSeries()
|
||||
{
|
||||
Name = parsedFiles.First().Series,
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize(parsedFiles.First().Series),
|
||||
NormalizedName = parsedFiles.First().Series.ToNormalized(),
|
||||
Format = parsedFiles.First().Format
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,10 +11,12 @@ using API.DTOs.ReadingLists;
|
||||
using API.DTOs.ReadingLists.CBL;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using AutoMapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -44,7 +46,7 @@ public class ReadingListServiceTests
|
||||
|
||||
var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperProfiles>());
|
||||
var mapper = config.CreateMapper();
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null);
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null!);
|
||||
|
||||
_readingListService = new ReadingListService(_unitOfWork, Substitute.For<ILogger<ReadingListService>>(), Substitute.For<IEventHub>());
|
||||
}
|
||||
@ -124,36 +126,26 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone,
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "3",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("3")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build(),
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -162,8 +154,8 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
var readingList = DbFactory.ReadingList("test");
|
||||
user!.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
};
|
||||
@ -191,36 +183,26 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone,
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "3",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("3")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build()
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -229,8 +211,8 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
var readingList = DbFactory.ReadingList("test");
|
||||
user!.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
};
|
||||
@ -265,36 +247,26 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone,
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "3",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("3")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build()
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -303,7 +275,7 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
var readingList = DbFactory.ReadingList("Test");
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
@ -341,36 +313,26 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone,
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "3",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("3")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build()
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -379,8 +341,8 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
var readingList = DbFactory.ReadingList("test");
|
||||
user!.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
};
|
||||
@ -436,31 +398,22 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build(),
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -469,7 +422,7 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
var readingList = DbFactory.ReadingList("Test");
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
@ -508,39 +461,26 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
AgeRating = AgeRating.Everyone,
|
||||
Pages = 1
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
AgeRating = AgeRating.X18Plus,
|
||||
Pages = 1
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "3",
|
||||
AgeRating = AgeRating.X18Plus,
|
||||
Pages = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.WithAgeRating(AgeRating.Everyone)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("3")
|
||||
.WithAgeRating(AgeRating.X18Plus)
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build()
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -549,7 +489,7 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists | AppUserIncludes.Progress);
|
||||
var readingList = new ReadingList();
|
||||
var readingList = DbFactory.ReadingList("Test");
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
@ -594,29 +534,20 @@ public class ReadingListServiceTests
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build()
|
||||
}
|
||||
},
|
||||
}
|
||||
@ -625,8 +556,8 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
var readingList = DbFactory.ReadingList("Test");
|
||||
user!.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
};
|
||||
@ -645,29 +576,20 @@ public class ReadingListServiceTests
|
||||
public async Task CalculateAgeRating_ShouldUpdateToMax()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>()),
|
||||
Volumes = new List<Volume>()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(DbFactory.SeriesMetadata(new List<CollectionTag>()))
|
||||
.WithVolumes(new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Name = "0",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Number = "1",
|
||||
},
|
||||
new Chapter()
|
||||
{
|
||||
Number = "2",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1")
|
||||
.Build()
|
||||
)
|
||||
.WithChapter(new ChapterBuilder("2")
|
||||
.Build()
|
||||
)
|
||||
.Build()
|
||||
})
|
||||
.Build();
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "majora2007",
|
||||
@ -691,7 +613,7 @@ public class ReadingListServiceTests
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists);
|
||||
var readingList = new ReadingList();
|
||||
var readingList = DbFactory.ReadingList("Test");
|
||||
user.ReadingLists = new List<ReadingList>()
|
||||
{
|
||||
readingList
|
||||
@ -1108,33 +1030,53 @@ public class ReadingListServiceTests
|
||||
var cblReadingList = LoadCblFromPath("Fables.cbl");
|
||||
|
||||
// Mock up our series
|
||||
var fablesSeries = DbFactory.Series("Fables");
|
||||
var fables2Series = DbFactory.Series("Fables: The Last Castle");
|
||||
// var fablesSeries = DbFactory.Series("Fables");
|
||||
// var fables2Series = DbFactory.Series("Fables: The Last Castle");
|
||||
|
||||
fablesSeries.Volumes.Add(new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "2002",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false),
|
||||
EntityFactory.CreateChapter("2", false),
|
||||
EntityFactory.CreateChapter("3", false),
|
||||
var fablesSeries = new SeriesBuilder("Fables")
|
||||
.WithVolume(new VolumeBuilder("2002")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1").Build())
|
||||
.WithChapter(new ChapterBuilder("2").Build())
|
||||
.WithChapter(new ChapterBuilder("3").Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
}
|
||||
});
|
||||
fables2Series.Volumes.Add(new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "2003",
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false),
|
||||
EntityFactory.CreateChapter("2", false),
|
||||
EntityFactory.CreateChapter("3", false),
|
||||
var fables2Series = new SeriesBuilder("Fables: The Last Castle")
|
||||
.WithVolume(new VolumeBuilder("2003")
|
||||
.WithNumber(1)
|
||||
.WithChapter(new ChapterBuilder("1").Build())
|
||||
.WithChapter(new ChapterBuilder("2").Build())
|
||||
.WithChapter(new ChapterBuilder("3").Build())
|
||||
.Build())
|
||||
.Build();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// fablesSeries.Volumes.Add(new Volume()
|
||||
// {
|
||||
// Number = 1,
|
||||
// Name = "2002",
|
||||
// Chapters = new List<Chapter>()
|
||||
// {
|
||||
// EntityFactory.CreateChapter("1", false),
|
||||
// EntityFactory.CreateChapter("2", false),
|
||||
// EntityFactory.CreateChapter("3", false),
|
||||
//
|
||||
// }
|
||||
// });
|
||||
// fables2Series.Volumes.Add(new Volume()
|
||||
// {
|
||||
// Number = 1,
|
||||
// Name = "2003",
|
||||
// Chapters = new List<Chapter>()
|
||||
// {
|
||||
// EntityFactory.CreateChapter("1", false),
|
||||
// EntityFactory.CreateChapter("2", false),
|
||||
// EntityFactory.CreateChapter("3", false),
|
||||
//
|
||||
// }
|
||||
// });
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
|
@ -3,10 +3,12 @@ using System.Linq;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Parser;
|
||||
using API.Services.Tasks;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using API.Tests.Helpers;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Xunit;
|
||||
|
||||
namespace API.Tests.Services;
|
||||
@ -23,23 +25,14 @@ public class ScannerServiceTests
|
||||
|
||||
var existingSeries = new List<Series>
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Darker Than Black",
|
||||
LocalizedName = "Darker Than Black",
|
||||
OriginalName = "Darker Than Black",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
{
|
||||
Number = 1,
|
||||
Name = "1"
|
||||
}
|
||||
},
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker Than Black"),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Format = MangaFormat.Epub
|
||||
}
|
||||
new SeriesBuilder("Darker Than Black")
|
||||
.WithFormat(MangaFormat.Epub)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithName("1")
|
||||
.Build())
|
||||
.WithLocalizedName("Darker Than Black")
|
||||
.Build()
|
||||
};
|
||||
|
||||
Assert.Equal(1, ScannerService.FindSeriesNotOnDisk(existingSeries, infos).Count());
|
||||
@ -56,76 +49,42 @@ public class ScannerServiceTests
|
||||
|
||||
var existingSeries = new List<Series>
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Cage of Eden",
|
||||
LocalizedName = "Cage of Eden",
|
||||
OriginalName = "Cage of Eden",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Cage of Eden"),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Format = MangaFormat.Archive
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Darker Than Black",
|
||||
LocalizedName = "Darker Than Black",
|
||||
OriginalName = "Darker Than Black",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Darker Than Black"),
|
||||
Metadata = new SeriesMetadata(),
|
||||
Format = MangaFormat.Archive
|
||||
}
|
||||
new SeriesBuilder("Cage of Eden")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithName("1")
|
||||
.Build())
|
||||
.WithLocalizedName("Darker Than Black")
|
||||
.Build(),
|
||||
new SeriesBuilder("Darker Than Black")
|
||||
.WithFormat(MangaFormat.Archive)
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithName("1")
|
||||
.Build())
|
||||
.WithLocalizedName("Darker Than Black")
|
||||
.Build(),
|
||||
// new Series()
|
||||
// {
|
||||
// Name = "Cage of Eden",
|
||||
// LocalizedName = "Cage of Eden",
|
||||
// OriginalName = "Cage of Eden",
|
||||
// NormalizedName = "Darker Than Black".ToNormalized(),
|
||||
// Metadata = new SeriesMetadata(),
|
||||
// Format = MangaFormat.Archive
|
||||
// },
|
||||
// new Series()
|
||||
// {
|
||||
// Name = "Darker Than Black",
|
||||
// LocalizedName = "Darker Than Black",
|
||||
// OriginalName = "Darker Than Black",
|
||||
// NormalizedName = "Darker Than Black".ToNormalized(),
|
||||
// Metadata = new SeriesMetadata(),
|
||||
// Format = MangaFormat.Archive
|
||||
// }
|
||||
};
|
||||
|
||||
|
||||
|
||||
Assert.Empty(ScannerService.FindSeriesNotOnDisk(existingSeries, infos));
|
||||
}
|
||||
|
||||
|
||||
// TODO: Figure out how to do this with ParseScannedFiles
|
||||
// [Theory]
|
||||
// [InlineData(new [] {"Darker than Black"}, "Darker than Black", "Darker than Black")]
|
||||
// [InlineData(new [] {"Darker than Black"}, "Darker Than Black", "Darker than Black")]
|
||||
// [InlineData(new [] {"Darker than Black"}, "Darker Than Black!", "Darker than Black")]
|
||||
// [InlineData(new [] {""}, "Runaway Jack", "Runaway Jack")]
|
||||
// public void MergeNameTest(string[] existingSeriesNames, string parsedInfoName, string expected)
|
||||
// {
|
||||
// var collectedSeries = new ConcurrentDictionary<ParsedSeries, List<ParserInfo>>();
|
||||
// foreach (var seriesName in existingSeriesNames)
|
||||
// {
|
||||
// AddToParsedInfo(collectedSeries, new ParserInfo() {Series = seriesName, Format = MangaFormat.Archive});
|
||||
// }
|
||||
//
|
||||
// var actualName = new ParseScannedFiles(_bookService, _logger).MergeName(collectedSeries, new ParserInfo()
|
||||
// {
|
||||
// Series = parsedInfoName,
|
||||
// Format = MangaFormat.Archive
|
||||
// });
|
||||
//
|
||||
// Assert.Equal(expected, actualName);
|
||||
// }
|
||||
|
||||
// [Fact]
|
||||
// public void RemoveMissingSeries_Should_RemoveSeries()
|
||||
// {
|
||||
// var existingSeries = new List<Series>()
|
||||
// {
|
||||
// EntityFactory.CreateSeries("Darker than Black Vol 1"),
|
||||
// EntityFactory.CreateSeries("Darker than Black"),
|
||||
// EntityFactory.CreateSeries("Beastars"),
|
||||
// };
|
||||
// var missingSeries = new List<Series>()
|
||||
// {
|
||||
// EntityFactory.CreateSeries("Darker than Black Vol 1"),
|
||||
// };
|
||||
// existingSeries = ScannerService.RemoveMissingSeries(existingSeries, missingSeries, out var removeCount).ToList();
|
||||
//
|
||||
// Assert.DoesNotContain(missingSeries[0].Name, existingSeries.Select(s => s.Name));
|
||||
// Assert.Equal(missingSeries.Count, removeCount);
|
||||
// }
|
||||
|
||||
|
||||
// TODO: I want a test for UpdateSeries where if I have chapter 10 and now it's mapping into Vol 2 Chapter 10,
|
||||
// if I can do it without deleting the underlying chapter (aka id change)
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
@ -14,14 +12,10 @@ using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using API.Tests.Helpers;
|
||||
using AutoMapper;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using API.Tests.Helpers.Builders;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
@ -93,28 +87,22 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("Omake", true, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("Something SP02", true, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("22", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("Omake").WithIsSpecial(true).WithTitle("Omake").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("Something SP02").WithIsSpecial(true).WithTitle("Something").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -147,28 +135,22 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("22", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("2").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -201,26 +183,20 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("2").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -253,26 +229,20 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>()),
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("2").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -308,21 +278,16 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -354,21 +319,15 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("Ano Orokamono ni mo Kyakkou wo! - Volume 1.epub", true, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("Ano Orokamono ni mo Kyakkou wo! - Volume 2.epub", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("Ano Orokamono ni mo Kyakkou wo! - Volume 1.epub", "Ano Orokamono ni mo Kyakkou wo! - Volume 1.epub").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("Ano Orokamono ni mo Kyakkou wo! - Volume 2.epub", "Ano Orokamono ni mo Kyakkou wo! - Volume 2.epub").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -407,25 +366,19 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1.2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>()),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("1.2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -462,17 +415,12 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -516,17 +464,12 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -587,17 +530,12 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -639,17 +577,12 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Manga,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
}
|
||||
}
|
||||
new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -678,14 +611,16 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldCreateEmptyMetadata_IfDoesntExist()
|
||||
{
|
||||
await ResetDb();
|
||||
_context.Series.Add(new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
}
|
||||
});
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
|
||||
_context.Series.Add(s);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var success = await _seriesService.UpdateSeriesMetadata(new UpdateSeriesMetadataDto()
|
||||
@ -710,14 +645,16 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldCreateNewTags_IfNoneExist()
|
||||
{
|
||||
await ResetDb();
|
||||
_context.Series.Add(new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library() {
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
}
|
||||
});
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
|
||||
_context.Series.Add(s);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var success = await _seriesService.UpdateSeriesMetadata(new UpdateSeriesMetadataDto()
|
||||
@ -752,16 +689,15 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldRemoveExistingTags()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
|
||||
var g = DbFactory.Genre("Existing Genre");
|
||||
s.Metadata.Genres = new List<Genre>() {g};
|
||||
_context.Series.Add(s);
|
||||
@ -791,16 +727,15 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldAddNewPerson_NoExistingPeople()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
|
||||
var g = DbFactory.Person("Existing Person", PersonRole.Publisher);
|
||||
_context.Series.Add(s);
|
||||
|
||||
@ -829,15 +764,13 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldAddNewPerson_ExistingPeople()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
var g = DbFactory.Person("Existing Person", PersonRole.Publisher);
|
||||
s.Metadata.People = new List<Person>() {DbFactory.Person("Existing Writer", PersonRole.Writer),
|
||||
@ -871,15 +804,13 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldRemoveExistingPerson()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
var g = DbFactory.Person("Existing Person", PersonRole.Publisher);
|
||||
_context.Series.Add(s);
|
||||
@ -908,15 +839,13 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldLockIfTold()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
var g = DbFactory.Genre("Existing Genre");
|
||||
s.Metadata.Genres = new List<Genre>() {g};
|
||||
@ -949,15 +878,13 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
public async Task UpdateSeriesMetadata_ShouldNotUpdateReleaseYear_IfLessThan1000()
|
||||
{
|
||||
await ResetDb();
|
||||
var s = new Series()
|
||||
var s = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadataBuilder().Build())
|
||||
.Build();
|
||||
s.Library = new Library()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
},
|
||||
Metadata = DbFactory.SeriesMetadata(new List<CollectionTag>())
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Book,
|
||||
};
|
||||
_context.Series.Add(s);
|
||||
await _context.SaveChangesAsync();
|
||||
@ -986,43 +913,37 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
|
||||
private static Series CreateSeriesMock()
|
||||
{
|
||||
var files = new List<MangaFile>()
|
||||
var file = EntityFactory.CreateMangaFile("Test.cbz", MangaFormat.Archive, 1);
|
||||
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithMetadata(new SeriesMetadata())
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).WithFile(file).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).WithFile(file).Build())
|
||||
.WithChapter(new ChapterBuilder("A Special Case").WithIsSpecial(true).WithFile(file).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).WithFile(file).Build())
|
||||
.WithChapter(new ChapterBuilder("2").WithPages(1).WithFile(file).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).WithFile(file).Build())
|
||||
.WithChapter(new ChapterBuilder("22").WithPages(1).WithFile(file).Build())
|
||||
.Build())
|
||||
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).WithFile(file).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).WithFile(file).Build())
|
||||
.Build())
|
||||
.Build();
|
||||
series.Library = new Library()
|
||||
{
|
||||
EntityFactory.CreateMangaFile("Test.cbz", MangaFormat.Archive, 1)
|
||||
};
|
||||
return new Series()
|
||||
{
|
||||
Name = "Test",
|
||||
Library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
},
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, files, 1),
|
||||
EntityFactory.CreateChapter("96", false, files, 1),
|
||||
EntityFactory.CreateChapter("A Special Case", true, files, 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, files, 1),
|
||||
EntityFactory.CreateChapter("2", false, files, 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, files, 1),
|
||||
EntityFactory.CreateChapter("22", false, files, 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, files, 1),
|
||||
EntityFactory.CreateChapter("32", false, files, 1),
|
||||
}),
|
||||
}
|
||||
Name = "Test LIb",
|
||||
Type = LibraryType.Manga,
|
||||
};
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@ -1082,21 +1003,9 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
}
|
||||
new SeriesBuilder("Test Series").Build(),
|
||||
new SeriesBuilder("Test Series Prequels").Build(),
|
||||
new SeriesBuilder("Test Series Sequels").Build(),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1129,21 +1038,9 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
}
|
||||
DbFactory.Series("Test Series"),
|
||||
DbFactory.Series("Test Series Prequels"),
|
||||
DbFactory.Series("Test Series Sequels"),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1183,16 +1080,8 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Series A",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Series B",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
DbFactory.Series("Series A"),
|
||||
DbFactory.Series("Series B"),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1236,16 +1125,8 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Series A",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Series B",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
DbFactory.Series("Series A"),
|
||||
DbFactory.Series("Series B"),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1289,16 +1170,8 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
}
|
||||
DbFactory.Series("Test Series"),
|
||||
DbFactory.Series("Test Series Prequels"),
|
||||
}
|
||||
});
|
||||
|
||||
@ -1342,31 +1215,11 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Editions",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels",
|
||||
Volumes = new List<Volume>(){}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Adaption",
|
||||
Volumes = new List<Volume>(){}
|
||||
}
|
||||
DbFactory.Series("Test Series"),
|
||||
DbFactory.Series("Test Series Editions"),
|
||||
DbFactory.Series("Test Series Prequels"),
|
||||
DbFactory.Series("Test Series Sequels"),
|
||||
DbFactory.Series("Test Series Adaption"),
|
||||
}
|
||||
});
|
||||
await _context.SaveChangesAsync();
|
||||
@ -1403,21 +1256,9 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>() { }
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>() { }
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels",
|
||||
Volumes = new List<Volume>() { }
|
||||
}
|
||||
DbFactory.Series("Test Series"),
|
||||
DbFactory.Series("Test Series Prequels"),
|
||||
DbFactory.Series("Test Series Sequels"),
|
||||
}
|
||||
};
|
||||
_context.Library.Add(lib);
|
||||
@ -1463,40 +1304,17 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
new Volume()
|
||||
new SeriesBuilder("Test Series")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("1").WithFile(new MangaFile()
|
||||
{
|
||||
Chapters = new List<Chapter>()
|
||||
{
|
||||
new Chapter()
|
||||
{
|
||||
Files = new List<MangaFile>()
|
||||
{
|
||||
new MangaFile()
|
||||
{
|
||||
Pages = 1,
|
||||
FilePath = "fake file"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels",
|
||||
Volumes = new List<Volume>() { }
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels",
|
||||
Volumes = new List<Volume>() { }
|
||||
}
|
||||
Pages = 1,
|
||||
FilePath = "fake file"
|
||||
}).Build())
|
||||
.Build())
|
||||
.Build(),
|
||||
new SeriesBuilder("Test Series Prequels").Build(),
|
||||
new SeriesBuilder("Test Series Sequels").Build(),
|
||||
}
|
||||
};
|
||||
_context.Library.Add(lib1);
|
||||
@ -1513,21 +1331,9 @@ public class SeriesServiceTests : AbstractDbTest
|
||||
Type = LibraryType.Book,
|
||||
Series = new List<Series>()
|
||||
{
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series 2",
|
||||
Volumes = new List<Volume>() { }
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Prequels 2",
|
||||
Volumes = new List<Volume>() { }
|
||||
},
|
||||
new Series()
|
||||
{
|
||||
Name = "Test Series Sequels 2",
|
||||
Volumes = new List<Volume>() { }
|
||||
}
|
||||
DbFactory.Series("Test Series 2"),
|
||||
DbFactory.Series("Test Series Prequels 2"),
|
||||
DbFactory.Series("Test Series Prequels 2"),
|
||||
}
|
||||
};
|
||||
_context.Library.Add(lib2);
|
||||
|
@ -1,138 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Enums.Theme;
|
||||
using API.Entities.Enums.UserPreferences;
|
||||
using API.Helpers;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using API.SignalR;
|
||||
using AutoMapper;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace API.Tests.Services;
|
||||
|
||||
public class SiteThemeServiceTests
|
||||
|
||||
public abstract class SiteThemeServiceTest : AbstractDbTest
|
||||
{
|
||||
private readonly ILogger<ThemeService> _logger = Substitute.For<ILogger<ThemeService>>();
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
private readonly IEventHub _messageHub = Substitute.For<IEventHub>();
|
||||
|
||||
private readonly DbConnection _connection;
|
||||
private readonly DataContext _context;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
|
||||
private const string CacheDirectory = "C:/kavita/config/cache/";
|
||||
private const string CoverImageDirectory = "C:/kavita/config/covers/";
|
||||
private const string BackupDirectory = "C:/kavita/config/backups/";
|
||||
private const string BookmarkDirectory = "C:/kavita/config/bookmarks/";
|
||||
private const string SiteThemeDirectory = "C:/kavita/config/themes/";
|
||||
|
||||
public SiteThemeServiceTests()
|
||||
protected SiteThemeServiceTest(ITestOutputHelper testOutputHelper) : base()
|
||||
{
|
||||
var contextOptions = new DbContextOptionsBuilder()
|
||||
.UseSqlite(CreateInMemoryDatabase())
|
||||
.Options;
|
||||
_connection = RelationalOptionsExtension.Extract(contextOptions).Connection;
|
||||
|
||||
_context = new DataContext(contextOptions);
|
||||
Task.Run(SeedDb).GetAwaiter().GetResult();
|
||||
|
||||
var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperProfiles>());
|
||||
var mapper = config.CreateMapper();
|
||||
_unitOfWork = new UnitOfWork(_context, mapper, null);
|
||||
_testOutputHelper = testOutputHelper;
|
||||
}
|
||||
|
||||
#region Setup
|
||||
|
||||
private static DbConnection CreateInMemoryDatabase()
|
||||
{
|
||||
var connection = new SqliteConnection("Filename=:memory:");
|
||||
|
||||
connection.Open();
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private async Task<bool> SeedDb()
|
||||
{
|
||||
await _context.Database.MigrateAsync();
|
||||
var filesystem = CreateFileSystem();
|
||||
|
||||
await Seed.SeedSettings(_context, new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem));
|
||||
|
||||
var setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.CacheDirectory).SingleAsync();
|
||||
setting.Value = CacheDirectory;
|
||||
|
||||
setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BackupDirectory).SingleAsync();
|
||||
setting.Value = BackupDirectory;
|
||||
|
||||
setting = await _context.ServerSetting.Where(s => s.Key == ServerSettingKey.BookmarkDirectory).SingleAsync();
|
||||
setting.Value = BookmarkDirectory;
|
||||
|
||||
_context.ServerSetting.Update(setting);
|
||||
|
||||
_context.AppUser.Add(new AppUser()
|
||||
{
|
||||
UserName = "Joe",
|
||||
UserPreferences = new AppUserPreferences
|
||||
{
|
||||
Theme = Seed.DefaultThemes[0]
|
||||
}
|
||||
});
|
||||
|
||||
_context.Library.Add(new Library()
|
||||
{
|
||||
Name = "Manga",
|
||||
Folders = new List<FolderPath>()
|
||||
{
|
||||
new FolderPath()
|
||||
{
|
||||
Path = "C:/data/"
|
||||
}
|
||||
}
|
||||
});
|
||||
return await _context.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
private static MockFileSystem CreateFileSystem()
|
||||
{
|
||||
var fileSystem = new MockFileSystem();
|
||||
fileSystem.Directory.SetCurrentDirectory("C:/kavita/");
|
||||
fileSystem.AddDirectory("C:/kavita/config/");
|
||||
fileSystem.AddDirectory(CacheDirectory);
|
||||
fileSystem.AddDirectory(CoverImageDirectory);
|
||||
fileSystem.AddDirectory(BackupDirectory);
|
||||
fileSystem.AddDirectory(BookmarkDirectory);
|
||||
fileSystem.AddDirectory(SiteThemeDirectory);
|
||||
fileSystem.AddDirectory("C:/data/");
|
||||
|
||||
return fileSystem;
|
||||
}
|
||||
|
||||
private async Task ResetDb()
|
||||
protected override async Task ResetDb()
|
||||
{
|
||||
_context.SiteTheme.RemoveRange(_context.SiteTheme);
|
||||
await _context.SaveChangesAsync();
|
||||
// Recreate defaults
|
||||
await Seed.SeedThemes(_context);
|
||||
}
|
||||
|
||||
#endregion
|
||||
[Fact]
|
||||
public async Task UpdateDefault_ShouldThrowOnInvalidId()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine($"[UpdateDefault_ShouldThrowOnInvalidId] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData("123"));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
var siteThemeService = new ThemeService(ds, _unitOfWork, _messageHub);
|
||||
|
||||
_context.SiteTheme.Add(new SiteTheme()
|
||||
{
|
||||
Name = "Custom",
|
||||
NormalizedName = "Custom".ToNormalized(),
|
||||
Provider = ThemeProvider.User,
|
||||
FileName = "custom.css",
|
||||
IsDefault = false
|
||||
});
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var ex = await Assert.ThrowsAsync<KavitaException>(async () => await siteThemeService.UpdateDefault(10));
|
||||
Assert.Equal("Theme file missing or invalid", ex.Message);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Scan_ShouldFindCustomFile()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine($"[Scan_ShouldOnlyInsertOnceOnSecondScan] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData(""));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
@ -146,6 +79,8 @@ public class SiteThemeServiceTests
|
||||
public async Task Scan_ShouldOnlyInsertOnceOnSecondScan()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine(
|
||||
$"[Scan_ShouldOnlyInsertOnceOnSecondScan] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData(""));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
@ -157,7 +92,8 @@ public class SiteThemeServiceTests
|
||||
await siteThemeService.Scan();
|
||||
|
||||
var customThemes = (await _unitOfWork.SiteThemeRepository.GetThemeDtos()).Where(t =>
|
||||
API.Services.Tasks.Scanner.Parser.Parser.Normalize(t.Name).Equals(API.Services.Tasks.Scanner.Parser.Parser.Normalize("custom")));
|
||||
t.Name.ToNormalized().Equals("custom".ToNormalized()));
|
||||
|
||||
Assert.Single(customThemes);
|
||||
}
|
||||
|
||||
@ -165,6 +101,7 @@ public class SiteThemeServiceTests
|
||||
public async Task Scan_ShouldDeleteWhenFileDoesntExistOnSecondScan()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine($"[Scan_ShouldDeleteWhenFileDoesntExistOnSecondScan] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData(""));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
@ -176,16 +113,17 @@ public class SiteThemeServiceTests
|
||||
filesystem.RemoveFile($"{SiteThemeDirectory}custom.css");
|
||||
await siteThemeService.Scan();
|
||||
|
||||
var customThemes = (await _unitOfWork.SiteThemeRepository.GetThemeDtos()).Where(t =>
|
||||
API.Services.Tasks.Scanner.Parser.Parser.Normalize(t.Name).Equals(API.Services.Tasks.Scanner.Parser.Parser.Normalize("custom")));
|
||||
var themes = (await _unitOfWork.SiteThemeRepository.GetThemeDtos());
|
||||
|
||||
Assert.Empty(customThemes);
|
||||
Assert.Equal(0, themes.Count(t =>
|
||||
t.Name.ToNormalized().Equals("custom".ToNormalized())));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetContent_ShouldReturnContent()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine($"[GetContent_ShouldReturnContent] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData("123"));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
@ -194,7 +132,7 @@ public class SiteThemeServiceTests
|
||||
_context.SiteTheme.Add(new SiteTheme()
|
||||
{
|
||||
Name = "Custom",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Custom"),
|
||||
NormalizedName = "Custom".ToNormalized(),
|
||||
Provider = ThemeProvider.User,
|
||||
FileName = "custom.css",
|
||||
IsDefault = false
|
||||
@ -211,6 +149,7 @@ public class SiteThemeServiceTests
|
||||
public async Task UpdateDefault_ShouldHaveOneDefault()
|
||||
{
|
||||
await ResetDb();
|
||||
_testOutputHelper.WriteLine($"[UpdateDefault_ShouldHaveOneDefault] All Themes: {(await _unitOfWork.SiteThemeRepository.GetThemes()).Count(t => t.IsDefault)}");
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData("123"));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
@ -219,7 +158,7 @@ public class SiteThemeServiceTests
|
||||
_context.SiteTheme.Add(new SiteTheme()
|
||||
{
|
||||
Name = "Custom",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Custom"),
|
||||
NormalizedName = "Custom".ToNormalized(),
|
||||
Provider = ThemeProvider.User,
|
||||
FileName = "custom.css",
|
||||
IsDefault = false
|
||||
@ -228,6 +167,7 @@ public class SiteThemeServiceTests
|
||||
|
||||
var customTheme = (await _unitOfWork.SiteThemeRepository.GetThemeDtoByName("Custom"));
|
||||
|
||||
Assert.NotNull(customTheme);
|
||||
await siteThemeService.UpdateDefault(customTheme.Id);
|
||||
|
||||
|
||||
@ -235,31 +175,5 @@ public class SiteThemeServiceTests
|
||||
Assert.Equal(customTheme.Id, (await _unitOfWork.SiteThemeRepository.GetDefaultTheme()).Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateDefault_ShouldThrowOnInvalidId()
|
||||
{
|
||||
await ResetDb();
|
||||
var filesystem = CreateFileSystem();
|
||||
filesystem.AddFile($"{SiteThemeDirectory}custom.css", new MockFileData("123"));
|
||||
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), filesystem);
|
||||
var siteThemeService = new ThemeService(ds, _unitOfWork, _messageHub);
|
||||
|
||||
_context.SiteTheme.Add(new SiteTheme()
|
||||
{
|
||||
Name = "Custom",
|
||||
NormalizedName = API.Services.Tasks.Scanner.Parser.Parser.Normalize("Custom"),
|
||||
Provider = ThemeProvider.User,
|
||||
FileName = "custom.css",
|
||||
IsDefault = false
|
||||
});
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
|
||||
|
||||
var ex = await Assert.ThrowsAsync<KavitaException>(async () => await siteThemeService.UpdateDefault(10));
|
||||
Assert.Equal("Theme file missing or invalid", ex.Message);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
namespace API.Tests.Services;
|
||||
using API.Extensions;
|
||||
using API.Tests.Helpers.Builders;
|
||||
|
||||
namespace API.Tests.Services;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
@ -111,33 +114,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("4", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("3").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("4").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -169,33 +164,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("4", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("3").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("4").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -233,33 +220,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("23", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("22").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -296,33 +275,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("23", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("22").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -360,26 +331,19 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 199),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 192),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("0", false, new List<MangaFile>(), 255),
|
||||
}),
|
||||
},
|
||||
Pages = 646
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(199).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(192).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("0").WithPages(255).Build())
|
||||
.Build())
|
||||
.WithPages(646)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -418,31 +382,23 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1997", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2002", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("2", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2005", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1997")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2002")
|
||||
.WithChapter(new ChapterBuilder("2").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2005")
|
||||
.WithChapter(new ChapterBuilder("3").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -485,33 +441,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("4", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("3").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("4").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -542,33 +490,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("3", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("4", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("3").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("4").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -606,33 +546,25 @@ public class TachiyomiServiceTests
|
||||
{
|
||||
await ResetDb();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("23", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("23").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
@ -668,34 +600,25 @@ public class TachiyomiServiceTests
|
||||
public async Task MarkChaptersUntilAsRead_ShouldReturnEncodedVolume_Progress()
|
||||
{
|
||||
await ResetDb();
|
||||
var series = new SeriesBuilder("Test")
|
||||
.WithVolume(new VolumeBuilder("0")
|
||||
.WithChapter(new ChapterBuilder("95").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("96").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("1")
|
||||
.WithChapter(new ChapterBuilder("1").WithIsSpecial(true).WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("2")
|
||||
.WithChapter(new ChapterBuilder("21").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("23").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithVolume(new VolumeBuilder("3")
|
||||
.WithChapter(new ChapterBuilder("31").WithPages(1).Build())
|
||||
.WithChapter(new ChapterBuilder("32").WithPages(1).Build())
|
||||
.Build())
|
||||
.WithPages(7)
|
||||
.Build();
|
||||
|
||||
var series = new Series
|
||||
{
|
||||
Name = "Test",
|
||||
Volumes = new List<Volume>()
|
||||
{
|
||||
EntityFactory.CreateVolume("0", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("95", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("96", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("1", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("1", true, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("2", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("21", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("23", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
EntityFactory.CreateVolume("3", new List<Chapter>()
|
||||
{
|
||||
EntityFactory.CreateChapter("31", false, new List<MangaFile>(), 1),
|
||||
EntityFactory.CreateChapter("32", false, new List<MangaFile>(), 1),
|
||||
}),
|
||||
},
|
||||
Pages = 7
|
||||
};
|
||||
var library = new Library()
|
||||
{
|
||||
Name = "Test LIb",
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 143 KiB |
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Entities;
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<AnalysisMode>Default</AnalysisMode>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<TieredPGO>true</TieredPGO>
|
||||
<TieredCompilation>true</TieredCompilation>
|
||||
<ApplicationIcon>../favicon.ico</ApplicationIcon>
|
||||
<Nullable>warnings</Nullable>
|
||||
<LangVersion>latestmajor</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="PostBuild" AfterTargets="Build" Condition=" '$(Configuration)' == 'Debug' ">
|
||||
@ -55,32 +57,32 @@
|
||||
<PackageReference Include="CsvHelper" Version="30.0.1" />
|
||||
<PackageReference Include="Docnet.Core" Version="2.4.0-alpha.4" />
|
||||
<PackageReference Include="ExCSS" Version="4.1.0" />
|
||||
<PackageReference Include="Flurl" Version="3.0.6" />
|
||||
<PackageReference Include="Flurl" Version="3.0.7" />
|
||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.31" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.31" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="0.3.4" />
|
||||
<PackageReference Include="Hangfire" Version="1.7.33" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.33" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="0.3.6" />
|
||||
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
|
||||
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
|
||||
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.3.2" />
|
||||
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.3.3" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.10">
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.1" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="NetVips" Version="2.2.0" />
|
||||
<PackageReference Include="NetVips.Native" Version="8.13.1" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.5" />
|
||||
<PackageReference Include="NetVips.Native" Version="8.13.2" />
|
||||
<PackageReference Include="NReco.Logging.File" Version="1.1.6" />
|
||||
<PackageReference Include="Serilog" Version="2.12.0" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="6.1.0" />
|
||||
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.2.0-dev-00752" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="5.0.1" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="3.4.0" />
|
||||
@ -89,16 +91,16 @@
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.SignalR.Core" Version="0.1.2" />
|
||||
<PackageReference Include="SharpCompress" Version="0.32.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.3" />
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.47.0.55603">
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.0.0" />
|
||||
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.53.0.62665">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.6" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.24.0" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="17.2.3" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.27.0" />
|
||||
<PackageReference Include="System.IO.Abstractions" Version="19.2.1" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
<PackageReference Include="VersOne.Epub" Version="3.3.0-alpha1" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -5,7 +5,7 @@ namespace API.Comparators;
|
||||
public class NumericComparer : IComparer
|
||||
{
|
||||
|
||||
public int Compare(object x, object y)
|
||||
public int Compare(object? x, object? y)
|
||||
{
|
||||
if((x is string xs) && (y is string ys))
|
||||
{
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using API.Constants;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
@ -23,7 +22,6 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace API.Controllers;
|
||||
@ -213,10 +211,13 @@ public class AccountController : BaseApiController
|
||||
var dto = _mapper.Map<UserDto>(user);
|
||||
dto.Token = await _tokenService.CreateToken(user);
|
||||
dto.RefreshToken = await _tokenService.CreateRefreshToken(user);
|
||||
var pref = await _unitOfWork.UserRepository.GetPreferencesAsync(user.UserName);
|
||||
var pref = await _unitOfWork.UserRepository.GetPreferencesAsync(user.UserName!);
|
||||
if (pref == null) return Ok(dto);
|
||||
|
||||
pref.Theme ??= await _unitOfWork.SiteThemeRepository.GetDefaultTheme();
|
||||
dto.Preferences = _mapper.Map<UserPreferencesDto>(pref);
|
||||
return dto;
|
||||
|
||||
return Ok(dto);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -248,7 +249,7 @@ public class AccountController : BaseApiController
|
||||
.GetFields(BindingFlags.Public | BindingFlags.Static)
|
||||
.Where(f => f.FieldType == typeof(string))
|
||||
.ToDictionary(f => f.Name,
|
||||
f => (string) f.GetValue(null)).Values.ToList();
|
||||
f => (string) f.GetValue(null)!).Values.ToList();
|
||||
}
|
||||
|
||||
|
||||
@ -260,6 +261,7 @@ public class AccountController : BaseApiController
|
||||
public async Task<ActionResult<string>> ResetApiKey()
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
user.ApiKey = HashUtil.ApiKey();
|
||||
|
||||
@ -281,7 +283,7 @@ public class AccountController : BaseApiController
|
||||
/// <param name="dto"></param>
|
||||
/// <returns>Returns just if the email was sent or server isn't reachable</returns>
|
||||
[HttpPost("update/email")]
|
||||
public async Task<ActionResult> UpdateEmail(UpdateEmailDto dto)
|
||||
public async Task<ActionResult> UpdateEmail(UpdateEmailDto? dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return Unauthorized("You do not have permission");
|
||||
@ -297,7 +299,7 @@ public class AccountController : BaseApiController
|
||||
}
|
||||
|
||||
// Validate no other users exist with this email
|
||||
if (user.Email.Equals(dto.Email)) return Ok("Nothing to do");
|
||||
if (user.Email!.Equals(dto.Email)) return Ok("Nothing to do");
|
||||
|
||||
// Check if email is used by another user
|
||||
var existingUserEmail = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||
@ -335,7 +337,7 @@ public class AccountController : BaseApiController
|
||||
{
|
||||
EmailAddress = string.IsNullOrEmpty(user.Email) ? dto.Email : user.Email,
|
||||
InstallId = BuildInfo.Version.ToString(),
|
||||
InvitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName,
|
||||
InvitingUser = (await _unitOfWork.UserRepository.GetAdminUsersAsync()).First().UserName!,
|
||||
ServerConfirmationLink = emailLink
|
||||
});
|
||||
}
|
||||
@ -357,7 +359,7 @@ public class AccountController : BaseApiController
|
||||
}
|
||||
|
||||
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
@ -367,9 +369,9 @@ public class AccountController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return Unauthorized("You do not have permission");
|
||||
if (dto == null) return BadRequest("Invalid payload");
|
||||
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
if (!await _accountService.HasChangeRestrictionRole(user)) return BadRequest("You do not have permission");
|
||||
|
||||
user.AgeRestriction = isAdmin ? AgeRating.NotApplicable : dto.AgeRating;
|
||||
user.AgeRestrictionIncludeUnknowns = isAdmin || dto.IncludeUnknowns;
|
||||
@ -387,7 +389,7 @@ public class AccountController : BaseApiController
|
||||
return BadRequest("There was an error updating the age restriction");
|
||||
}
|
||||
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
@ -402,13 +404,14 @@ public class AccountController : BaseApiController
|
||||
public async Task<ActionResult> UpdateAccount(UpdateUserDto dto)
|
||||
{
|
||||
var adminUser = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (adminUser == null) return Unauthorized();
|
||||
if (!await _unitOfWork.UserRepository.IsUserAdminAsync(adminUser)) return Unauthorized("You do not have permission");
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(dto.UserId);
|
||||
if (user == null) return BadRequest("User does not exist");
|
||||
|
||||
// Check if username is changing
|
||||
if (!user.UserName.Equals(dto.Username))
|
||||
if (!user.UserName!.Equals(dto.Username))
|
||||
{
|
||||
// Validate username change
|
||||
var errors = await _accountService.ValidateUsername(dto.Username);
|
||||
@ -488,12 +491,13 @@ public class AccountController : BaseApiController
|
||||
public async Task<ActionResult<string>> GetInviteUrl(int userId, bool withBaseUrl)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.EmailConfirmed)
|
||||
return BadRequest("User is already confirmed");
|
||||
if (string.IsNullOrEmpty(user.ConfirmationToken))
|
||||
return BadRequest("Manual setup is unable to be completed. Please cancel and recreate the invite.");
|
||||
|
||||
return await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", user.Email, withBaseUrl);
|
||||
return await _accountService.GenerateEmailLink(Request, user.ConfirmationToken, "confirm-email", user.Email!, withBaseUrl);
|
||||
}
|
||||
|
||||
|
||||
@ -520,23 +524,14 @@ public class AccountController : BaseApiController
|
||||
if (emailValidationErrors.Any())
|
||||
{
|
||||
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||
if (await _userManager.IsEmailConfirmedAsync(invitedUser))
|
||||
return BadRequest($"User is already registered as {invitedUser.UserName}");
|
||||
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
|
||||
return BadRequest($"User is already registered as {invitedUser!.UserName}");
|
||||
return BadRequest("User is already invited under this email and has yet to accepted invite.");
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new user
|
||||
var user = new AppUser()
|
||||
{
|
||||
UserName = dto.Email,
|
||||
Email = dto.Email,
|
||||
ApiKey = HashUtil.ApiKey(),
|
||||
UserPreferences = new AppUserPreferences
|
||||
{
|
||||
Theme = await _unitOfWork.SiteThemeRepository.GetDefaultTheme()
|
||||
}
|
||||
};
|
||||
var user = DbFactory.AppUser(dto.Email, dto.Email, await _unitOfWork.SiteThemeRepository.GetDefaultTheme());
|
||||
|
||||
try
|
||||
{
|
||||
@ -612,7 +607,7 @@ public class AccountController : BaseApiController
|
||||
await _emailService.SendConfirmationEmail(new ConfirmationEmailDto()
|
||||
{
|
||||
EmailAddress = dto.Email,
|
||||
InvitingUser = adminUser.UserName,
|
||||
InvitingUser = adminUser.UserName!,
|
||||
ServerConfirmationLink = emailLink
|
||||
});
|
||||
}
|
||||
@ -680,14 +675,14 @@ public class AccountController : BaseApiController
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
|
||||
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
|
||||
AppUserIncludes.UserPreferences);
|
||||
user = (await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
|
||||
AppUserIncludes.UserPreferences))!;
|
||||
|
||||
// Perform Login code
|
||||
return new UserDto
|
||||
{
|
||||
Username = user.UserName,
|
||||
Email = user.Email,
|
||||
Username = user.UserName!,
|
||||
Email = user.Email!,
|
||||
Token = await _tokenService.CreateToken(user),
|
||||
RefreshToken = await _tokenService.CreateRefreshToken(user),
|
||||
ApiKey = user.ApiKey,
|
||||
@ -731,7 +726,7 @@ public class AccountController : BaseApiController
|
||||
|
||||
// For the user's connected devices to pull the new information in
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate,
|
||||
MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
|
||||
MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
|
||||
|
||||
// Perform Login code
|
||||
return Ok();
|
||||
@ -832,14 +827,14 @@ public class AccountController : BaseApiController
|
||||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName,
|
||||
user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName!,
|
||||
AppUserIncludes.UserPreferences);
|
||||
|
||||
// Perform Login code
|
||||
return new UserDto
|
||||
{
|
||||
Username = user.UserName,
|
||||
Email = user.Email,
|
||||
Username = user!.UserName!,
|
||||
Email = user.Email!,
|
||||
Token = await _tokenService.CreateToken(user),
|
||||
RefreshToken = await _tokenService.CreateRefreshToken(user),
|
||||
ApiKey = user.ApiKey,
|
||||
@ -873,8 +868,8 @@ public class AccountController : BaseApiController
|
||||
{
|
||||
await _emailService.SendMigrationEmail(new EmailMigrationDto()
|
||||
{
|
||||
EmailAddress = user.Email,
|
||||
Username = user.UserName,
|
||||
EmailAddress = user.Email!,
|
||||
Username = user.UserName!,
|
||||
ServerConfirmationLink = emailLink,
|
||||
InstallId = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallId)).Value
|
||||
});
|
||||
@ -908,8 +903,8 @@ public class AccountController : BaseApiController
|
||||
if (emailValidationErrors.Any())
|
||||
{
|
||||
var invitedUser = await _unitOfWork.UserRepository.GetUserByEmailAsync(dto.Email);
|
||||
if (await _userManager.IsEmailConfirmedAsync(invitedUser))
|
||||
return BadRequest($"User is already registered as {invitedUser.UserName}");
|
||||
if (await _userManager.IsEmailConfirmedAsync(invitedUser!))
|
||||
return BadRequest($"User is already registered as {invitedUser!.UserName}");
|
||||
|
||||
_logger.LogInformation("A user is attempting to login, but hasn't accepted email invite");
|
||||
return BadRequest("User is already invited under this email and has yet to accepted invite.");
|
||||
|
@ -37,6 +37,7 @@ public class BookController : BaseApiController
|
||||
public async Task<ActionResult<BookInfoDto>> GetBookInfo(int chapterId)
|
||||
{
|
||||
var dto = await _unitOfWork.ChapterRepository.GetChapterInfoDtoAsync(chapterId);
|
||||
if (dto == null) return BadRequest("Chapter does not exist");
|
||||
var bookTitle = string.Empty;
|
||||
switch (dto.SeriesFormat)
|
||||
{
|
||||
@ -93,6 +94,7 @@ public class BookController : BaseApiController
|
||||
{
|
||||
if (chapterId <= 0) return BadRequest("Chapter is not valid");
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId);
|
||||
if (chapter == null) return BadRequest("Chapter is not valid");
|
||||
using var book = await EpubReader.OpenBookAsync(chapter.Files.ElementAt(0).FilePath, BookService.BookReaderOptions);
|
||||
|
||||
var key = BookService.CoalesceKeyForAnyFile(book, file);
|
||||
@ -116,8 +118,9 @@ public class BookController : BaseApiController
|
||||
public async Task<ActionResult<ICollection<BookChapterItem>>> GetBookChapters(int chapterId)
|
||||
{
|
||||
if (chapterId <= 0) return BadRequest("Chapter is not valid");
|
||||
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId);
|
||||
if (chapter == null) return BadRequest("Chapter is not valid");
|
||||
|
||||
try
|
||||
{
|
||||
return Ok(await _bookService.GenerateTableOfContents(chapter));
|
||||
@ -140,6 +143,7 @@ public class BookController : BaseApiController
|
||||
public async Task<ActionResult<string>> GetBookPage(int chapterId, [FromQuery] int page)
|
||||
{
|
||||
var chapter = await _cacheService.Ensure(chapterId);
|
||||
if (chapter == null) return BadRequest("Could not find Chapter");
|
||||
var path = _cacheService.GetCachedFile(chapter);
|
||||
|
||||
var baseUrl = "//" + Request.Host + Request.PathBase + "/api/";
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.DTOs.ReadingLists;
|
||||
using API.DTOs.ReadingLists.CBL;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
|
@ -1,14 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs.CollectionTags;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.Services.Tasks.Metadata;
|
||||
using API.SignalR;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@ -35,16 +33,17 @@ public class CollectionController : BaseApiController
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<IEnumerable<CollectionTagDto>> GetAllTags()
|
||||
public async Task<ActionResult<IEnumerable<CollectionTagDto>>> GetAllTags()
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return Unauthorized();
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
if (isAdmin)
|
||||
{
|
||||
return await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync();
|
||||
return Ok(await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync());
|
||||
}
|
||||
|
||||
return await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync(user.Id);
|
||||
return Ok(await _unitOfWork.CollectionTagRepository.GetAllPromotedTagDtosAsync(user.Id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -55,13 +54,13 @@ public class CollectionController : BaseApiController
|
||||
/// <returns></returns>
|
||||
[Authorize(Policy = "RequireAdminRole")]
|
||||
[HttpGet("search")]
|
||||
public async Task<IEnumerable<CollectionTagDto>> SearchTags(string queryString)
|
||||
public async Task<ActionResult<IEnumerable<CollectionTagDto>>> SearchTags(string queryString)
|
||||
{
|
||||
queryString ??= string.Empty;
|
||||
queryString = queryString.Replace(@"%", string.Empty);
|
||||
if (queryString.Length == 0) return await GetAllTags();
|
||||
|
||||
return await _unitOfWork.CollectionTagRepository.SearchTagDtosAsync(queryString, User.GetUserId());
|
||||
return Ok(await _unitOfWork.CollectionTagRepository.SearchTagDtosAsync(queryString, User.GetUserId()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -126,7 +125,7 @@ public class CollectionController : BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetFullTagAsync(updateSeriesForTagDto.Tag.Id);
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetTagAsync(updateSeriesForTagDto.Tag.Id, CollectionTagIncludes.SeriesMetadata);
|
||||
if (tag == null) return BadRequest("Not a valid Tag");
|
||||
tag.SeriesMetadatas ??= new List<SeriesMetadata>();
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
@ -9,9 +7,7 @@ using API.DTOs.Device;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using ExCSS;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers;
|
||||
@ -39,6 +35,7 @@ public class DeviceController : BaseApiController
|
||||
public async Task<ActionResult> CreateOrUpdateDevice(CreateDeviceDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Devices);
|
||||
if (user == null) return Unauthorized();
|
||||
var device = await _deviceService.Create(dto, user);
|
||||
|
||||
if (device == null) return BadRequest("There was an error when creating the device");
|
||||
@ -50,6 +47,7 @@ public class DeviceController : BaseApiController
|
||||
public async Task<ActionResult> UpdateDevice(UpdateDeviceDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Devices);
|
||||
if (user == null) return Unauthorized();
|
||||
var device = await _deviceService.Update(dto, user);
|
||||
|
||||
if (device == null) return BadRequest("There was an error when updating the device");
|
||||
@ -67,6 +65,7 @@ public class DeviceController : BaseApiController
|
||||
{
|
||||
if (deviceId <= 0) return BadRequest("Not a valid deviceId");
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Devices);
|
||||
if (user == null) return Unauthorized();
|
||||
if (await _deviceService.Delete(user, deviceId)) return Ok();
|
||||
|
||||
return BadRequest("Could not delete device");
|
||||
|
@ -93,13 +93,13 @@ public class DownloadController : BaseApiController
|
||||
public async Task<ActionResult> DownloadVolume(int volumeId)
|
||||
{
|
||||
if (!await HasDownloadPermission()) return BadRequest("You do not have permission");
|
||||
|
||||
var files = await _unitOfWork.VolumeRepository.GetFilesForVolume(volumeId);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeByIdAsync(volumeId);
|
||||
if (volume == null) return BadRequest("Volume doesn't exist");
|
||||
var files = await _unitOfWork.VolumeRepository.GetFilesForVolume(volumeId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId);
|
||||
try
|
||||
{
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_v{volumeId}", $"{series.Name} - Volume {volume.Number}.zip");
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_v{volumeId}", $"{series!.Name} - Volume {volume.Number}.zip");
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
@ -110,6 +110,7 @@ public class DownloadController : BaseApiController
|
||||
private async Task<bool> HasDownloadPermission()
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return false;
|
||||
return await _accountService.HasDownloadPermission(user);
|
||||
}
|
||||
|
||||
@ -130,11 +131,12 @@ public class DownloadController : BaseApiController
|
||||
if (!await HasDownloadPermission()) return BadRequest("You do not have permission");
|
||||
var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId);
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(chapterId);
|
||||
if (chapter == null) return BadRequest("Invalid chapter");
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeByIdAsync(chapter.VolumeId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume!.SeriesId);
|
||||
try
|
||||
{
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_c{chapterId}", $"{series.Name} - Chapter {chapter.Number}.zip");
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_c{chapterId}", $"{series!.Name} - Chapter {chapter.Number}.zip");
|
||||
}
|
||||
catch (KavitaException ex)
|
||||
{
|
||||
@ -177,8 +179,9 @@ public class DownloadController : BaseApiController
|
||||
public async Task<ActionResult> DownloadSeries(int seriesId)
|
||||
{
|
||||
if (!await HasDownloadPermission()) return BadRequest("You do not have permission");
|
||||
var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId);
|
||||
if (series == null) return BadRequest("Invalid Series");
|
||||
var files = await _unitOfWork.SeriesRepository.GetFilesForSeries(seriesId);
|
||||
try
|
||||
{
|
||||
return await DownloadFiles(files, $"download_{User.GetUsername()}_s{seriesId}", $"{series.Name}.zip");
|
||||
@ -201,13 +204,13 @@ public class DownloadController : BaseApiController
|
||||
if (!downloadBookmarkDto.Bookmarks.Any()) return BadRequest("Bookmarks cannot be empty");
|
||||
|
||||
// We know that all bookmarks will be for one single seriesId
|
||||
var userId = User.GetUserId();
|
||||
var username = User.GetUsername();
|
||||
var userId = User.GetUserId()!;
|
||||
var username = User.GetUsername()!;
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(downloadBookmarkDto.Bookmarks.First().SeriesId);
|
||||
|
||||
var files = await _bookmarkService.GetBookmarkFilesById(downloadBookmarkDto.Bookmarks.Select(b => b.Id));
|
||||
|
||||
var filename = $"{series.Name} - Bookmarks.zip";
|
||||
var filename = $"{series!.Name} - Bookmarks.zip";
|
||||
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
|
||||
MessageFactory.DownloadProgressEvent(username, Path.GetFileNameWithoutExtension(filename), 0F));
|
||||
var seriesIds = string.Join("_", downloadBookmarkDto.Bookmarks.Select(b => b.SeriesId).Distinct());
|
||||
|
@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using API.Services;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
|
@ -1,5 +1,3 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
|
@ -7,7 +7,6 @@ using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.JumpBar;
|
||||
using API.DTOs.Search;
|
||||
using API.DTOs.System;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
@ -17,7 +16,6 @@ using API.Services;
|
||||
using API.Services.Tasks.Scanner;
|
||||
using API.SignalR;
|
||||
using AutoMapper;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -209,6 +207,7 @@ public class LibraryController : BaseApiController
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(dto.ApiKey);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
// Validate user has Admin privileges
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
@ -244,7 +243,6 @@ public class LibraryController : BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId, LibraryIncludes.None);
|
||||
if (TaskScheduler.HasScanTaskRunningForLibrary(libraryId))
|
||||
{
|
||||
_logger.LogInformation("User is attempting to delete a library while a scan is in progress");
|
||||
@ -252,6 +250,9 @@ public class LibraryController : BaseApiController
|
||||
"You cannot delete a library while a scan is in progress. Please wait for scan to complete or restart Kavita then try to delete");
|
||||
}
|
||||
|
||||
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId);
|
||||
if (library == null) return BadRequest("Library no longer exists");
|
||||
|
||||
// Due to a bad schema that I can't figure out how to fix, we need to erase all RelatedSeries before we delete the library
|
||||
// Aka SeriesRelation has an invalid foreign key
|
||||
foreach (var s in await _unitOfWork.SeriesRepository.GetSeriesForLibraryIdAsync(library.Id,
|
||||
@ -317,8 +318,10 @@ public class LibraryController : BaseApiController
|
||||
[HttpPost("update")]
|
||||
public async Task<ActionResult> UpdateLibrary(UpdateLibraryDto dto)
|
||||
{
|
||||
var newName = dto.Name.Trim();
|
||||
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(dto.Id, LibraryIncludes.Folders);
|
||||
if (library == null) return BadRequest("Library doesn't exist");
|
||||
|
||||
var newName = dto.Name.Trim();
|
||||
if (await _unitOfWork.LibraryRepository.LibraryExists(newName) && !library.Name.Equals(newName))
|
||||
return BadRequest("Library name already exists");
|
||||
|
||||
|
@ -194,6 +194,7 @@ public class OpdsController : BaseApiController
|
||||
return BadRequest("OPDS is not enabled on this server");
|
||||
var userId = await GetUser(apiKey);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
if (user == null) return Unauthorized();
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
|
||||
IEnumerable<CollectionTagDto> tags = isAdmin ? (await _unitOfWork.CollectionTagRepository.GetAllTagDtosAsync())
|
||||
@ -230,6 +231,7 @@ public class OpdsController : BaseApiController
|
||||
return BadRequest("OPDS is not enabled on this server");
|
||||
var userId = await GetUser(apiKey);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
if (user == null) return Unauthorized();
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
|
||||
IEnumerable <CollectionTagDto> tags;
|
||||
@ -310,7 +312,8 @@ public class OpdsController : BaseApiController
|
||||
var userId = await GetUser(apiKey);
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
|
||||
var userWithLists = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user.UserName, AppUserIncludes.ReadingListsWithItems);
|
||||
var userWithLists = await _unitOfWork.UserRepository.GetUserByUsernameAsync(user!.UserName!, AppUserIncludes.ReadingListsWithItems);
|
||||
if (userWithLists == null) return Unauthorized();
|
||||
var readingList = userWithLists.ReadingLists.SingleOrDefault(t => t.Id == readingListId);
|
||||
if (readingList == null)
|
||||
{
|
||||
@ -432,7 +435,6 @@ public class OpdsController : BaseApiController
|
||||
query = query.Replace(@"%", string.Empty);
|
||||
// Get libraries user has access to
|
||||
var libraries = (await _unitOfWork.LibraryRepository.GetLibrariesForUserIdAsync(userId)).ToList();
|
||||
|
||||
if (!libraries.Any()) return BadRequest("User does not have access to any libraries");
|
||||
|
||||
var isAdmin = await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
@ -569,7 +571,7 @@ public class OpdsController : BaseApiController
|
||||
(await _unitOfWork.ChapterRepository.GetChaptersAsync(volumeId)).OrderBy(x => double.Parse(x.Number),
|
||||
_chapterSortComparer);
|
||||
|
||||
var feed = CreateFeed(series.Name + " - Volume " + volume.Name + $" - {SeriesService.FormatChapterName(libraryType)}s ", $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey);
|
||||
var feed = CreateFeed(series.Name + " - Volume " + volume!.Name + $" - {SeriesService.FormatChapterName(libraryType)}s ", $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey);
|
||||
SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-{SeriesService.FormatChapterName(libraryType)}s");
|
||||
foreach (var chapter in chapters)
|
||||
{
|
||||
@ -597,11 +599,12 @@ public class OpdsController : BaseApiController
|
||||
var userId = await GetUser(apiKey);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
|
||||
var libraryType = await _unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId);
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterDtoAsync(chapterId);
|
||||
if (chapter == null) return BadRequest("Chapter doesn't exist");
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId);
|
||||
var files = await _unitOfWork.ChapterRepository.GetFilesForChapterAsync(chapterId);
|
||||
|
||||
var feed = CreateFeed(series.Name + " - Volume " + volume.Name + $" - {SeriesService.FormatChapterName(libraryType)}s", $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}", apiKey);
|
||||
var feed = CreateFeed(series.Name + " - Volume " + volume!.Name + $" - {SeriesService.FormatChapterName(libraryType)}s", $"{apiKey}/series/{seriesId}/volume/{volumeId}/chapter/{chapterId}", apiKey);
|
||||
SetFeedId(feed, $"series-{series.Id}-volume-{volumeId}-{SeriesService.FormatChapterName(libraryType)}-{chapterId}-files");
|
||||
foreach (var mangaFile in files)
|
||||
{
|
||||
@ -768,7 +771,7 @@ public class OpdsController : BaseApiController
|
||||
DirectoryService.GetHumanReadableBytes(_directoryService.GetTotalSize(new List<string>()
|
||||
{mangaFile.FilePath}));
|
||||
var fileType = _downloadService.GetContentTypeFromFile(mangaFile.FilePath);
|
||||
var filename = Uri.EscapeDataString(Path.GetFileName(mangaFile.FilePath) ?? string.Empty);
|
||||
var filename = Uri.EscapeDataString(Path.GetFileName(mangaFile.FilePath));
|
||||
var libraryType = await _unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeDtoAsync(volumeId, await GetUser(apiKey));
|
||||
|
||||
@ -890,7 +893,7 @@ public class OpdsController : BaseApiController
|
||||
return link;
|
||||
}
|
||||
|
||||
private static FeedLink CreateLink(string rel, string type, string href, string title = null)
|
||||
private static FeedLink CreateLink(string rel, string type, string href, string? title = null)
|
||||
{
|
||||
return new FeedLink()
|
||||
{
|
||||
|
@ -38,10 +38,10 @@ public class PluginController : BaseApiController
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByApiKeyAsync(apiKey);
|
||||
if (userId <= 0) return Unauthorized();
|
||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||
_logger.LogInformation("Plugin {PluginName} has authenticated with {UserName} ({UserId})'s API Key", pluginName, user.UserName, userId);
|
||||
_logger.LogInformation("Plugin {PluginName} has authenticated with {UserName} ({UserId})'s API Key", pluginName, user!.UserName, userId);
|
||||
return new UserDto
|
||||
{
|
||||
Username = user.UserName,
|
||||
Username = user.UserName!,
|
||||
Token = await _tokenService.CreateToken(user),
|
||||
ApiKey = user.ApiKey,
|
||||
};
|
||||
|
@ -13,7 +13,6 @@ using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using API.SignalR;
|
||||
using Hangfire;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -164,7 +163,7 @@ public class ReaderController : BaseApiController
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId", "extractPdf"})]
|
||||
public async Task<ActionResult<IEnumerable<FileDimensionDto>>> GetFileDimensions(int chapterId, bool extractPdf = false)
|
||||
{
|
||||
if (chapterId <= 0) return null;
|
||||
if (chapterId <= 0) return ArraySegment<FileDimensionDto>.Empty;
|
||||
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
|
||||
if (chapter == null) return BadRequest("Could not find Chapter");
|
||||
return Ok(_cacheService.GetCachedFileDimensions(chapterId));
|
||||
@ -179,9 +178,9 @@ public class ReaderController : BaseApiController
|
||||
/// <returns></returns>
|
||||
[HttpGet("chapter-info")]
|
||||
[ResponseCache(CacheProfileName = ResponseCacheProfiles.Hour, VaryByQueryKeys = new []{"chapterId", "extractPdf", "includeDimensions"})]
|
||||
public async Task<ActionResult<ChapterInfoDto>> GetChapterInfo(int chapterId, bool extractPdf = false, bool includeDimensions = false)
|
||||
public async Task<ActionResult<ChapterInfoDto?>> GetChapterInfo(int chapterId, bool extractPdf = false, bool includeDimensions = false)
|
||||
{
|
||||
if (chapterId <= 0) return null; // This can happen occasionally from UI, we should just ignore
|
||||
if (chapterId <= 0) return Ok(null); // This can happen occasionally from UI, we should just ignore
|
||||
var chapter = await _cacheService.Ensure(chapterId, extractPdf);
|
||||
if (chapter == null) return BadRequest("Could not find Chapter");
|
||||
|
||||
@ -249,7 +248,7 @@ public class ReaderController : BaseApiController
|
||||
|
||||
return Ok(new BookmarkInfoDto()
|
||||
{
|
||||
SeriesName = series.Name,
|
||||
SeriesName = series!.Name,
|
||||
SeriesFormat = series.Format,
|
||||
SeriesId = series.Id,
|
||||
LibraryId = series.LibraryId,
|
||||
@ -267,6 +266,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkRead(MarkReadDto markReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
await _readerService.MarkSeriesAsRead(user, markReadDto.SeriesId);
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest("There was an issue saving progress");
|
||||
@ -284,6 +284,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkUnread(MarkReadDto markReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
await _readerService.MarkSeriesAsUnread(user, markReadDto.SeriesId);
|
||||
|
||||
if (!await _unitOfWork.CommitAsync()) return BadRequest("There was an issue saving progress");
|
||||
@ -300,6 +301,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkVolumeAsUnread(MarkVolumeReadDto markVolumeReadDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
||||
await _readerService.MarkChaptersAsUnread(user, markVolumeReadDto.SeriesId, chapters);
|
||||
@ -323,9 +325,10 @@ public class ReaderController : BaseApiController
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
|
||||
var chapters = await _unitOfWork.ChapterRepository.GetChaptersAsync(markVolumeReadDto.VolumeId);
|
||||
if (user == null) return Unauthorized();
|
||||
await _readerService.MarkChaptersAsRead(user, markVolumeReadDto.SeriesId, chapters);
|
||||
await _eventHub.SendMessageAsync(MessageFactory.UserProgressUpdate,
|
||||
MessageFactory.UserProgressUpdateEvent(user.Id, user.UserName, markVolumeReadDto.SeriesId,
|
||||
MessageFactory.UserProgressUpdateEvent(user.Id, user.UserName!, markVolumeReadDto.SeriesId,
|
||||
markVolumeReadDto.VolumeId, 0, chapters.Sum(c => c.Pages)));
|
||||
|
||||
if (await _unitOfWork.CommitAsync())
|
||||
@ -346,6 +349,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkMultipleAsRead(MarkVolumesReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds);
|
||||
@ -374,6 +378,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkMultipleAsUnread(MarkVolumesReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
var chapterIds = await _unitOfWork.VolumeRepository.GetChapterIdsByVolumeIds(dto.VolumeIds);
|
||||
@ -401,6 +406,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkMultipleSeriesAsRead(MarkMultipleSeriesAsReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true);
|
||||
@ -426,6 +432,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> MarkMultipleSeriesAsUnread(MarkMultipleSeriesAsReadDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
var volumes = await _unitOfWork.VolumeRepository.GetVolumesForSeriesAsync(dto.SeriesIds.ToArray(), true);
|
||||
@ -509,6 +516,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult<bool>> MarkChaptersUntilAsRead(int seriesId, float chapterNumber)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
if (user == null) return Unauthorized();
|
||||
user.Progresses ??= new List<AppUserProgress>();
|
||||
|
||||
// Tachiyomi sends chapter 0.0f when there's no chapters read.
|
||||
@ -546,6 +554,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarks(int chapterId)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForChapter(user.Id, chapterId));
|
||||
}
|
||||
@ -559,6 +568,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetAllBookmarks(FilterDto filterDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
|
||||
return Ok(await _unitOfWork.UserRepository.GetAllBookmarkDtos(user.Id, filterDto));
|
||||
@ -573,6 +583,7 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> RemoveBookmarks(RemoveBookmarkForSeriesDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user == null) return Unauthorized();
|
||||
if (user.Bookmarks == null) return Ok("Nothing to remove");
|
||||
|
||||
try
|
||||
@ -612,7 +623,8 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult> BulkRemoveBookmarks(BulkRemoveBookmarkForSeriesDto dto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user.Bookmarks == null) return Ok("Nothing to remove");
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok("Nothing to remove");
|
||||
|
||||
try
|
||||
{
|
||||
@ -648,7 +660,8 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForVolume(int volumeId)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForVolume(user.Id, volumeId));
|
||||
}
|
||||
|
||||
@ -661,7 +674,8 @@ public class ReaderController : BaseApiController
|
||||
public async Task<ActionResult<IEnumerable<BookmarkDto>>> GetBookmarksForSeries(int seriesId)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Bookmarks);
|
||||
if (user.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
if (user == null) return Unauthorized();
|
||||
if (user?.Bookmarks == null) return Ok(Array.Empty<BookmarkDto>());
|
||||
|
||||
return Ok(await _unitOfWork.UserRepository.GetBookmarkDtosForSeries(user.Id, seriesId));
|
||||
}
|
||||
|
@ -1,22 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Comparators;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs.ReadingLists;
|
||||
using API.DTOs.ReadingLists.CBL;
|
||||
using API.Entities;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
using API.SignalR;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace API.Controllers;
|
||||
@ -186,8 +179,8 @@ public class ReadingListController : BaseApiController
|
||||
[HttpPost("create")]
|
||||
public async Task<ActionResult<ReadingListDto>> CreateList(CreateReadingListDto dto)
|
||||
{
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.ReadingLists);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public class RecommendedController : BaseApiController
|
||||
[HttpGet("highly-rated")]
|
||||
public async Task<ActionResult<PagedList<SeriesDto>>> GetHighlyRated(int libraryId, [FromQuery] UserParams userParams)
|
||||
{
|
||||
var userId = User.GetUserId();
|
||||
var userId = User.GetUserId()!;
|
||||
userParams ??= new UserParams();
|
||||
var series = await _unitOfWork.SeriesRepository.GetHighlyRated(userId, libraryId, userParams);
|
||||
await _unitOfWork.SeriesRepository.AddSeriesModifiers(userId, series);
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
@ -54,6 +53,7 @@ public class SearchController : BaseApiController
|
||||
queryString = Services.Tasks.Scanner.Parser.Parser.CleanQuery(queryString);
|
||||
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user == null) return Unauthorized();
|
||||
var libraries = _unitOfWork.LibraryRepository.GetLibraryIdsForUserIdAsync(user.Id, QueryContext.Search).ToList();
|
||||
if (!libraries.Any()) return BadRequest("User does not have access to any libraries");
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Constants;
|
||||
using API.Data;
|
||||
@ -11,7 +10,6 @@ using API.DTOs.Metadata;
|
||||
using API.DTOs.SeriesDetail;
|
||||
using API.Entities;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Metadata;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.Services;
|
||||
@ -137,7 +135,7 @@ public class SeriesController : BaseApiController
|
||||
public async Task<ActionResult> UpdateSeriesRating(UpdateSeriesRatingDto updateSeriesRatingDto)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Ratings);
|
||||
if (!await _seriesService.UpdateRating(user, updateSeriesRatingDto)) return BadRequest("There was a critical error.");
|
||||
if (!await _seriesService.UpdateRating(user!, updateSeriesRatingDto)) return BadRequest("There was a critical error.");
|
||||
return Ok();
|
||||
}
|
||||
|
||||
@ -159,14 +157,14 @@ public class SeriesController : BaseApiController
|
||||
}
|
||||
|
||||
series.Name = updateSeries.Name.Trim();
|
||||
series.NormalizedName = Services.Tasks.Scanner.Parser.Parser.Normalize(series.Name);
|
||||
if (!string.IsNullOrEmpty(updateSeries.SortName.Trim()))
|
||||
series.NormalizedName = series.Name.ToNormalized();
|
||||
if (!string.IsNullOrEmpty(updateSeries.SortName?.Trim()))
|
||||
{
|
||||
series.SortName = updateSeries.SortName.Trim();
|
||||
}
|
||||
|
||||
series.LocalizedName = updateSeries.LocalizedName.Trim();
|
||||
series.NormalizedLocalizedName = Services.Tasks.Scanner.Parser.Parser.Normalize(series.LocalizedName);
|
||||
series.LocalizedName = updateSeries.LocalizedName?.Trim();
|
||||
series.NormalizedLocalizedName = series.LocalizedName?.ToNormalized();
|
||||
|
||||
series.NameLocked = updateSeries.NameLocked;
|
||||
series.SortNameLocked = updateSeries.SortNameLocked;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@ -8,7 +7,6 @@ using API.DTOs.Jobs;
|
||||
using API.DTOs.Stats;
|
||||
using API.DTOs.Update;
|
||||
using API.Extensions;
|
||||
using API.Logging;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using Hangfire;
|
||||
@ -16,7 +14,6 @@ using Hangfire.Storage;
|
||||
using Kavita.Common;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TaskScheduler = API.Services.TaskScheduler;
|
||||
|
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -32,7 +32,7 @@ public class StatsController : BaseApiController
|
||||
public async Task<ActionResult<UserReadStatistics>> GetUserReadStatistics(int userId)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
if (user.Id != userId && !await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole))
|
||||
if (user!.Id != userId && !await _userManager.IsInRoleAsync(user, PolicyConstants.AdminRole))
|
||||
return Unauthorized("You are not authorized to view another user's statistics");
|
||||
|
||||
return Ok(await _statService.GetUserReadStatistics(userId, new List<int>()));
|
||||
@ -116,7 +116,7 @@ public class StatsController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
var isAdmin = User.IsInRole(PolicyConstants.AdminRole);
|
||||
if (!isAdmin && userId != user.Id) return BadRequest();
|
||||
if (!isAdmin && userId != user!.Id) return BadRequest();
|
||||
|
||||
return Ok(await _statService.ReadCountByDay(userId, days));
|
||||
}
|
||||
@ -136,7 +136,7 @@ public class StatsController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
|
||||
var isAdmin = User.IsInRole(PolicyConstants.AdminRole);
|
||||
if (!isAdmin && userId != user.Id) return BadRequest();
|
||||
if (!isAdmin && userId != user!.Id) return BadRequest();
|
||||
|
||||
return Ok(await _statService.GetReadingHistory(userId));
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ public class TachiyomiController : BaseApiController
|
||||
[HttpPost("mark-chapter-until-as-read")]
|
||||
public async Task<ActionResult<bool>> MarkChaptersUntilAsRead(int seriesId, float chapterNumber)
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(), AppUserIncludes.Progress);
|
||||
var user = (await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(),
|
||||
AppUserIncludes.Progress))!;
|
||||
return Ok(await _tachiyomiService.MarkChaptersUntilAsRead(user, seriesId, chapterNumber));
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.DTOs.Theme;
|
||||
using API.Extensions;
|
||||
using API.Services;
|
||||
using API.Services.Tasks;
|
||||
using Kavita.Common;
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.DTOs.Uploads;
|
||||
@ -10,7 +9,6 @@ using Flurl.Http;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NetVips;
|
||||
|
||||
namespace API.Controllers;
|
||||
|
||||
@ -93,8 +91,10 @@ public class UploadController : BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, ImageService.GetSeriesFormat(uploadFileDto.Id));
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(uploadFileDto.Id);
|
||||
if (series == null) return BadRequest("Invalid Series");
|
||||
var convertToWebP = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).ConvertCoverToWebP;
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, ImageService.GetSeriesFormat(uploadFileDto.Id), convertToWebP);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
@ -140,8 +140,10 @@ public class UploadController : BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetCollectionTagFormat(uploadFileDto.Id)}");
|
||||
var tag = await _unitOfWork.CollectionTagRepository.GetTagAsync(uploadFileDto.Id);
|
||||
if (tag == null) return BadRequest("Invalid Tag id");
|
||||
var convertToWebP = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).ConvertCoverToWebP;
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetCollectionTagFormat(uploadFileDto.Id)}", convertToWebP);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
@ -190,8 +192,10 @@ public class UploadController : BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetReadingListFormat(uploadFileDto.Id)}");
|
||||
var readingList = await _unitOfWork.ReadingListRepository.GetReadingListByIdAsync(uploadFileDto.Id);
|
||||
if (readingList == null) return BadRequest("Reading list is not valid");
|
||||
var convertToWebP = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).ConvertCoverToWebP;
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetReadingListFormat(uploadFileDto.Id)}", convertToWebP);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
@ -238,7 +242,9 @@ public class UploadController : BaseApiController
|
||||
try
|
||||
{
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(uploadFileDto.Id);
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetChapterFormat(uploadFileDto.Id, chapter.VolumeId)}");
|
||||
if (chapter == null) return BadRequest("Invalid Chapter");
|
||||
var convertToWebP = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).ConvertCoverToWebP;
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url, $"{ImageService.GetChapterFormat(uploadFileDto.Id, chapter.VolumeId)}", convertToWebP);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
@ -246,8 +252,11 @@ public class UploadController : BaseApiController
|
||||
chapter.CoverImageLocked = true;
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId);
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
if (volume != null)
|
||||
{
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
}
|
||||
}
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
@ -301,8 +310,9 @@ public class UploadController : BaseApiController
|
||||
|
||||
try
|
||||
{
|
||||
var convertToWebP = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).ConvertCoverToWebP;
|
||||
var filePath = _imageService.CreateThumbnailFromBase64(uploadFileDto.Url,
|
||||
$"{ImageService.GetLibraryFormat(uploadFileDto.Id)}", ImageService.LibraryThumbnailWidth);
|
||||
$"{ImageService.GetLibraryFormat(uploadFileDto.Id)}", convertToWebP, ImageService.LibraryThumbnailWidth);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
@ -340,19 +350,20 @@ public class UploadController : BaseApiController
|
||||
try
|
||||
{
|
||||
var chapter = await _unitOfWork.ChapterRepository.GetChapterAsync(uploadFileDto.Id);
|
||||
if (chapter == null) return BadRequest("Chapter no longer exists");
|
||||
var originalFile = chapter.CoverImage;
|
||||
chapter.CoverImage = string.Empty;
|
||||
chapter.CoverImageLocked = false;
|
||||
_unitOfWork.ChapterRepository.Update(chapter);
|
||||
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId);
|
||||
var volume = (await _unitOfWork.VolumeRepository.GetVolumeAsync(chapter.VolumeId))!;
|
||||
volume.CoverImage = chapter.CoverImage;
|
||||
_unitOfWork.VolumeRepository.Update(volume);
|
||||
var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId);
|
||||
var series = (await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(volume.SeriesId))!;
|
||||
|
||||
if (_unitOfWork.HasChanges())
|
||||
{
|
||||
await _unitOfWork.CommitAsync();
|
||||
System.IO.File.Delete(originalFile);
|
||||
if (originalFile != null) System.IO.File.Delete(originalFile);
|
||||
_taskScheduler.RefreshSeriesMetadata(series.LibraryId, series.Id, true);
|
||||
return Ok();
|
||||
}
|
||||
|
@ -4,10 +4,7 @@ using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
using API.DTOs;
|
||||
using API.DTOs.Filtering;
|
||||
using API.Entities.Enums;
|
||||
using API.Extensions;
|
||||
using API.Helpers;
|
||||
using API.SignalR;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
@ -68,6 +65,7 @@ public class UsersController : BaseApiController
|
||||
{
|
||||
var userId = await _unitOfWork.UserRepository.GetUserIdByUsernameAsync(User.GetUsername());
|
||||
var library = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(libraryId);
|
||||
if (library == null) return BadRequest("Library does not exist");
|
||||
return Ok(await _unitOfWork.AppUserProgressRepository.UserHasProgress(library.Type, userId));
|
||||
}
|
||||
|
||||
@ -83,9 +81,8 @@ public class UsersController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(),
|
||||
AppUserIncludes.UserPreferences);
|
||||
var existingPreferences = user.UserPreferences;
|
||||
|
||||
preferencesDto.Theme ??= await _unitOfWork.SiteThemeRepository.GetDefaultTheme();
|
||||
if (user == null) return Unauthorized();
|
||||
var existingPreferences = user!.UserPreferences;
|
||||
|
||||
existingPreferences.ReadingDirection = preferencesDto.ReadingDirection;
|
||||
existingPreferences.ScalingOption = preferencesDto.ScalingOption;
|
||||
@ -107,8 +104,8 @@ public class UsersController : BaseApiController
|
||||
existingPreferences.BookReaderImmersiveMode = preferencesDto.BookReaderImmersiveMode;
|
||||
existingPreferences.GlobalPageLayoutMode = preferencesDto.GlobalPageLayoutMode;
|
||||
existingPreferences.BlurUnreadSummaries = preferencesDto.BlurUnreadSummaries;
|
||||
existingPreferences.Theme = await _unitOfWork.SiteThemeRepository.GetThemeById(preferencesDto.Theme.Id);
|
||||
existingPreferences.LayoutMode = preferencesDto.LayoutMode;
|
||||
existingPreferences.Theme = preferencesDto.Theme ?? await _unitOfWork.SiteThemeRepository.GetDefaultTheme();
|
||||
existingPreferences.PromptForDownloadSize = preferencesDto.PromptForDownloadSize;
|
||||
existingPreferences.NoTransitions = preferencesDto.NoTransitions;
|
||||
existingPreferences.SwipeToPaginate = preferencesDto.SwipeToPaginate;
|
||||
@ -117,7 +114,7 @@ public class UsersController : BaseApiController
|
||||
|
||||
if (await _unitOfWork.CommitAsync())
|
||||
{
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName), user.Id);
|
||||
await _eventHub.SendMessageToAsync(MessageFactory.UserUpdate, MessageFactory.UserUpdateEvent(user.Id, user.UserName!), user.Id);
|
||||
return Ok(preferencesDto);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.Data.Repositories;
|
||||
@ -56,6 +55,7 @@ public class WantToReadController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(),
|
||||
AppUserIncludes.WantToRead);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
var existingIds = user.WantToRead.Select(s => s.Id).ToList();
|
||||
existingIds.AddRange(dto.SeriesIds);
|
||||
@ -84,6 +84,7 @@ public class WantToReadController : BaseApiController
|
||||
{
|
||||
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername(),
|
||||
AppUserIncludes.WantToRead);
|
||||
if (user == null) return Unauthorized();
|
||||
|
||||
user.WantToRead = user.WantToRead.Where(s => !dto.SeriesIds.Contains(s.Id)).ToList();
|
||||
|
||||
|
@ -5,12 +5,12 @@ namespace API.DTOs.Account;
|
||||
public class ConfirmEmailDto
|
||||
{
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
[Required]
|
||||
public string Token { get; set; }
|
||||
public string Token { get; set; } = default!;
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; } = default!;
|
||||
[Required]
|
||||
public string Username { get; set; }
|
||||
public string Username { get; set; } = default!;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ namespace API.DTOs.Account;
|
||||
public class ConfirmEmailUpdateDto
|
||||
{
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
[Required]
|
||||
public string Token { get; set; }
|
||||
public string Token { get; set; } = default!;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
public class ConfirmMigrationEmailDto
|
||||
{
|
||||
public string Email { get; set; }
|
||||
public string Token { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
public string Token { get; set; } = default!;
|
||||
}
|
||||
|
@ -5,10 +5,10 @@ namespace API.DTOs.Account;
|
||||
public class ConfirmPasswordResetDto
|
||||
{
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
[Required]
|
||||
public string Token { get; set; }
|
||||
public string Token { get; set; } = default!;
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -1,24 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using API.Entities.Enums;
|
||||
|
||||
namespace API.DTOs.Account;
|
||||
|
||||
public class InviteUserDto
|
||||
{
|
||||
[Required]
|
||||
public string Email { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// List of Roles to assign to user. If admin not present, Pleb will be applied.
|
||||
/// If admin present, all libraries will be granted access and will ignore those from DTO.
|
||||
/// </summary>
|
||||
public ICollection<string> Roles { get; init; }
|
||||
public ICollection<string> Roles { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// A list of libraries to grant access to
|
||||
/// </summary>
|
||||
public IList<int> Libraries { get; init; }
|
||||
public IList<int> Libraries { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// An Age Rating which will limit the account to seeing everything equal to or below said rating.
|
||||
/// </summary>
|
||||
public AgeRestrictionDto AgeRestriction { get; set; }
|
||||
public AgeRestrictionDto AgeRestriction { get; set; } = default!;
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ public class InviteUserResponse
|
||||
/// <summary>
|
||||
/// Email link used to setup the user account
|
||||
/// </summary>
|
||||
public string EmailLink { get; set; }
|
||||
public string EmailLink { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Was an email sent (ie is this server accessible)
|
||||
/// </summary>
|
||||
public bool EmailSent { get; set; }
|
||||
public bool EmailSent { get; set; } = default!;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
public class LoginDto
|
||||
{
|
||||
public string Username { get; init; }
|
||||
public string Password { get; set; }
|
||||
public string Username { get; init; } = default!;
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
public class MigrateUserEmailDto
|
||||
{
|
||||
public string Email { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool SendEmail { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
public string Username { get; set; } = default!;
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -8,15 +8,15 @@ public class ResetPasswordDto
|
||||
/// The Username of the User
|
||||
/// </summary>
|
||||
[Required]
|
||||
public string UserName { get; init; }
|
||||
public string UserName { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// The new password
|
||||
/// </summary>
|
||||
[Required]
|
||||
[StringLength(32, MinimumLength = 6)]
|
||||
public string Password { get; init; }
|
||||
public string Password { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// The old, existing password. If an admin is performing the change, this is not required. Otherwise, it is.
|
||||
/// </summary>
|
||||
public string OldPassword { get; init; }
|
||||
public string OldPassword { get; init; } = default!;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
public class TokenRequestDto
|
||||
{
|
||||
public string Token { get; init; }
|
||||
public string RefreshToken { get; init; }
|
||||
public string Token { get; init; } = default!;
|
||||
public string RefreshToken { get; init; } = default!;
|
||||
}
|
||||
|
@ -2,6 +2,6 @@
|
||||
|
||||
public class UpdateEmailDto
|
||||
{
|
||||
public string Email { get; set; }
|
||||
public string Password { get; set; }
|
||||
public string Email { get; set; } = default!;
|
||||
public string Password { get; set; } = default!;
|
||||
}
|
||||
|
@ -1,24 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using API.Entities.Enums;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||
|
||||
namespace API.DTOs.Account;
|
||||
|
||||
public record UpdateUserDto
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Username { get; set; } = default!;
|
||||
/// List of Roles to assign to user. If admin not present, Pleb will be applied.
|
||||
/// If admin present, all libraries will be granted access and will ignore those from DTO.
|
||||
public IList<string> Roles { get; init; }
|
||||
public IList<string> Roles { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// A list of libraries to grant access to
|
||||
/// </summary>
|
||||
public IList<int> Libraries { get; init; }
|
||||
public IList<int> Libraries { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// An Age Rating which will limit the account to seeing everything equal to or below said rating.
|
||||
/// </summary>
|
||||
public AgeRestrictionDto AgeRestriction { get; init; }
|
||||
public AgeRestrictionDto AgeRestriction { get; init; } = default!;
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using API.Entities.Enums;
|
||||
using API.Entities.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
|
||||
namespace API.DTOs;
|
||||
|
||||
@ -16,11 +15,11 @@ public class ChapterDto : IHasReadTimeEstimate, IEntityDate
|
||||
/// <summary>
|
||||
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2".
|
||||
/// </summary>
|
||||
public string Range { get; init; }
|
||||
public string Range { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// Smallest number of the Range.
|
||||
/// </summary>
|
||||
public string Number { get; init; }
|
||||
public string Number { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// Total number of pages in all MangaFiles
|
||||
/// </summary>
|
||||
@ -32,11 +31,11 @@ public class ChapterDto : IHasReadTimeEstimate, IEntityDate
|
||||
/// <summary>
|
||||
/// Used for books/specials to display custom title. For non-specials/books, will be set to <see cref="Range"/>
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
public string Title { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// The files that represent this Chapter
|
||||
/// </summary>
|
||||
public ICollection<MangaFileDto> Files { get; init; }
|
||||
public ICollection<MangaFileDto> Files { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// Calculated at API time. Number of pages read for this Chapter for logged in user.
|
||||
/// </summary>
|
||||
@ -69,12 +68,12 @@ public class ChapterDto : IHasReadTimeEstimate, IEntityDate
|
||||
/// Title of the Chapter/Issue
|
||||
/// </summary>
|
||||
/// <remarks>Metadata field</remarks>
|
||||
public string TitleName { get; set; }
|
||||
public string TitleName { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Summary of the Chapter
|
||||
/// </summary>
|
||||
/// <remarks>This is not set normally, only for Series Detail</remarks>
|
||||
public string Summary { get; init; }
|
||||
public string Summary { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// Age Rating for the issue/chapter
|
||||
/// </summary>
|
||||
|
@ -9,9 +9,9 @@ public class CollectionTagBulkAddDto
|
||||
/// </summary>
|
||||
/// <remarks>Can be 0 which then will use Title to create a tag</remarks>
|
||||
public int CollectionTagId { get; init; }
|
||||
public string CollectionTagTitle { get; init; }
|
||||
public string CollectionTagTitle { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// Series Ids to add onto Collection Tag
|
||||
/// </summary>
|
||||
public IEnumerable<int> SeriesIds { get; init; }
|
||||
public IEnumerable<int> SeriesIds { get; init; } = default!;
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
public class CollectionTagDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Summary { get; set; }
|
||||
public string Title { get; set; } = default!;
|
||||
public string Summary { get; set; } = default!;
|
||||
public bool Promoted { get; set; }
|
||||
/// <summary>
|
||||
/// The cover image string. This is used on Frontend to show or hide the Cover Image
|
||||
/// </summary>
|
||||
public string CoverImage { get; set; }
|
||||
public string CoverImage { get; set; } = default!;
|
||||
public bool CoverImageLocked { get; set; }
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ namespace API.DTOs.CollectionTags;
|
||||
|
||||
public class UpdateSeriesForTagDto
|
||||
{
|
||||
public CollectionTagDto Tag { get; init; }
|
||||
public IEnumerable<int> SeriesIdsToRemove { get; init; }
|
||||
public CollectionTagDto Tag { get; init; } = default!;
|
||||
public IEnumerable<int> SeriesIdsToRemove { get; init; } = default!;
|
||||
}
|
||||
|
@ -7,10 +7,10 @@ namespace API.DTOs;
|
||||
public class CreateLibraryDto
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; init; }
|
||||
public string Name { get; init; } = default!;
|
||||
[Required]
|
||||
public LibraryType Type { get; init; }
|
||||
[Required]
|
||||
[MinLength(1)]
|
||||
public IEnumerable<string> Folders { get; init; }
|
||||
public IEnumerable<string> Folders { get; init; } = default!;
|
||||
}
|
||||
|
@ -4,5 +4,5 @@ namespace API.DTOs;
|
||||
|
||||
public class DeleteSeriesDto
|
||||
{
|
||||
public IList<int> SeriesIds { get; set; }
|
||||
public IList<int> SeriesIds { get; set; } = default!;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Runtime.InteropServices;
|
||||
using API.Entities.Enums.Device;
|
||||
|
||||
namespace API.DTOs.Device;
|
||||
@ -7,14 +6,14 @@ namespace API.DTOs.Device;
|
||||
public class CreateDeviceDto
|
||||
{
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Platform of the device. If not know, defaults to "Custom"
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DevicePlatform Platform { get; set; }
|
||||
[Required]
|
||||
public string EmailAddress { get; set; }
|
||||
public string EmailAddress { get; set; } = default!;
|
||||
|
||||
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ public class DeviceDto
|
||||
/// </summary>
|
||||
/// <remarks>If this device is web, this will be the browser name</remarks>
|
||||
/// <example>Pixel 3a, John's Kindle</example>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// An email address associated with the device (ie Kindle). Will be used with Send to functionality
|
||||
/// </summary>
|
||||
public string EmailAddress { get; set; }
|
||||
public string EmailAddress { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Platform (ie) Windows 10
|
||||
/// </summary>
|
||||
|
@ -5,5 +5,5 @@ namespace API.DTOs.Device;
|
||||
public class SendToDeviceDto
|
||||
{
|
||||
public int DeviceId { get; set; }
|
||||
public IReadOnlyList<int> ChapterIds { get; set; }
|
||||
public IReadOnlyList<int> ChapterIds { get; set; } = default!;
|
||||
}
|
||||
|
@ -8,12 +8,12 @@ public class UpdateDeviceDto
|
||||
[Required]
|
||||
public int Id { get; set; }
|
||||
[Required]
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = default!;
|
||||
/// <summary>
|
||||
/// Platform of the device. If not know, defaults to "Custom"
|
||||
/// </summary>
|
||||
[Required]
|
||||
public DevicePlatform Platform { get; set; }
|
||||
[Required]
|
||||
public string EmailAddress { get; set; }
|
||||
public string EmailAddress { get; set; } = default!;
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ namespace API.DTOs.Downloads;
|
||||
public class DownloadBookmarkDto
|
||||
{
|
||||
[Required]
|
||||
public IEnumerable<BookmarkDto> Bookmarks { get; set; }
|
||||
public IEnumerable<BookmarkDto> Bookmarks { get; set; } = default!;
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
public class ConfirmationEmailDto
|
||||
{
|
||||
public string InvitingUser { get; init; }
|
||||
public string EmailAddress { get; init; }
|
||||
public string ServerConfirmationLink { get; init; }
|
||||
public string InvitingUser { get; init; } = default!;
|
||||
public string EmailAddress { get; init; } = default!;
|
||||
public string ServerConfirmationLink { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// InstallId of this Kavita Instance
|
||||
/// </summary>
|
||||
public string InstallId { get; init; }
|
||||
public string InstallId { get; init; } = default!;
|
||||
}
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
public class EmailMigrationDto
|
||||
{
|
||||
public string EmailAddress { get; init; }
|
||||
public string Username { get; init; }
|
||||
public string ServerConfirmationLink { get; init; }
|
||||
public string EmailAddress { get; init; } = default!;
|
||||
public string Username { get; init; } = default!;
|
||||
public string ServerConfirmationLink { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// InstallId of this Kavita Instance
|
||||
/// </summary>
|
||||
public string InstallId { get; init; }
|
||||
public string InstallId { get; init; } = default!;
|
||||
}
|
||||
|
@ -6,5 +6,5 @@
|
||||
public class EmailTestResultDto
|
||||
{
|
||||
public bool Successful { get; set; }
|
||||
public string ErrorMessage { get; set; }
|
||||
public string ErrorMessage { get; set; } = default!;
|
||||
}
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
public class PasswordResetEmailDto
|
||||
{
|
||||
public string EmailAddress { get; init; }
|
||||
public string ServerConfirmationLink { get; init; }
|
||||
public string EmailAddress { get; init; } = default!;
|
||||
public string ServerConfirmationLink { get; init; } = default!;
|
||||
/// <summary>
|
||||
/// InstallId of this Kavita Instance
|
||||
/// </summary>
|
||||
public string InstallId { get; init; }
|
||||
public string InstallId { get; init; } = default!;
|
||||
}
|
||||
|
@ -4,6 +4,6 @@ namespace API.DTOs.Email;
|
||||
|
||||
public class SendToDto
|
||||
{
|
||||
public string DestinationEmail { get; set; }
|
||||
public IEnumerable<string> FilePaths { get; set; }
|
||||
public string DestinationEmail { get; set; } = default!;
|
||||
public IEnumerable<string> FilePaths { get; set; } = default!;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user