Compare commits
No commits in common. "b001e215fef08219f8b5fcf76d24f17dd5f3d081" and "main" have entirely different histories.
b001e215fe
...
main
42
.gitignore
vendored
42
.gitignore
vendored
@ -1,7 +1,8 @@
|
|||||||
|
# ---> VisualStudio
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
##
|
##
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
@ -91,6 +92,7 @@ StyleCopReport.xml
|
|||||||
*.tmp_proj
|
*.tmp_proj
|
||||||
*_wpftmp.csproj
|
*_wpftmp.csproj
|
||||||
*.log
|
*.log
|
||||||
|
*.tlog
|
||||||
*.vspscc
|
*.vspscc
|
||||||
*.vssscc
|
*.vssscc
|
||||||
.builds
|
.builds
|
||||||
@ -294,6 +296,17 @@ node_modules/
|
|||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
*.vbw
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
||||||
|
*.vbp
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
||||||
|
*.dsw
|
||||||
|
*.dsp
|
||||||
|
|
||||||
|
# Visual Studio 6 technical files
|
||||||
|
*.ncb
|
||||||
|
*.aps
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# Visual Studio LightSwitch build output
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
@ -350,6 +363,9 @@ ASALocalRun/
|
|||||||
# Local History for Visual Studio
|
# Local History for Visual Studio
|
||||||
.localhistory/
|
.localhistory/
|
||||||
|
|
||||||
|
# Visual Studio History (VSHistory) files
|
||||||
|
.vshistory/
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
# BeatPulse healthcheck temp database
|
||||||
healthchecksdb
|
healthchecksdb
|
||||||
|
|
||||||
@ -360,4 +376,26 @@ MigrationBackup/
|
|||||||
.ionide/
|
.ionide/
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
# VS Code files for those working on multiple tools
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# Windows Installer files from build outputs
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
|||||||
13
.idea/.idea.MyBookmark/.idea/.gitignore
generated
vendored
Normal file
13
.idea/.idea.MyBookmark/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/contentModel.xml
|
||||||
|
/.idea.MyBookmark.iml
|
||||||
|
/modules.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
8
.idea/.idea.MyBookmark/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.MyBookmark/.idea/indexLayout.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/.idea.MyBookmark/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.MyBookmark/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace Common.Application.DomainEvents.Abstractions;
|
||||||
|
|
||||||
|
public interface IHasDomainEvents
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
9
Common.Application/Common.Application.csproj
Normal file
9
Common.Application/Common.Application.csproj
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
9
Common.Application/Exceptions/AppException.cs
Normal file
9
Common.Application/Exceptions/AppException.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace Common.WebApi.Exceptions;
|
||||||
|
|
||||||
|
public abstract class AppException( string errorCode, string message, int statusCode,
|
||||||
|
params object[]? formatArgs) : Exception(message)
|
||||||
|
{
|
||||||
|
public string ErrorCode { get; } = errorCode;
|
||||||
|
public int StatusCode { get; } = statusCode;
|
||||||
|
public object[]? FormatArgs { get; } = formatArgs;
|
||||||
|
}
|
||||||
0
Common.Application/Resources/Errors.cs
Normal file
0
Common.Application/Resources/Errors.cs
Normal file
0
Common.Application/Resources/Errors.en.resx
Normal file
0
Common.Application/Resources/Errors.en.resx
Normal file
24
Common.Application/Resources/Errors.resx
Normal file
24
Common.Application/Resources/Errors.resx
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<root>
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>1.3</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<data name="UnexpectedError" xml:space="preserve">
|
||||||
|
<value>An unexpected error has occurred</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
0
Common.Application/Resources/Errors.ru.resx
Normal file
0
Common.Application/Resources/Errors.ru.resx
Normal file
0
Common.Domain/Abstractions/IDomainEvent.cs
Normal file
0
Common.Domain/Abstractions/IDomainEvent.cs
Normal file
0
Common.Domain/AggregateRoot.cs
Normal file
0
Common.Domain/AggregateRoot.cs
Normal file
9
Common.Security/Common.Security.csproj
Normal file
9
Common.Security/Common.Security.csproj
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
0
Common.Security/Configuration/JwtSettings.cs
Normal file
0
Common.Security/Configuration/JwtSettings.cs
Normal file
0
Common.Security/Constants.cs
Normal file
0
Common.Security/Constants.cs
Normal file
0
Common.Security/Exceptions/ForbiddenException.cs
Normal file
0
Common.Security/Exceptions/ForbiddenException.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace Common.Security.Infrastructure.Mediatr;
|
||||||
|
|
||||||
|
public interface IRequirePermission
|
||||||
|
{
|
||||||
|
string PermissionCode { get; }
|
||||||
|
}
|
||||||
0
Common.Security/Infrastructure/UserContext.cs
Normal file
0
Common.Security/Infrastructure/UserContext.cs
Normal file
0
Common.Security/Interfaces/IUserContext.cs
Normal file
0
Common.Security/Interfaces/IUserContext.cs
Normal file
0
Common.Security/Models/Location.cs
Normal file
0
Common.Security/Models/Location.cs
Normal file
0
Common.Security/ServiceCollectionExtensions.cs
Normal file
0
Common.Security/ServiceCollectionExtensions.cs
Normal file
13
Common.WebApi/Common.WebApi.csproj
Normal file
13
Common.WebApi/Common.WebApi.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="MongoDB.Driver" Version="2.29.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
89
Common.WebApi/Middlewares/ExceptionMiddleware.cs
Normal file
89
Common.WebApi/Middlewares/ExceptionMiddleware.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MongoDB.Driver;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace Common.WebApi.Middlewares;
|
||||||
|
|
||||||
|
public class ExceptionMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
private readonly IHostEnvironment _host;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly JsonSerializerOptions _serializerOptions;
|
||||||
|
|
||||||
|
public ExceptionMiddleware(RequestDelegate next, IHostEnvironment host, ILogger<ExceptionMiddleware> logger)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_next = next;
|
||||||
|
_host = host;
|
||||||
|
_serializerOptions = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
Converters = {
|
||||||
|
new JsonStringEnumConverter()
|
||||||
|
},
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InvokeAsync(HttpContext httpContext)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//if (httpContext.Request.Method == "POST")
|
||||||
|
//{
|
||||||
|
// using var streamreader = new System.IO.StreamReader(httpContext.Request.Body);
|
||||||
|
// var body = await streamreader.ReadToEndAsync();
|
||||||
|
//}
|
||||||
|
await _next(httpContext);
|
||||||
|
}
|
||||||
|
catch (Exception exc)
|
||||||
|
{
|
||||||
|
var title = exc.Message;
|
||||||
|
var detail = "Unexpected error occured";
|
||||||
|
if (!_host.IsProduction()) detail = GetExceptionDetail(exc, false, true);
|
||||||
|
if (exc is MongoException dbUpdateException)
|
||||||
|
{
|
||||||
|
title = "Database error";
|
||||||
|
if (!_host.IsProduction()) detail = GetExceptionDetail(dbUpdateException, true, true);
|
||||||
|
}
|
||||||
|
else if (exc.Source?.Contains("Mongo") == true)
|
||||||
|
{
|
||||||
|
title = "Database error";
|
||||||
|
if (!_host.IsProduction()) detail = GetExceptionDetail(exc, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var problemDetail = new ProblemDetails
|
||||||
|
{
|
||||||
|
Title = title,
|
||||||
|
Detail = detail,
|
||||||
|
Instance = httpContext.Request.Path,
|
||||||
|
Status = StatusCodes.Status400BadRequest
|
||||||
|
};
|
||||||
|
|
||||||
|
_logger.LogError("Необработанная ошибка: {Message}", exc.Message);
|
||||||
|
httpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
httpContext.Response.ContentType = "application/problem+json";
|
||||||
|
await httpContext.Response.WriteAsync(JsonSerializer.Serialize(problemDetail, _serializerOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExceptionDetail(Exception exc, bool includeMessage, bool includeInner)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
if (!string.IsNullOrWhiteSpace(exc.Message) && includeMessage) sb.Append(exc.Message);
|
||||||
|
if (!string.IsNullOrWhiteSpace(exc.InnerException?.Message) && includeInner)
|
||||||
|
{
|
||||||
|
if (sb.Length > 0) sb.AppendLine();
|
||||||
|
sb.AppendLine("Inner:");
|
||||||
|
sb.Append(exc.InnerException.Message);
|
||||||
|
}
|
||||||
|
if (sb.Length > 0) sb.AppendLine();
|
||||||
|
sb.Append(exc.StackTrace);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Common.WebApi/ServiceCollectionExtensions.cs
Normal file
24
Common.WebApi/ServiceCollectionExtensions.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace Common.WebApi;
|
||||||
|
|
||||||
|
public static class DependencyInjectionExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddApplicationDatabase(this IServiceCollection services, string? connectionString)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullException(nameof(connectionString));
|
||||||
|
|
||||||
|
services.AddDbContext<UserDbContext>(options =>
|
||||||
|
{
|
||||||
|
options.UseNpgsql(connectionString, q =>
|
||||||
|
{
|
||||||
|
q.MigrationsAssembly(Assembly.GetAssembly(typeof(UserDbContext))!.GetName().Name);
|
||||||
|
q.MigrationsHistoryTable("__Migrations");
|
||||||
|
});
|
||||||
|
//options.UseNpgsql(connectionString);
|
||||||
|
//AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true); //Включаем UTC-время.
|
||||||
|
//options.UseLazyLoadingProxies(); // lazy loading
|
||||||
|
});
|
||||||
|
AddRepositories(services);
|
||||||
|
// AddGateways(services);
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
ExcelTableImporter/AnimeLibraryEditor.cs
Normal file
0
ExcelTableImporter/AnimeLibraryEditor.cs
Normal file
16
ExcelTableImporter/CommandHandlerFactory.cs
Normal file
16
ExcelTableImporter/CommandHandlerFactory.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using ExcelTableImporter.Models.ExcelModels;
|
||||||
|
|
||||||
|
namespace ExcelTableImporter.Commands;
|
||||||
|
|
||||||
|
public class CommandHandlerFactory(AnimeLibrary library)
|
||||||
|
{
|
||||||
|
public ICommandHandler? GetHandler(ICommand command)
|
||||||
|
{
|
||||||
|
return command switch
|
||||||
|
{
|
||||||
|
ExitCommand exitCommand => new ExitCommandHandler(library, exitCommand),
|
||||||
|
ListCommand listCommand => new ListCommandHandler(library, listCommand),
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
0
ExcelTableImporter/Commands/ExitCommand.cs
Normal file
0
ExcelTableImporter/Commands/ExitCommand.cs
Normal file
0
ExcelTableImporter/Commands/ListCommand.cs
Normal file
0
ExcelTableImporter/Commands/ListCommand.cs
Normal file
0
ExcelTableImporter/Commands/MergeCommand.cs
Normal file
0
ExcelTableImporter/Commands/MergeCommand.cs
Normal file
0
ExcelTableImporter/Commands/SaveCommand.cs
Normal file
0
ExcelTableImporter/Commands/SaveCommand.cs
Normal file
0
ExcelTableImporter/Commands/SetCommand.cs
Normal file
0
ExcelTableImporter/Commands/SetCommand.cs
Normal file
0
ExcelTableImporter/Commands/SplitCommand.cs
Normal file
0
ExcelTableImporter/Commands/SplitCommand.cs
Normal file
0
ExcelTableImporter/Commands/SplitExpandCommand.cs
Normal file
0
ExcelTableImporter/Commands/SplitExpandCommand.cs
Normal file
33
ExcelTableImporter/ICommand.cs
Normal file
33
ExcelTableImporter/ICommand.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using ExcelTableImporter.Models.ExcelModels;
|
||||||
|
|
||||||
|
namespace ExcelTableImporter.Commands;
|
||||||
|
|
||||||
|
public interface ICommand
|
||||||
|
{
|
||||||
|
string HelpText { get; }
|
||||||
|
string UsageText { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ICommandHandler
|
||||||
|
{
|
||||||
|
void Handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AnimeLibraryCommandHandlerBase<T>(AnimeLibrary library, T command) : ICommandHandler
|
||||||
|
where T : ICommand
|
||||||
|
{
|
||||||
|
protected readonly AnimeLibrary Library = library;
|
||||||
|
|
||||||
|
public void Handle()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Handle(command);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected abstract void Handle(T command);
|
||||||
|
}
|
||||||
177
ExcelTableImporter/LibraryLoader.cs
Normal file
177
ExcelTableImporter/LibraryLoader.cs
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using ExcelTableImporter.Models.ExcelModels;
|
||||||
|
using ExcelTableImporter.Models.ExcelModels.ExcelModels;
|
||||||
|
using NPOI.SS.UserModel;
|
||||||
|
|
||||||
|
namespace ExcelTableImporter;
|
||||||
|
|
||||||
|
public class LibrayLoader
|
||||||
|
{
|
||||||
|
public async Task<AnimeLibrary> LoadLibrary(string filePath)
|
||||||
|
{
|
||||||
|
var animeRows = await ReadExcelFile(filePath);
|
||||||
|
return MakeLibrary(animeRows);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<AnimeRow>> ReadExcelFile(string filePath)
|
||||||
|
{
|
||||||
|
await using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
IWorkbook workbook = WorkbookFactory.Create(stream);
|
||||||
|
var sheet = workbook.GetSheetAt(0);
|
||||||
|
|
||||||
|
var animeRows = new List<AnimeRow>();
|
||||||
|
for (var i = 1; i <= sheet.LastRowNum; i++)
|
||||||
|
{
|
||||||
|
var row = sheet.GetRow(i);
|
||||||
|
var isEmpty = row.GetCell(0) is null
|
||||||
|
&& row.GetCell(1) is null
|
||||||
|
&& row.GetCell(2) is null
|
||||||
|
&& row.GetCell(3) is null
|
||||||
|
&& row.GetCell(4) is null
|
||||||
|
&& row.GetCell(8) is null
|
||||||
|
&& row.GetCell(9) is null;
|
||||||
|
|
||||||
|
if (isEmpty) continue;
|
||||||
|
var c1 = row.GetCell(0)?.ToString(); // russian name
|
||||||
|
var c2 = row.GetCell(1)?.ToString(); // original name
|
||||||
|
var c3 = TryShort(row.GetCell(2)); // release year
|
||||||
|
var c4 = ReadSerialsCount(row.GetCell(3)); // formula cell
|
||||||
|
var c5 = ReadSerialsCount(row.GetCell(4)); // series viewed
|
||||||
|
var c6 = row.GetCell(6)?.ToString(); // is completed
|
||||||
|
var c7 = TryShort(row.GetCell(8)); // rating
|
||||||
|
var c8 = row.GetCell(9)?.ToString(); // comment
|
||||||
|
// var str = $"{c1} | {c2} [{c3}] - {c4} - : — {c5} — [{c6}] [{c7}]; {c8}";
|
||||||
|
|
||||||
|
animeRows.Add(new AnimeRow
|
||||||
|
{
|
||||||
|
NameRussian = c1,
|
||||||
|
NameOriginal = c2,
|
||||||
|
ReleaseYear = c3,
|
||||||
|
AnimeSeriesCountItems = ParseFormula(c4),
|
||||||
|
AnimeSeriesViewsCountItems = ParseFormula(c5),
|
||||||
|
IsCompleted = c6 == "Да",
|
||||||
|
RatingValue = c7,
|
||||||
|
Comment = c8,
|
||||||
|
});
|
||||||
|
// Console.WriteLine(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
return animeRows;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimeLibrary MakeLibrary(List<AnimeRow> animeRows)
|
||||||
|
{
|
||||||
|
var animeTitles = new Dictionary<string, AnimeTitle>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
foreach (var row in animeRows)
|
||||||
|
{
|
||||||
|
if (!animeTitles.TryGetValue(row.NameOriginal, out var title))
|
||||||
|
{
|
||||||
|
title = new AnimeTitle
|
||||||
|
{
|
||||||
|
NameRussian = row.NameRussian,
|
||||||
|
NameOriginal = row.NameOriginal,
|
||||||
|
ReleaseYear = row.ReleaseYear,
|
||||||
|
RatingValue = row.RatingValue,
|
||||||
|
Comment = row.Comment
|
||||||
|
};
|
||||||
|
|
||||||
|
animeTitles[row.NameOriginal] = title;
|
||||||
|
}
|
||||||
|
|
||||||
|
var part = new AnimePart
|
||||||
|
{
|
||||||
|
ReleaseYear = row.ReleaseYear,
|
||||||
|
Type = DetectPartType(row.NameRussian, row.NameOriginal),
|
||||||
|
SeasonNumber = DetectSeasonNumber(row.NameRussian)
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var item in row.AnimeSeriesCountItems)
|
||||||
|
{
|
||||||
|
part.EpisodeGroups.Add(new AnimeEpisodeGroup
|
||||||
|
{
|
||||||
|
Order = item.Order,
|
||||||
|
Count = item.Count,
|
||||||
|
Viewed = row.AnimeSeriesViewsCountItems
|
||||||
|
.FirstOrDefault(v => v.Order == item.Order)?.Count ?? 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
title.Parts.Add(part);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new AnimeLibrary
|
||||||
|
{
|
||||||
|
Titles = animeTitles.Values.ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static short? TryShort(ICell? cell)
|
||||||
|
{
|
||||||
|
if (cell == null) return null;
|
||||||
|
if (cell.CellType == CellType.Numeric) return Convert.ToInt16(cell.NumericCellValue);
|
||||||
|
if (short.TryParse(cell.ToString(), out var v)) return v;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static string? ReadSerialsCount(ICell? cell)
|
||||||
|
{
|
||||||
|
if (cell == null) return null;
|
||||||
|
return cell.CellType switch
|
||||||
|
{
|
||||||
|
CellType.Numeric => cell.NumericCellValue.ToString(CultureInfo.InvariantCulture),
|
||||||
|
CellType.Formula => cell.CellFormula,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<AnimeSeriesCountItem> ParseFormula(string? formula)
|
||||||
|
{
|
||||||
|
var result = new List<AnimeSeriesCountItem>();
|
||||||
|
if (string.IsNullOrWhiteSpace(formula)) return result;
|
||||||
|
formula = formula.TrimStart('=');
|
||||||
|
|
||||||
|
var parts = formula.Split('+', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
var order = 1;
|
||||||
|
foreach (var p in parts)
|
||||||
|
{
|
||||||
|
if (int.TryParse(p, out var count))
|
||||||
|
{
|
||||||
|
result.Add(new AnimeSeriesCountItem
|
||||||
|
{
|
||||||
|
Order = order++,
|
||||||
|
Count = count
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AnimePartType DetectPartType(string nameRu, string nameOrig)
|
||||||
|
{
|
||||||
|
var name = (nameRu + " " + nameOrig).ToLowerInvariant();
|
||||||
|
|
||||||
|
if (name.Contains("фильм") || name.Contains("movie") || name.Contains("gekijouban"))
|
||||||
|
return AnimePartType.Movie;
|
||||||
|
|
||||||
|
if (name.Contains("ova"))
|
||||||
|
return AnimePartType.Ova;
|
||||||
|
|
||||||
|
if (name.Contains("special") || name.Contains("спешл"))
|
||||||
|
return AnimePartType.Special;
|
||||||
|
|
||||||
|
return AnimePartType.Season;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int? DetectSeasonNumber(string nameRu)
|
||||||
|
{
|
||||||
|
var match = Regex.Match(nameRu, @"сезон\s*(\d+)", RegexOptions.IgnoreCase);
|
||||||
|
if (match.Success && int.TryParse(match.Groups[1].Value, out var num))
|
||||||
|
return num;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
ExcelTableImporter/Models/AnimeTitle.cs
Normal file
37
ExcelTableImporter/Models/AnimeTitle.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace ExcelTableImporter.Models.ExcelModels;
|
||||||
|
|
||||||
|
public class AnimeTitle
|
||||||
|
{
|
||||||
|
public string NameRussian { get; set; } = null!;
|
||||||
|
public string NameOriginal { get; set; } = null!;
|
||||||
|
public int ReleaseYear { get; set; }
|
||||||
|
public List<AnimePart> Parts { get; set; } = [];
|
||||||
|
public bool IsCompleted { get; set; }
|
||||||
|
public int RatingValue { get; set; }
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnimePart
|
||||||
|
{
|
||||||
|
public AnimePartType Type { get; set; }
|
||||||
|
public int? SeasonNumber { get; set; }
|
||||||
|
public int ReleaseYear { get; set; }
|
||||||
|
public List<AnimeEpisodeGroup> EpisodeGroups { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AnimePartType
|
||||||
|
{
|
||||||
|
Season,
|
||||||
|
RegularEpisode,
|
||||||
|
Movie,
|
||||||
|
Ova,
|
||||||
|
Special,
|
||||||
|
Unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnimeEpisodeGroup
|
||||||
|
{
|
||||||
|
public int Order { get; set; }
|
||||||
|
public int Count { get; set; }
|
||||||
|
public int Viewed { get; set; }
|
||||||
|
}
|
||||||
0
ExcelTableImporter/Models/ExcelModels/AnimeRow.cs
Normal file
0
ExcelTableImporter/Models/ExcelModels/AnimeRow.cs
Normal file
0
Modules.Library.Application/Clients/UserClient.cs
Normal file
0
Modules.Library.Application/Clients/UserClient.cs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Application.Services;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Title;
|
||||||
|
|
||||||
|
public class AddEpisodeCommand : IRequest<Guid>, IDisposable, IAsyncDisposable
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
|
||||||
|
public IEnumerable<Name> Names { get; init; } = [];
|
||||||
|
public MediaInfo? Preview { get; set; }
|
||||||
|
public IEnumerable<Description> Descriptions { get; init; } = [];
|
||||||
|
public IEnumerable<Genre> Genres { get; init; } = [];
|
||||||
|
public List<MediaInfo> RelatedContent { get; init; } = [];
|
||||||
|
|
||||||
|
public DateTimeOffset? AnnouncementDate { get; init; }
|
||||||
|
public DateTimeOffset? ExpectedReleaseDate { get; init; }
|
||||||
|
public DateTimeOffset ReleaseDate { get; init; }
|
||||||
|
|
||||||
|
public int? Number { get; init; }
|
||||||
|
public ushort? Order { get; init; }
|
||||||
|
public Models.AnimeEpisodeType Type { get; init; }
|
||||||
|
|
||||||
|
public TimeSpan? Duration { get; init; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (Preview != null && Preview.Data != null && Preview.Data.CanSeek)
|
||||||
|
{
|
||||||
|
Preview.Data.Dispose();
|
||||||
|
}
|
||||||
|
Preview = null;
|
||||||
|
foreach (var item in RelatedContent)
|
||||||
|
{
|
||||||
|
if (item.Data != null && item.Data.CanSeek)
|
||||||
|
{
|
||||||
|
item.Data.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RelatedContent.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (Preview != null && Preview.Data != null && Preview.Data.CanSeek)
|
||||||
|
{
|
||||||
|
await Preview.Data.DisposeAsync();
|
||||||
|
}
|
||||||
|
Preview = null;
|
||||||
|
foreach (var item in RelatedContent)
|
||||||
|
{
|
||||||
|
if (item.Data != null && item.Data.CanSeek)
|
||||||
|
{
|
||||||
|
await item.Data.DisposeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RelatedContent.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddEpisodeCommandHandler(IAnimeTitleGateway titleGateway, IAnimeEpisodeGateway episodeGateway, ILanguageGateway languageGateway,
|
||||||
|
IGenreGateway genreGateway, MediaInfoService mediaInfoService) : IRequestHandler<AddEpisodeCommand, Guid>
|
||||||
|
{
|
||||||
|
public async Task<Guid> Handle(AddEpisodeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId, cancellationToken);
|
||||||
|
//if (!request.Names.Any()) throw new Exception("No names");
|
||||||
|
|
||||||
|
var languages = (await languageGateway
|
||||||
|
.GetLanguageByIds(request.Names.Select(q => q.LanguageId).Distinct(), cancellationToken)).ToArray();
|
||||||
|
var genres = (await genreGateway
|
||||||
|
.GetGenreByIds(request.Genres.Select(q => q.GenreId).Distinct(), cancellationToken)).ToArray();
|
||||||
|
|
||||||
|
//var episode = title.AddEpisode((Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType)request.Type);
|
||||||
|
//replace type by tags
|
||||||
|
//var episodeType = request.Type switch
|
||||||
|
//{
|
||||||
|
// Models.AnimeEpisodeType.Regilar => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.Regilar,
|
||||||
|
// Models.AnimeEpisodeType.Ova => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.Ova,
|
||||||
|
// Models.AnimeEpisodeType.FullLength => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.FullLength,
|
||||||
|
// _ => throw new NotImplementedException()
|
||||||
|
//};
|
||||||
|
|
||||||
|
AnimeEpisode episode;
|
||||||
|
|
||||||
|
if (!request.Order.HasValue)
|
||||||
|
{
|
||||||
|
episode = title.AddEpisode((AnimeEpisodeType)request.Type, request.Names.Select(q =>
|
||||||
|
new Domain.Entities.MediaContent.CommonProperties.NameItem((Domain.Entities.MediaContent.CommonProperties.NameType)q.NameType,
|
||||||
|
languages.First(x => x.Id == q.LanguageId).Id, q.Value)), request.Number, request.Duration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
episode = title.AddEpisodeAsVariant((AnimeEpisodeType)request.Type, request.Names.Select(q =>
|
||||||
|
new Domain.Entities.MediaContent.CommonProperties.NameItem((Domain.Entities.MediaContent.CommonProperties.NameType)q.NameType,
|
||||||
|
languages.First(x => x.Id == q.LanguageId).Id, q.Value)), request.Order.Value, request.Number, request.Duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//var language = await languageGateway.GetLanguageById(request.NameLanguageId);
|
||||||
|
foreach (var name in request.Names)
|
||||||
|
{
|
||||||
|
var languageId = languages.First(x => x.Id == name.LanguageId).Id;
|
||||||
|
var type = (Domain.Entities.MediaContent.CommonProperties.NameType)name.NameType;
|
||||||
|
episode.CommonProperties.AddName(type, languageId, name.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Descriptions.Any())
|
||||||
|
{
|
||||||
|
foreach (var description in request.Descriptions)
|
||||||
|
{
|
||||||
|
var languageId = languages.First(q => q.Id == description.LanguageId).Id;
|
||||||
|
if (description.IsOriginal) episode.CommonProperties.AddOriginalDescription(languageId, description.Value);
|
||||||
|
else episode.CommonProperties.AddNotOriginalDescription(languageId, description.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.Genres.Any())
|
||||||
|
{
|
||||||
|
foreach (var genre in request.Genres)
|
||||||
|
{
|
||||||
|
var genreId = genres.First(q => q.Id == genre.GenreId).Id;
|
||||||
|
episode.CommonProperties.AddGenre(genreId, genre.Proportion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.RelatedContent.Any())
|
||||||
|
{
|
||||||
|
foreach (var relatedContentItem in request.RelatedContent)
|
||||||
|
{
|
||||||
|
//add model
|
||||||
|
var (objectId, contentType) = await mediaInfoService.Add(new MediaInfoService.CreateModel
|
||||||
|
{
|
||||||
|
Data = relatedContentItem.Data,
|
||||||
|
Url = relatedContentItem.Url,
|
||||||
|
ContentType = relatedContentItem.ContentType,
|
||||||
|
Type = (Domain.Entities.MediaInfoType)relatedContentItem.Type,
|
||||||
|
}, false, cancellationToken);
|
||||||
|
|
||||||
|
//objectId
|
||||||
|
episode.CommonProperties.AddRelatedContent(objectId, (Domain.Entities.MediaInfoType)relatedContentItem.Type, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
episode.CommonProperties.SetAnnouncementDate(request.AnnouncementDate);
|
||||||
|
episode.CommonProperties.SetExpectedReleaseDate(request.ExpectedReleaseDate);
|
||||||
|
episode.CommonProperties.SetReleaseDate(request.ReleaseDate);
|
||||||
|
var animeEpisodeId = await episodeGateway.Create(title.Id, null, episode, cancellationToken);
|
||||||
|
if (request.Preview != null)
|
||||||
|
{
|
||||||
|
title = await titleGateway.GetById(title.Id, cancellationToken);
|
||||||
|
episode = title.Items.OfType<AnimeEpisode>().First(q => q.Id == animeEpisodeId);
|
||||||
|
var (objectId, contentType) = await mediaInfoService.Add(new MediaInfoService.CreateModel
|
||||||
|
{
|
||||||
|
Id = animeEpisodeId,
|
||||||
|
Data = request.Preview.Data,
|
||||||
|
Url = request.Preview.Url,
|
||||||
|
ContentType = request.Preview.ContentType,
|
||||||
|
Type = (Domain.Entities.MediaInfoType)request.Preview.Type,
|
||||||
|
}, true, cancellationToken);
|
||||||
|
episode.CommonProperties.SetPreview(objectId, (Domain.Entities.MediaInfoType)request.Preview.Type, contentType);
|
||||||
|
await episodeGateway.Update(title.Id, null, episode, cancellationToken);
|
||||||
|
}
|
||||||
|
//return await titleGateway.Create(animeTitle);
|
||||||
|
return animeEpisodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Description;
|
||||||
|
|
||||||
|
public class AddDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddDescriptionCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<AddDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await languageGateway.IsLanguageExists(request.LanguageId)) throw new Exception();
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
if (request.IsOriginal) episode.CommonProperties.AddOriginalDescription(request.LanguageId, request.Value);
|
||||||
|
else episode.CommonProperties.AddNotOriginalDescription(request.LanguageId, request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Description;
|
||||||
|
|
||||||
|
public class DeleteDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteDescriptionCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
var description = new Domain.Entities.MediaContent.CommonProperties.Description(request.LanguageId, request.IsOriginal, request.Value);
|
||||||
|
episode.CommonProperties.RemoveDescription(description);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Description;
|
||||||
|
|
||||||
|
public class EditDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
public Guid? NewLanguageId { get; set; }
|
||||||
|
public string? NewValue { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditDescriptionCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<EditDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await languageGateway.IsLanguageExists(request.LanguageId)) throw new Exception("Language not exists");
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
var description = new Domain.Entities.MediaContent.CommonProperties.Description(request.LanguageId, request.IsOriginal, request.Value);
|
||||||
|
episode.CommonProperties.SetDescriptionValue(description, request.NewLanguageId, request.NewValue);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Genre;
|
||||||
|
|
||||||
|
public class AddGenreCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
public decimal? Proportion { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddGenreCommandHandler(IAnimeTitleGateway titleGateway, IGenreGateway genreGateway) : IRequestHandler<AddGenreCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddGenreCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await genreGateway.IsGenreExists(request.GenreId)) throw new Exception("NotFound");
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.AddGenre(request.GenreId, request.Proportion);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Genre;
|
||||||
|
|
||||||
|
public class DeleteGenreCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteGenreCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteGenreCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteGenreCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.RemoveGenre(request.GenreId);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Genre;
|
||||||
|
|
||||||
|
public class SetGenreProportionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
public decimal? Proportion { get; set; }
|
||||||
|
public decimal? NewProportion { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetGenreProportionCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetGenreProportionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetGenreProportionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetGenreProportion(request.GenreId, request.NewProportion);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Name;
|
||||||
|
|
||||||
|
public class AddNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddNameCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<AddNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var language = await languageGateway.GetLanguageById(request.LanguageId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.AddName((Domain.Entities.MediaContent.CommonProperties.NameType)request.NameType, language.Id, request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Name;
|
||||||
|
|
||||||
|
public class DeleteNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public CommonModels.NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteNameCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<DeleteNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var language = await languageGateway.GetLanguageById(request.LanguageId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.RemoveName(new NameItem((NameType)request.NameType, request.LanguageId, request.Value));
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Name;
|
||||||
|
|
||||||
|
public class EditNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public CommonModels.NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public string? NewValue { get; set; }
|
||||||
|
public Guid? NewLanguageId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditNameCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<EditNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!request.NewLanguageId.HasValue && string.IsNullOrWhiteSpace(request.NewValue))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"{nameof(EditNameCommand.NewLanguageId)}, {nameof(EditNameCommand.NewValue)}");
|
||||||
|
}
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetNameValue(new NameItem((NameType)request.NameType, request.LanguageId, request.Value), request.NewLanguageId, request.NewValue);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Preview;
|
||||||
|
|
||||||
|
public class DeletePreviewCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeletePreviewCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeletePreviewCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeletePreviewCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.DeletePreview();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.Preview;
|
||||||
|
|
||||||
|
public class SetPreviewCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetPreviewCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetPreviewCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetPreviewCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetPreview(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class AddRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<AddRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.AddRelatedContent(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class DeleteRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var mediaInfo = new Domain.Entities.MediaInfo(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.RemoveRelatedContent(mediaInfo);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class EditRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
public MediaInfoType NewType { get; set; }
|
||||||
|
public string NewUrl { get; set; } = default!;
|
||||||
|
public string NewContentType { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<EditRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var mediaInfo = new Domain.Entities.MediaInfo(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.EditRelatedContent(mediaInfo, request.NewUrl, (Domain.Entities.MediaInfoType)request.NewType, request.NewContentType);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetAnnouncementDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public DateTimeOffset? Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetAnnouncementDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetAnnouncementDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetAnnouncementDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetAnnouncementDate(request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetCompletedCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public bool Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetCompletedCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetCompletedCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetCompletedCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
if (request.Value) episode.SetCompleted();
|
||||||
|
else episode.SetNotCompleted();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetDurationCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
public Guid SeasonId { get; init; }
|
||||||
|
public Guid EpisodeId { get; init; }
|
||||||
|
public TimeSpan Duration { get; init; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetDurationCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetDurationCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetDurationCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.SetDuration(request.Duration);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetEstimatedReleaseDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public DateTimeOffset? Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetEstimatedReleaseDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetEstimatedReleaseDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetEstimatedReleaseDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetEstimatedReleaseDate(request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetExpirationTimeCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public TimeSpan ExpirationTime { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetExpirationTimeCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetExpirationTimeCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetExpirationTimeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.SetExpirationTime(request.ExpirationTime);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode.Properties;
|
||||||
|
|
||||||
|
public class SetReleaseDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
public DateTimeOffset? Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetReleaseDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetReleaseDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetReleaseDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var episode = season.Episodes.FirstOrDefault(q => q.Id == request.EpisodeId) ??
|
||||||
|
throw new Exception("Episode not found");
|
||||||
|
episode.CommonProperties.SetReleaseDate(request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Rating.Api.Commands;
|
||||||
|
using Modules.User.Application;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode;
|
||||||
|
|
||||||
|
public class UnvoteTitleCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnvoteEpisodeCommandHandler(IAnimeTitleGateway titleGateway, UserContext userContext, IMediator mediator) : IRequestHandler<UnvoteTitleCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(UnvoteTitleCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var user = await userContext.GetUserInfo(cancellationToken);
|
||||||
|
if (!user.IsAuthenticated || (!user.Id.HasValue || user.Id == Guid.Empty))
|
||||||
|
{
|
||||||
|
throw new Exception("User is not authenticated");
|
||||||
|
}
|
||||||
|
var subjectId = user.Id.Value;
|
||||||
|
var title = await titleGateway.GetById(request.TitleId, cancellationToken);
|
||||||
|
if (!title.Deleted)
|
||||||
|
{
|
||||||
|
await mediator.Send(new UnrateObjectCommand { ObjectId = title.Id, SubjectId = subjectId }, cancellationToken);
|
||||||
|
}
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Rating.Api.Commands;
|
||||||
|
using Modules.User.Application;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Episode;
|
||||||
|
|
||||||
|
public class VoteTitleCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; init; }
|
||||||
|
public Guid EpisodeId { get; init; }
|
||||||
|
public ushort RatingPercentage { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VoteTitleCommandHandler(IAnimeTitleGateway titleGateway, UserContext userContext, IMediator mediator) : IRequestHandler<VoteTitleCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(VoteTitleCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var user = await userContext.GetUserInfo(cancellationToken);
|
||||||
|
if (!user.IsAuthenticated || (!user.Id.HasValue || user.Id == Guid.Empty))
|
||||||
|
{
|
||||||
|
throw new Exception("User is not authenticated");
|
||||||
|
}
|
||||||
|
var subjectId = user.Id.Value;
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!title.Deleted)
|
||||||
|
{
|
||||||
|
await mediator.Send(new VoteForObjectCommand
|
||||||
|
{
|
||||||
|
ObjectId = title.Id,
|
||||||
|
SubjectId = subjectId,
|
||||||
|
RatingPercentage = request.RatingPercentage
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Modules.Library.Application.Commands.Anime.Models;
|
||||||
|
|
||||||
|
public enum AnimeEpisodeType
|
||||||
|
{
|
||||||
|
Regular,
|
||||||
|
Ova,
|
||||||
|
Ona,
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class AddEpisodeCommand : IRequest<Guid>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public AnimeEpisodeType Type { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AnimeEpisodeType
|
||||||
|
{
|
||||||
|
Regilar,
|
||||||
|
FullLength,
|
||||||
|
Ova,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddEpisodeCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<AddEpisodeCommand, Guid>
|
||||||
|
{
|
||||||
|
public async Task<Guid> Handle(AddEpisodeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().First(q => q.Id == request.SeasonId);
|
||||||
|
var episode = season.AddEpisode((Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType)request.Type);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return episode.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class CreateSeasonCommand : IRequest<Guid>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CreateSeasonCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<CreateSeasonCommand, Guid>
|
||||||
|
{
|
||||||
|
public async Task<Guid> Handle(CreateSeasonCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.AddSeason();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return season.Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class DeleteEpisodeCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid EpisodeId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteEpisodeCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteEpisodeCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteEpisodeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().First(q => q.Id == request.SeasonId);
|
||||||
|
var episode = season.Episodes.First(q => q.Id == request.EpisodeId);
|
||||||
|
episode.Delete();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class DeleteSeasonCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteSeasonCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteSeasonCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteSeasonCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.Delete();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Description;
|
||||||
|
|
||||||
|
public class AddDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddDescriptionCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<AddDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await languageGateway.IsLanguageExists(request.LanguageId)) throw new Exception();
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
if (request.IsOriginal) season.CommonProperties.AddOriginalDescription(request.LanguageId, request.Value);
|
||||||
|
else season.CommonProperties.AddNotOriginalDescription(request.LanguageId, request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Description;
|
||||||
|
|
||||||
|
public class DeleteDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteDescriptionCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
var description = new Domain.Entities.MediaContent.CommonProperties.Description(request.LanguageId, request.IsOriginal, request.Value);
|
||||||
|
season.CommonProperties.RemoveDescription(description);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Description;
|
||||||
|
|
||||||
|
public class EditDescriptionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public bool IsOriginal { get; set; }
|
||||||
|
public string? NewValue { get; set; }
|
||||||
|
public Guid? NewLanguageId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditDescriptionCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<EditDescriptionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditDescriptionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await languageGateway.IsLanguageExists(request.LanguageId)) throw new Exception("Language not exists");
|
||||||
|
var description = new Domain.Entities.MediaContent.CommonProperties.Description(request.LanguageId, request.IsOriginal, request.Value);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetDescriptionValue(description, request.NewLanguageId, request.NewValue);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Genre;
|
||||||
|
|
||||||
|
public class AddGenreCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
public decimal? Proportion { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddGenreCommandHandler(IAnimeTitleGateway titleGateway, IGenreGateway genreGateway) : IRequestHandler<AddGenreCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddGenreCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!await genreGateway.IsGenreExists(request.GenreId)) throw new Exception("NotFound");
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.AddGenre(request.GenreId, request.Proportion);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Genre;
|
||||||
|
|
||||||
|
public class DeleteGenreCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteGenreCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteGenreCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteGenreCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.RemoveGenre(request.GenreId);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Genre;
|
||||||
|
|
||||||
|
public class SetGenreProportionCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public Guid GenreId { get; set; }
|
||||||
|
public decimal? Proportion { get; set; }
|
||||||
|
public decimal? NewProportion { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetGenreProportionCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetGenreProportionCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetGenreProportionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetGenreProportion(request.GenreId, request.NewProportion);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Name;
|
||||||
|
|
||||||
|
public class AddNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddNameCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<AddNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var language = await languageGateway.GetLanguageById(request.LanguageId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.AddName((Domain.Entities.MediaContent.CommonProperties.NameType)request.NameType, language.Id, request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Name;
|
||||||
|
|
||||||
|
public class DeleteNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public CommonModels.NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteNameCommandHandler(IAnimeTitleGateway titleGateway, ILanguageGateway languageGateway) : IRequestHandler<DeleteNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var language = await languageGateway.GetLanguageById(request.LanguageId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.RemoveName(new NameItem((NameType)request.NameType, request.LanguageId, request.Value));
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.CommonProperties;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Name;
|
||||||
|
|
||||||
|
public class EditNameCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public CommonModels.NameType NameType { get; set; }
|
||||||
|
public Guid LanguageId { get; set; }
|
||||||
|
public string Value { get; set; } = default!;
|
||||||
|
public string? NewValue { get; set; }
|
||||||
|
public Guid? NewLanguageId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditNameCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<EditNameCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditNameCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!request.NewLanguageId.HasValue && string.IsNullOrWhiteSpace(request.NewValue))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException($"{nameof(EditNameCommand.NewLanguageId)}, {nameof(EditNameCommand.NewValue)}");
|
||||||
|
}
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetNameValue(new NameItem((NameType)request.NameType, request.LanguageId, request.Value), request.NewLanguageId, request.NewValue);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Preview;
|
||||||
|
|
||||||
|
public class DeletePreviewCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeletePreviewCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeletePreviewCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeletePreviewCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.DeletePreview();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.Preview;
|
||||||
|
|
||||||
|
public class SetPreviewCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetPreviewCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetPreviewCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetPreviewCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetPreview(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class AddRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<AddRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(AddRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.AddRelatedContent(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class DeleteRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeleteRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<DeleteRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(DeleteRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var mediaInfo = new Domain.Entities.MediaInfo(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.RemoveRelatedContent(mediaInfo);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Commands.CommonModels;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties.RelatedContent;
|
||||||
|
|
||||||
|
public class EditRelatedContentCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public MediaInfoType Type { get; set; }
|
||||||
|
public string Url { get; set; } = default!;
|
||||||
|
public string ContentType { get; set; } = default!;
|
||||||
|
public MediaInfoType NewType { get; set; }
|
||||||
|
public string NewUrl { get; set; } = default!;
|
||||||
|
public string NewContentType { get; set; } = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EditRelatedContentCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<EditRelatedContentCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(EditRelatedContentCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var mediaInfo = new Domain.Entities.MediaInfo(request.Url, (Domain.Entities.MediaInfoType)request.Type, request.ContentType);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.EditRelatedContent(mediaInfo, request.NewUrl, (Domain.Entities.MediaInfoType)request.NewType, request.NewContentType);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties;
|
||||||
|
|
||||||
|
public class SetAnnouncementDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public DateTimeOffset? Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetAnnouncementDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetAnnouncementDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetAnnouncementDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetAnnouncementDate(request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties;
|
||||||
|
|
||||||
|
public class SetCompletedCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public bool Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetCompletedCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetCompletedCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetCompletedCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
if (request.Value) season.SetCompleted();
|
||||||
|
else season.SetNotCompleted();
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties;
|
||||||
|
|
||||||
|
public class SetEstimatedReleaseDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
public Guid SeasonId { get; init; }
|
||||||
|
public DateTimeOffset? Value { get; init; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetEstimatedReleaseDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetEstimatedReleaseDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetEstimatedReleaseDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId, cancellationToken);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetExpectedReleaseDate(request.Value);
|
||||||
|
await titleGateway.Update(title, cancellationToken);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties;
|
||||||
|
|
||||||
|
public class SetExpirationTimeCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public TimeSpan ExpirationTime { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetExpirationTimeCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetExpirationTimeCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetExpirationTimeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.SetExpirationTime(request.ExpirationTime);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season.Properties;
|
||||||
|
|
||||||
|
public class SetReleaseDateCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public Guid SeasonId { get; set; }
|
||||||
|
public DateTimeOffset? Value { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SetReleaseDateCommandHandler(IAnimeTitleGateway titleGateway) : IRequestHandler<SetReleaseDateCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(SetReleaseDateCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
var season = title.Items.OfType<AnimeSeason>().FirstOrDefault(q => q.Id == request.SeasonId) ??
|
||||||
|
throw new Exception("Season not found");
|
||||||
|
season.CommonProperties.SetReleaseDate(request.Value);
|
||||||
|
await titleGateway.Update(title);
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Rating.Api.Commands;
|
||||||
|
using Modules.User.Application;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class UnvoteTitleCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UnvoteSeasonCommandHandler(IAnimeTitleGateway titleGateway, UserContext userContext, IMediator mediator) : IRequestHandler<UnvoteTitleCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(UnvoteTitleCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var user = await userContext.GetUserInfo(cancellationToken);
|
||||||
|
if (!user.IsAuthenticated || (!user.Id.HasValue || user.Id == Guid.Empty))
|
||||||
|
{
|
||||||
|
throw new Exception("User is not authenticated");
|
||||||
|
}
|
||||||
|
var subjectId = user.Id.Value;
|
||||||
|
var title = await titleGateway.GetById(request.TitleId, cancellationToken);
|
||||||
|
if (!title.Deleted)
|
||||||
|
{
|
||||||
|
await mediator.Send(new UnrateObjectCommand { ObjectId = title.Id, SubjectId = subjectId }, cancellationToken);
|
||||||
|
}
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Rating.Api.Commands;
|
||||||
|
using Modules.User.Application;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Season;
|
||||||
|
|
||||||
|
public class VoteSeasonCommand : IRequest<Unit>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; set; }
|
||||||
|
public ushort RatingPercentage { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VoteSeasonCommandHandler(IAnimeTitleGateway titleGateway, UserContext userContext, IMediator mediator) : IRequestHandler<VoteSeasonCommand, Unit>
|
||||||
|
{
|
||||||
|
public async Task<Unit> Handle(VoteSeasonCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var user = await userContext.GetUserInfo(cancellationToken);
|
||||||
|
if (!user.IsAuthenticated || (!user.Id.HasValue || user.Id == Guid.Empty))
|
||||||
|
{
|
||||||
|
throw new Exception("User is not authenticated");
|
||||||
|
}
|
||||||
|
var subjectId = user.Id.Value;
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
if (!title.Deleted)
|
||||||
|
{
|
||||||
|
await mediator.Send(new VoteForObjectCommand
|
||||||
|
{
|
||||||
|
ObjectId = title.Id,
|
||||||
|
SubjectId = subjectId,
|
||||||
|
RatingPercentage = request.RatingPercentage
|
||||||
|
}, cancellationToken);
|
||||||
|
}
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,116 @@
|
|||||||
|
using MediatR;
|
||||||
|
using Modules.Library.Application.Gateways;
|
||||||
|
using Modules.Library.Application.Services;
|
||||||
|
using Modules.Library.Domain.Entities.MediaContent.Items.Anime;
|
||||||
|
|
||||||
|
namespace Modules.Library.Application.Commands.Anime.Title;
|
||||||
|
|
||||||
|
public class AddEpisodeCommand : IRequest<Guid>
|
||||||
|
{
|
||||||
|
public Guid TitleId { get; init; }
|
||||||
|
|
||||||
|
public IEnumerable<Name> Names { get; init; } = [];
|
||||||
|
public MediaInfo? Preview { get; set; }
|
||||||
|
public IEnumerable<Description> Descriptions { get; init; } = [];
|
||||||
|
public IEnumerable<Genre> Genres { get; init; } = [];
|
||||||
|
public List<MediaInfo> RelatedContent { get; init; } = [];
|
||||||
|
|
||||||
|
public DateTimeOffset? AnnouncementDate { get; init; }
|
||||||
|
public DateTimeOffset? EstimatedReleaseDate { get; init; }
|
||||||
|
public DateTimeOffset ReleaseDate { get; init; }
|
||||||
|
|
||||||
|
public int? Number { get; init; }
|
||||||
|
public Models.AnimeEpisodeType Type { get; init; }
|
||||||
|
|
||||||
|
public TimeSpan? Duration { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AddEpisodeCommandHandler(IAnimeTitleGateway titleGateway, IAnimeEpisodeGateway episodeGateway, ILanguageGateway languageGateway,
|
||||||
|
IGenreGateway genreGateway, MediaInfoService mediaInfoService) : IRequestHandler<AddEpisodeCommand, Guid>
|
||||||
|
{
|
||||||
|
public async Task<Guid> Handle(AddEpisodeCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var title = await titleGateway.GetById(request.TitleId);
|
||||||
|
//if (!request.Names.Any()) throw new Exception("No names");
|
||||||
|
|
||||||
|
var languages = (await languageGateway.GetLanguageByIds(request.Names.Select(q => q.LanguageId).Distinct())).ToArray();
|
||||||
|
var genres = (await genreGateway.GetGenreByIds(request.Genres.Select(q => q.GenreId).Distinct())).ToArray();
|
||||||
|
|
||||||
|
//var episode = title.AddEpisode((Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType)request.Type);
|
||||||
|
//replace type by tags
|
||||||
|
//var episodeType = request.Type switch
|
||||||
|
//{
|
||||||
|
// Models.AnimeEpisodeType.Regilar => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.Regilar,
|
||||||
|
// Models.AnimeEpisodeType.Ova => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.Ova,
|
||||||
|
// Models.AnimeEpisodeType.FullLength => Domain.Entities.MediaContent.Items.Anime.AnimeEpisodeType.FullLength,
|
||||||
|
// _ => throw new NotImplementedException()
|
||||||
|
//};
|
||||||
|
var episode = title.AddEpisode((AnimeEpisodeType)request.Type, request.Names.Select(q =>
|
||||||
|
new Domain.Entities.MediaContent.CommonProperties.NameItem((Domain.Entities.MediaContent.CommonProperties.NameType)q.NameType,
|
||||||
|
languages.First(x => x.Id == q.LanguageId).Id, q.Value)), request.Number, request.Duration);
|
||||||
|
//var language = await languageGateway.GetLanguageById(request.NameLanguageId);
|
||||||
|
foreach (var name in request.Names)
|
||||||
|
{
|
||||||
|
var languageId = languages.First(x => x.Id == name.LanguageId).Id;
|
||||||
|
var type = (Domain.Entities.MediaContent.CommonProperties.NameType)name.NameType;
|
||||||
|
episode.CommonProperties.AddName(type, languageId, name.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request.Descriptions.Any())
|
||||||
|
{
|
||||||
|
foreach (var description in request.Descriptions)
|
||||||
|
{
|
||||||
|
var languageId = languages.First(q => q.Id == description.LanguageId).Id;
|
||||||
|
if (description.IsOriginal) episode.CommonProperties.AddOriginalDescription(languageId, description.Value);
|
||||||
|
else episode.CommonProperties.AddNotOriginalDescription(languageId, description.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.Genres.Any())
|
||||||
|
{
|
||||||
|
foreach (var genre in request.Genres)
|
||||||
|
{
|
||||||
|
var genreId = genres.First(q => q.Id == genre.GenreId).Id;
|
||||||
|
episode.CommonProperties.AddGenre(genreId, genre.Proportion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.RelatedContent.Any())
|
||||||
|
{
|
||||||
|
foreach (var relatedContentItem in request.RelatedContent)
|
||||||
|
{
|
||||||
|
//add model
|
||||||
|
var (objectId, contentType) = await mediaInfoService.Add(new MediaInfoService.CreateModel
|
||||||
|
{
|
||||||
|
Data = relatedContentItem.Data,
|
||||||
|
Url = relatedContentItem.Url,
|
||||||
|
ContentType = relatedContentItem.ContentType,
|
||||||
|
Type = (Domain.Entities.MediaInfoType)relatedContentItem.Type,
|
||||||
|
}, false, cancellationToken);
|
||||||
|
|
||||||
|
//objectId
|
||||||
|
episode.CommonProperties.AddRelatedContent(objectId, (Domain.Entities.MediaInfoType)relatedContentItem.Type, contentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
episode.CommonProperties.SetAnnouncementDate(request.AnnouncementDate);
|
||||||
|
episode.CommonProperties.SetEstimatedReleaseDate(request.EstimatedReleaseDate);
|
||||||
|
episode.CommonProperties.SetReleaseDate(request.ReleaseDate);
|
||||||
|
var animeEpisodeId = await episodeGateway.Create(title.Id, null, episode);
|
||||||
|
if (request.Preview != null)
|
||||||
|
{
|
||||||
|
title = await titleGateway.GetById(title.Id);
|
||||||
|
episode = title.Items.OfType<AnimeEpisode>().First(q => q.Id == animeEpisodeId);
|
||||||
|
var (objectId, contentType) = await mediaInfoService.Add(new MediaInfoService.CreateModel
|
||||||
|
{
|
||||||
|
Id = animeEpisodeId,
|
||||||
|
Data = request.Preview.Data,
|
||||||
|
Url = request.Preview.Url,
|
||||||
|
ContentType = request.Preview.ContentType,
|
||||||
|
Type = (Domain.Entities.MediaInfoType)request.Preview.Type,
|
||||||
|
}, true, cancellationToken);
|
||||||
|
episode.CommonProperties.SetPreview(objectId, (Domain.Entities.MediaInfoType)request.Preview.Type, contentType);
|
||||||
|
await episodeGateway.Update(title.Id, null, episode);
|
||||||
|
}
|
||||||
|
//return await titleGateway.Create(animeTitle);
|
||||||
|
return animeEpisodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user