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
|
||||
## 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
|
||||
*.rsuser
|
||||
@ -91,6 +92,7 @@ StyleCopReport.xml
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.tlog
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
@ -294,6 +296,17 @@ node_modules/
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.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
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
@ -350,6 +363,9 @@ ASALocalRun/
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# Visual Studio History (VSHistory) files
|
||||
.vshistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
@ -360,4 +376,26 @@ MigrationBackup/
|
||||
.ionide/
|
||||
|
||||
# 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