From 5005c77abd91d49ccdfeea8bfe69090aac041d74 Mon Sep 17 00:00:00 2001 From: Vitalii Mikhailov Date: Thu, 17 Oct 2024 02:01:36 +0300 Subject: [PATCH] Added more Steam Workshop support --- .../Pages/Moderator/ManualModuleIdLink.razor | 189 ++---------- .../NexusMods.razor | 175 +++++++++++ .../SteamWorkshop.razor | 193 ++++++++++++ .../Pages/User/AllowUserMod.razor | 187 ++---------- .../AllowUserModComponents/NexusMods.razor | 182 +++++++++++ .../SteamWorkshop.razor | 179 +++++++++++ .../Pages/User/Mods.razor | 283 +----------------- .../Pages/User/ModsComponents/NexusMods.razor | 139 +++++++++ .../User/ModsComponents/SteamWorkshop.razor | 150 ++++++++++ .../Services/NexusModsUserClientWithDemo.cs | 19 +- .../IUnitOfRead.cs | 1 + .../NexusModsModToModuleEntityRepository.cs | 4 +- ...sModsUserToNexusModsModEntityRepository.cs | 4 +- ...sUserToSteamWorkshopModEntityRepository.cs | 16 +- .../Contexts/BaseAppDbContext.cs | 2 +- .../Controllers/NexusModsUserController.cs | 104 ++++++- .../Controllers/SteamController.cs | 12 +- .../20241016083519_SteamWorkshop.cs | 5 +- .../20241016101519_SteamWorkshop2.cs | 28 +- .../Repositories/IUnitOfRead.cs | 4 +- .../Repositories/IUnitOfWrite.cs | 2 +- .../NexusModsModToModuleEntityRepository.cs | 2 +- ...sModsUserToNexusModsModEntityRepository.cs | 4 +- ...sUserToSteamWorkshopModEntityRepository.cs | 20 ++ ...teamWorkshopModToModuleEntityRepository.cs | 10 +- .../SteamWorkshopModToNameEntityRepository.cs | 4 +- 26 files changed, 1260 insertions(+), 658 deletions(-) create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/NexusMods.razor create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/SteamWorkshop.razor create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/NexusMods.razor create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/SteamWorkshop.razor create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/NexusMods.razor create mode 100644 src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/SteamWorkshop.razor diff --git a/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLink.razor b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLink.razor index f66637e6..4f67774e 100644 --- a/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLink.razor +++ b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLink.razor @@ -1,185 +1,34 @@ @attribute [Authorize(Roles = $"{ApplicationRoles.Administrator}, {ApplicationRoles.Moderator}")] @page "/manual-module-id-link" -@inject INotificationService _notificationService -@inject INexusModsModClient _modClient - - - - - Remove Allowed Module Id - - - - @if (_dataGridRef?.Value is not null) - { -
- - Module Id to Remove - - - - -
- } -
- - - - -
-
- - - Manual Module Id Link - -
- - - Module Id - - - - - - NexusMods Mod Url - - - - - - - - -
-
-
- - - - Manual Module Id Links - - - - - - - @(string.Join(", ", context.NexusModsMods.Select(x => x.NexusModsModId))) - - - - - - + + + NexusMods Mods + Steam Workshop Mods + + + + + + + + + + + @code { - private sealed record ManualLinkModel - { - public required string ModuleId { get; set; } - public required string NexusModsUrl { get; set; } - } - - private bool _isLoading; - - private readonly ManualLinkModel _model = new() { ModuleId = string.Empty, NexusModsUrl = string.Empty }; - - private int? _modIdToDelete; + private string _selectedTab = "nexusmods"; - private Modal _modalRef = default!; - private DataGridPaging? _dataGridRef; - - private async Task ShowModal() + private Task OnSelectedTabChanged(string name) { - _modIdToDelete = _dataGridRef?.Value?.NexusModsMods.Select(x => x.NexusModsModId).First(); - await _modalRef.Show(); - } + _selectedTab = name; - private async Task HideModal(bool save) - { - await _modalRef.Hide(); - if (save && _dataGridRef?.Value is not null && _modIdToDelete is not null) - { - if (await _modClient.RemoveModuleManualLinkAsync(moduleId: _dataGridRef.Value.ModuleId, modId: _modIdToDelete.Value) is { Error: null }) - { - await _notificationService.Success("Disallowed succesfully!", "Success!"); - await _dataGridRef.Reload(); - } - else - { - await _notificationService.Error("Failed to disallow!", "Error!"); - } - } - } - - private async Task OnSubmit() - { - _isLoading = true; - - try - { - if (await DoManualLink(_model)) - { - await _notificationService.Success($"Linked '{_model.ModuleId}' to mod '{_model.NexusModsUrl}'!", "Success!"); - if (_dataGridRef is not null) - await _dataGridRef.Reload(); - } - else - { - await _notificationService.Error($"Failed to link '{_model.ModuleId}' to mod '{_model.NexusModsUrl}'!", "Error!"); - } - } - catch - { - await _notificationService.Error($"Failed to link '{_model.ModuleId}' to mod '{_model.NexusModsUrl}'!", "Error!"); - } - - _isLoading = false; - StateHasChanged(); - } - - private async Task.ItemsResponse?> GetManualLinks(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) - { - var response = await _modClient.GetModuleManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } - - private async Task OnDisallow(ButtonRowContext context) - { - if (context.DeleteCommand.Item is not null && await DoManualUnlink(context.DeleteCommand.Item)) - { - //await context.DeleteCommand.Clicked.InvokeAsync(); - } - } - - private async Task DoManualLink(ManualLinkModel model) - { - if (!NexusModsUtils.TryParseModUrl(model.NexusModsUrl, out _, out var nexusModsId) && !uint.TryParse(model.NexusModsUrl, out nexusModsId)) - return false; - - return await _modClient.AddModuleManualLinkAsync(moduleId: model.ModuleId, modId: (int) nexusModsId) is { Error: null }; - } - private async Task DoManualUnlink(LinkedByStaffModuleNexusModsModsModel model) - { - await ShowModal(); - return true; + return Task.CompletedTask; } } \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/NexusMods.razor b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/NexusMods.razor new file mode 100644 index 00000000..7f18adb8 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/NexusMods.razor @@ -0,0 +1,175 @@ +@inject INotificationService _notificationService +@inject INexusModsModClient _modClient + + + + + Remove Allowed Module Id + + + + @if (_dataGridRef?.Value is not null) + { +
+ + Module Id to Remove + + + + +
+ } +
+ + + + +
+
+ + + + Manual Module Id Link + + +
+ + + Module Id + + + + + + NexusMods Mod Url + + + + + + + + +
+
+
+ + + + Manual Module Id Links + + + + + + + @(string.Join(", ", context.Mods.Select(x => x.NexusModsModId))) + + + + + + + + + +@code { + + private Modal _modalRef = default!; + private DataGridPaging? _dataGridRef; + + private bool _isLoading; + private string _moduleId = string.Empty; + private string _modUrl = string.Empty; + private int? _modIdToDelete = null; + + private async Task ShowModal() + { + _modIdToDelete = _dataGridRef?.Value?.Mods.Select(x => x.NexusModsModId).FirstOrDefault() ?? 0; + await _modalRef.Show(); + } + + private async Task HideModal(bool save) + { + await _modalRef.Hide(); + if (save && _dataGridRef?.Value is not null && _modIdToDelete is not null) + { + if (await _modClient.RemoveModuleManualLinkAsync(moduleId: _dataGridRef.Value.ModuleId, modId: _modIdToDelete.Value) is { Error: null }) + { + await _notificationService.Success("Disallowed succesfully!", "Success!"); + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error("Failed to disallow!", "Error!"); + } + } + } + + private async Task OnSubmit() + { + _isLoading = true; + + try + { + if (await DoManualLink()) + { + await _notificationService.Success($"Linked '{_moduleId}' to mod '{_modUrl}'!", "Success!"); + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error($"Failed to link '{_moduleId}' to mod '{_modUrl}'!", "Error!"); + } + } + catch + { + await _notificationService.Error($"Failed to link '{_moduleId}' to mod '{_modUrl}'!", "Error!"); + } + + _isLoading = false; + StateHasChanged(); + } + + private async Task.ItemsResponse?> GetManualLinks(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) + { + var response = await _modClient.GetModuleManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnDisallow(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoManualUnlink()) + { + //await context.DeleteCommand.Clicked.InvokeAsync(); + } + } + + private async Task DoManualLink() + { + if (!NexusModsUtils.TryParseModUrl(_modUrl, out _, out var nexusModsId) && !uint.TryParse(_modUrl, out nexusModsId)) + return false; + + return await _modClient.AddModuleManualLinkAsync(moduleId: _moduleId, modId: (int) nexusModsId) is { Error: null }; + } + private async Task DoManualUnlink() + { + await ShowModal(); + return true; + } +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/SteamWorkshop.razor b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/SteamWorkshop.razor new file mode 100644 index 00000000..ae218903 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/Moderator/ManualModuleIdLinkComponents/SteamWorkshop.razor @@ -0,0 +1,193 @@ +@inject INotificationService _notificationService +@inject INexusModsUserClient _userClient +@inject ISteamClient _modClient + + + + + Remove Allowed Module Id + + + + @if (_dataGridRef?.Value is not null) + { +
+ + Module Id to Remove + + + + +
+ } +
+ + + + +
+
+ +@if (_user?.SteamUserId is null) +{ +

You need to link your Steam account to use this feature.

+ +} else { + + + Manual Module Id Link + + +
+ + + Module Id + + + + + + Steam Workshop Mod Url + + + + + + + + +
+
+
+ + + + Manual Module Id Links + + + + + + + @(string.Join(", ", context.Mods.Select(x => x.SteamWorkshopModId))) + + + + + + + + +} + + + +@code { + + private Modal _modalRef = default!; + private DataGridPaging? _dataGridRef; + + private ProfileModel? _user; + private bool _isLoading; + private string _moduleId = string.Empty; + private string _modUrl = string.Empty; + private string? _modIdToDelete = string.Empty; + + protected override async Task OnInitializedAsync() + { + var userResponse = await _userClient.GetProfileAsync(); + _user = userResponse.Value; + + await base.OnInitializedAsync(); + } + + private async Task ShowModal() + { + _modIdToDelete = _dataGridRef?.Value?.Mods.Select(x => x.SteamWorkshopModId).FirstOrDefault(); + await _modalRef.Show(); + } + + private async Task HideModal(bool save) + { + await _modalRef.Hide(); + if (save && _dataGridRef?.Value is not null && _modIdToDelete is not null) + { + if (await _modClient.RemoveModuleManualLinkAsync(moduleId: _dataGridRef.Value.ModuleId, modId: _modIdToDelete) is { Error: null }) + { + await _notificationService.Success("Disallowed succesfully!", "Success!"); + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error("Failed to disallow!", "Error!"); + } + } + } + + private async Task OnSubmit() + { + _isLoading = true; + + try + { + if (await DoManualLink()) + { + await _notificationService.Success($"Linked '{_moduleId}' to mod '{_modUrl}'!", "Success!"); + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error($"Failed to link '{_moduleId}' to mod '{_modUrl}'!", "Error!"); + } + } + catch + { + await _notificationService.Error($"Failed to link '{_moduleId}' to mod '{_modUrl}'!", "Error!"); + } + + _isLoading = false; + StateHasChanged(); + } + + private async Task.ItemsResponse?> GetManualLinks(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) + { + var response = await _modClient.GetModuleManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnDisallow(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoManualUnlink()) + { + //await context.DeleteCommand.Clicked.InvokeAsync(); + } + } + + private async Task DoManualLink() + { + if (!SteamUtils.TryParseWorkshopId(_modUrl, out var modId)) + modId = _modUrl; + + return await _modClient.AddModuleManualLinkAsync(moduleId: _moduleId, modId: modId) is { Error: null }; + } + private async Task DoManualUnlink() + { + await ShowModal(); + return true; + } +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserMod.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserMod.razor index ea44772d..dd9739be 100644 --- a/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserMod.razor +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserMod.razor @@ -1,185 +1,34 @@ @attribute [Authorize(Roles = $"{ApplicationRoles.Administrator}, {ApplicationRoles.Moderator}")] @page "/allow-user-mod" -@inject INotificationService _notificationService -@inject INexusModsUserClient _userClient - - - - - Remove Allowed Mod Id - - - - @if (_dataGridRef?.Value is not null) - { -
- - User Id to Remove - - - - -
- } -
- - - - -
-
- - - Allow User Mod - - -
- - - NexusMods User Url - - - - - - NexusMods Mod Url - - - - - - - - -
-
-
- - - Allowed Mods to Users - - - - - - @(string.Join(", ", context.NexusModsUsers.Select(x => $"{x.NexusModsUserId} ({x.NexusModsUsername})"))) - - - - - - + + + NexusMods Mods + Steam Workshop Mods + + + + + + + + + + @code { - private sealed record AllowUserModel - { - public required string UserUrl { get; set; } - public required string ModUrl { get; set; } - } - - private bool _isLoading; - - private readonly AllowUserModel _model = new() { UserUrl = string.Empty, ModUrl = string.Empty }; - - private int? _userIdToDelete; + private string _selectedTab = "nexusmods"; - private Modal _modalRef = default!; - private DataGridPaging? _dataGridRef; - - private async Task ShowModal() => await _modalRef.Show(); - - private async Task HideModal(bool save) + private Task OnSelectedTabChanged( string name ) { - await _modalRef.Hide(); - if (save && _dataGridRef?.Value is not null && _userIdToDelete is not null) - { - if (await _userClient.RemoveNexusModsModManualLinkAsync(userId: (int) _userIdToDelete, modId: _dataGridRef.Value.NexusModsModId, cancellationToken: CancellationToken.None) is { Error: null }) - { - await _notificationService.Success("Disallowed succesfully!", "Success!"); - await _dataGridRef.Reload(); - } - else - { - await _notificationService.Error("Failed to disallow!", "Error!"); - } - } - } - private async Task OnSubmit() - { - try - { - if (await DoUserAllowMod(_model)) - { - await _notificationService.Success($"Assigned '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Success!"); - if (_dataGridRef is not null) - await _dataGridRef.Reload(); - } - else - { - await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); - } - } - catch - { - await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); - } - } - - private async Task.ItemsResponse?> GetAllowUserMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) - { - var response = await _userClient.GetNexusModsModManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } + _selectedTab = name; - private async Task OnDisallow(ButtonRowContext context) - { - if (context.DeleteCommand.Item is not null && await DoUserDisallowMod(context.DeleteCommand.Item)) - { - //await context.DeleteCommand.Clicked.InvokeAsync(); - } - } - - private async Task DoUserAllowMod(AllowUserModel model) - { - var hasUsername = NexusModsUtils.TryParseUsername(model.UserUrl, out var username); - var hasUserId = NexusModsUtils.TryParseUserId(model.UserUrl, out _, out var userId); - if (!hasUsername && !hasUserId) - { - await _notificationService.Error("Failed to parse the user url!", "Error!"); - return false; - } - - if (!NexusModsUtils.TryParseModUrl(model.ModUrl, out _, out var modId)) - { - await _notificationService.Error("Failed to parse the mod url!", "Error!"); - return false; - } - - return await _userClient.AddNexusModsModManualLinkAsync(modId: (int) modId, userId: hasUserId ? (int) userId : null, username: hasUsername ? username : null) is { Error: null }; - } - private async Task DoUserDisallowMod(UserManuallyLinkedModModel model) - { - await ShowModal(); - return true; + return Task.CompletedTask; } } \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/NexusMods.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/NexusMods.razor new file mode 100644 index 00000000..3d59f1f8 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/NexusMods.razor @@ -0,0 +1,182 @@ +@inject INotificationService _notificationService +@inject INexusModsUserClient _userClient + + + + + Remove Allowed Mod Id + + + + @if (_dataGridRef?.Value is not null) + { +
+ + User Id to Remove + + + + +
+ } +
+ + + + +
+
+ + + + Allow User Mod + + +
+ + + NexusMods User Url + + + + + + NexusMods Mod Url + + + + + + + + +
+
+
+ + + Allowed Mods to Users + + + + + + + @(string.Join(", ", context.NexusModsUsers.Select(x => $"{x.NexusModsUserId} ({x.NexusModsUsername})"))) + + + + + + + + + +@code { + + private sealed record AllowUserModel + { + public required string UserUrl { get; set; } + public required string ModUrl { get; set; } + } + + private bool _isLoading; + + private readonly AllowUserModel _model = new() { UserUrl = string.Empty, ModUrl = string.Empty }; + + private int? _userIdToDelete; + + private Modal _modalRef = default!; + private DataGridPaging? _dataGridRef; + + private async Task ShowModal() => await _modalRef.Show(); + + private async Task HideModal(bool save) + { + await _modalRef.Hide(); + if (save && _dataGridRef?.Value is not null && _userIdToDelete is not null) + { + if (await _userClient.RemoveNexusModsModManualLinkAsync(userId: (int) _userIdToDelete, modId: _dataGridRef.Value.NexusModsModId, cancellationToken: CancellationToken.None) is { Error: null }) + { + await _notificationService.Success("Disallowed succesfully!", "Success!"); + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error("Failed to disallow!", "Error!"); + } + } + } + private async Task OnSubmit() + { + try + { + if (await DoUserAllowMod(_model)) + { + await _notificationService.Success($"Assigned '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Success!"); + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); + } + } + catch + { + await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); + } + } + + private async Task.ItemsResponse?> GetAllowUserMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) + { + var response = await _userClient.GetNexusModsModManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnDisallow(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoUserDisallowMod(context.DeleteCommand.Item)) + { + //await context.DeleteCommand.Clicked.InvokeAsync(); + } + } + + private async Task DoUserAllowMod(AllowUserModel model) + { + var hasUsername = NexusModsUtils.TryParseUsername(model.UserUrl, out var username); + var hasUserId = NexusModsUtils.TryParseUserId(model.UserUrl, out _, out var userId); + if (!hasUsername && !hasUserId) + { + await _notificationService.Error("Failed to parse the user url!", "Error!"); + return false; + } + + if (!NexusModsUtils.TryParseModUrl(model.ModUrl, out _, out var modId)) + { + await _notificationService.Error("Failed to parse the mod url!", "Error!"); + return false; + } + + return await _userClient.AddNexusModsModManualLinkAsync(modId: (int) modId, userId: hasUserId ? (int) userId : null, username: hasUsername ? username : null) is { Error: null }; + } + private async Task DoUserDisallowMod(UserManuallyLinkedNexusModsModModel model) + { + await ShowModal(); + return true; + } + +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/SteamWorkshop.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/SteamWorkshop.razor new file mode 100644 index 00000000..32090f61 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/AllowUserModComponents/SteamWorkshop.razor @@ -0,0 +1,179 @@ +@inject INotificationService _notificationService +@inject INexusModsUserClient _userClient + + + + + Remove Allowed Mod Id + + + + @if (_dataGridRef?.Value is not null) + { +
+ + User Id to Remove + + + + +
+ } +
+ + + + +
+
+ + + + Allow User Mod + + +
+ + + NexusMods User Url + + + + + + Steam Workshop Mod Url + + + + + + + + +
+
+
+ + + Allowed Mods to Users + + + + + + + @(string.Join(", ", context.NexusModsUsers.Select(x => $"{x.NexusModsUserId} ({x.NexusModsUsername})"))) + + + + + + + + + +@code { + + private sealed record AllowUserModel + { + public required string UserUrl { get; set; } + public required string ModUrl { get; set; } + } + + private bool _isLoading; + + private readonly AllowUserModel _model = new() { UserUrl = string.Empty, ModUrl = string.Empty }; + + private int? _userIdToDelete; + + private Modal _modalRef = default!; + private DataGridPaging? _dataGridRef; + + private async Task ShowModal() => await _modalRef.Show(); + + private async Task HideModal(bool save) + { + await _modalRef.Hide(); + if (save && _dataGridRef?.Value is not null && _userIdToDelete is not null) + { + if (await _userClient.RemoveSteamWorkshopModManualLinkAsync(userId: (int) _userIdToDelete, modId: _dataGridRef.Value.SteamWorkshopModId, cancellationToken: CancellationToken.None) is { Error: null }) + { + await _notificationService.Success("Disallowed succesfully!", "Success!"); + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error("Failed to disallow!", "Error!"); + } + } + } + private async Task OnSubmit() + { + try + { + if (await DoUserAllowMod(_model)) + { + await _notificationService.Success($"Assigned '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Success!"); + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + else + { + await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); + } + } + catch + { + await _notificationService.Error($"Failed to assign '{_model.ModUrl}' to user '{_model.UserUrl}'!", "Error!"); + } + } + + private async Task.ItemsResponse?> GetAllowUserMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct) + { + var response = await _userClient.GetSteamWorkshopModManualLinkPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnDisallow(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoUserDisallowMod(context.DeleteCommand.Item)) + { + //await context.DeleteCommand.Clicked.InvokeAsync(); + } + } + + private async Task DoUserAllowMod(AllowUserModel model) + { + var hasUsername = NexusModsUtils.TryParseUsername(model.UserUrl, out var username); + var hasUserId = NexusModsUtils.TryParseUserId(model.UserUrl, out _, out var userId); + if (!hasUsername && !hasUserId) + { + await _notificationService.Error("Failed to parse the user url!", "Error!"); + return false; + } + + if (!SteamUtils.TryParseWorkshopId(model.ModUrl, out var modId)) + modId = model.ModUrl; + + return await _userClient.AddSteamWorkshopModManualLinkAsync(modId: modId, userId: hasUserId ? (int) userId : null, username: hasUsername ? username : null) is { Error: null }; + } + private async Task DoUserDisallowMod(UserManuallyLinkedSteamWorkshopModModel model) + { + await ShowModal(); + return true; + } + +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/Mods.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/Mods.razor index 2acd52ff..3332864c 100644 --- a/src/BUTR.Site.NexusMods.Client/Pages/User/Mods.razor +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/Mods.razor @@ -1,165 +1,19 @@ @attribute [Authorize] @page "/mods" -@inject INexusModsUserClient _userClient -@inject TenantProvider _tenantProvider -@inject IJSRuntime _jsRuntime; - - + NexusMods Mods Steam Workshop Mods - - - Link Mod - - -
- - NexusMods Mod Url - - - - - - - -
-
-
- - - - Linked Mods - - - - - - - - @(string.Join(", ", context.AllowedNexusModsUserIds)) - - - @(string.Join(", ", context.ManuallyLinkedNexusModsUserIds)) - - - @(string.Join(", ", context.ManuallyLinkedModuleIds)) - - - @(string.Join(", ", context.KnownModuleIds)) - - - - - - - - - - - - - - Available Mods - - - - - - - - - - +
- @if (_user?.SteamUserId is null) - { -

You need to link your Steam account to use this feature.

- - } else { - - - Link Mod - - -
- - Steam Workshop Mod Url - - - - - - - -
-
-
- - - - Linked Mods - - - - - - - - @(string.Join(", ", context.AllowedNexusModsUserIds)) - - - @(string.Join(", ", context.ManuallyLinkedNexusModsUserIds)) - - - @(string.Join(", ", context.ManuallyLinkedModuleIds)) - - - @(string.Join(", ", context.KnownModuleIds)) - - - - - - - - - - - - - - Available Mods - - - - - - - - - - - } +
@@ -168,140 +22,13 @@ @code { - string selectedTab = "nexusmods"; + private string _selectedTab = "nexusmods"; private Task OnSelectedTabChanged( string name ) { - selectedTab = name; + _selectedTab = name; return Task.CompletedTask; } - private sealed record LinkModModel - { - public string ModUrl { get; set; } = string.Empty; - } - - private bool _isLoading; - - private LinkModModel _model = new(); - - private DataGridPaging? _dataGridRef; - private DataGridPaging? _dataGridRef2; - - private DataGridPaging? _dataGridRef3; - private DataGridPaging? _dataGridRef4; - - private ProfileModel? _user; - - override protected async Task OnInitializedAsync() - { - var userResponse = await _userClient.GetProfileAsync(); - _user = userResponse.Value; - - await base.OnInitializedAsync(); - } - - private async Task OnNexusModsSubmit() - { - _isLoading = true; - - if (await DoNexusModsLinkMod(_model)) - { - _model = new LinkModModel(); - if (_dataGridRef is not null) - await _dataGridRef.Reload(); - } - - _isLoading = false; - StateHasChanged(); - } - private async Task OnSteamWorkshopSubmit() - { - _isLoading = true; - - if (await DoSteamWorkshopLinkMod(_model)) - { - _model = new LinkModModel(); - if (_dataGridRef is not null) - await _dataGridRef.Reload(); - } - - _isLoading = false; - StateHasChanged(); - } - - private async Task DoNexusModsLinkMod(LinkModModel model) - { - if (!NexusModsUtils.TryParseModUrl(model.ModUrl, out _, out var modId) && !uint.TryParse(model.ModUrl, out modId)) - return false; - - return await _userClient.AddNexusModsModLinkAsync((int) modId) is { Error: null }; - } - - private async Task DoSteamWorkshopLinkMod(LinkModModel model) - { - if (!SteamUtils.TryParseWorkshopId(model.ModUrl, out var modId)) - modId = model.ModUrl; - - return await _userClient.AddSteamWorkshopModLinkAsync(modId) is { Error: null }; - } - - private async Task DoNexusModsUnlinkMod(UserLinkedNexusModsModModel model) - { - return await _userClient.RemoveNexusModsModLinkAsync(modId: model.NexusModsModId) is { Error: null }; - } - - private async Task DoSteamWorkshopUnlinkMod(UserLinkedSteamWorkshopModModel model) - { - return await _userClient.RemoveSteamWorkshopModLinkAsync(modId: model.SteamWorkshopModId) is { Error: null }; - } - - private async Task.ItemsResponse?> GetNexusModsMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) - { - var response = await _userClient.GetNexusModsModsPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } - private async Task.ItemsResponse?> GetSteamWorkshopMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) - { - var response = await _userClient.GetSteamWorkshopModsPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } - - private async Task.ItemsResponse?> GetNexusModsAllowedMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) - { - var response = await _userClient.GetNexusModsModsPaginateAvailabledAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } - private async Task.ItemsResponse?> GetSteamWorkshopAllowedMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) - { - var response = await _userClient.GetSteamWorkshopModsPaginateAvailabledAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); - return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; - } - - private async Task OnNexusModsClick(UserLinkedNexusModsModModel? mod) - { - if (mod is not null) - await _jsRuntime.InvokeVoidAsync("open", mod.Url(TenantUtils.FromTenantToGameDomain(await _tenantProvider.GetTenantAsync())!), "_blank"); - } - private async Task OnSteamWorkshopClick(UserLinkedSteamWorkshopModModel? mod) - { - if (mod is not null) - await _jsRuntime.InvokeVoidAsync("open", mod.Url(), "_blank"); - } - - private async Task OnNexusModsDelete(ButtonRowContext context) - { - if (context.DeleteCommand.Item is not null && await DoNexusModsUnlinkMod(context.DeleteCommand.Item)) - { - await context.DeleteCommand.Clicked.InvokeAsync(); - } - } - private async Task OnSteamWorkshopDelete(ButtonRowContext context) - { - if (context.DeleteCommand.Item is not null && await DoSteamWorkshopUnlinkMod(context.DeleteCommand.Item)) - { - await context.DeleteCommand.Clicked.InvokeAsync(); - } - } } \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/NexusMods.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/NexusMods.razor new file mode 100644 index 00000000..7d3e8119 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/NexusMods.razor @@ -0,0 +1,139 @@ +@inject INexusModsUserClient _userClient +@inject TenantProvider _tenantProvider +@inject IJSRuntime _jsRuntime; + + + + Link Mod + + +
+ + NexusMods Mod Url + + + + + + + +
+
+
+ + + + Linked Mods + + + + + + + + @(string.Join(", ", context.AllowedNexusModsUserIds)) + + + @(string.Join(", ", context.ManuallyLinkedNexusModsUserIds)) + + + @(string.Join(", ", context.ManuallyLinkedModuleIds)) + + + @(string.Join(", ", context.KnownModuleIds)) + + + + + + + + + + + + + + Available Mods + + + + + + + + + + + +@code { + + private DataGridPaging? _dataGridRef; + + private ProfileModel? _user; + private bool _isLoading; + private string _modUrl = string.Empty; + + private async Task OnSubmit() + { + _isLoading = true; + + if (await DoLinkMod()) + { + _modUrl = string.Empty; + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + + _isLoading = false; + StateHasChanged(); + } + + private async Task DoLinkMod() + { + if (!NexusModsUtils.TryParseModUrl(_modUrl, out _, out var modId) && !uint.TryParse(_modUrl, out modId)) + return false; + + return await _userClient.AddNexusModsModLinkAsync((int) modId) is { Error: null }; + } + + + private async Task DoUnlinkMod(UserLinkedNexusModsModModel model) + { + return await _userClient.RemoveNexusModsModLinkAsync(modId: model.NexusModsModId) is { Error: null }; + } + + private async Task.ItemsResponse?> GetMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) + { + var response = await _userClient.GetNexusModsModsPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task.ItemsResponse?> GetAllowedMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) + { + var response = await _userClient.GetNexusModsModsPaginateAvailabledAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnClick(UserLinkedNexusModsModModel? mod) + { + if (mod is null) + return; + + await _jsRuntime.InvokeVoidAsync("open", mod.Url(TenantUtils.FromTenantToGameDomain(await _tenantProvider.GetTenantAsync())!), "_blank"); + } + + private async Task OnDelete(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoUnlinkMod(context.DeleteCommand.Item)) + { + await context.DeleteCommand.Clicked.InvokeAsync(); + } + } +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/SteamWorkshop.razor b/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/SteamWorkshop.razor new file mode 100644 index 00000000..de18ce58 --- /dev/null +++ b/src/BUTR.Site.NexusMods.Client/Pages/User/ModsComponents/SteamWorkshop.razor @@ -0,0 +1,150 @@ +@inject INexusModsUserClient _userClient +@inject IJSRuntime _jsRuntime; + +@if (_user?.SteamUserId is null) +{ +

You need to link your Steam account to use this feature.

+ +} else { + + + Link Mod + + +
+ + Steam Workshop Mod Url + + + + + + + +
+
+
+ + + + Linked Mods + + + + + + + + @(string.Join(", ", context.AllowedNexusModsUserIds)) + + + @(string.Join(", ", context.ManuallyLinkedNexusModsUserIds)) + + + @(string.Join(", ", context.ManuallyLinkedModuleIds)) + + + @(string.Join(", ", context.KnownModuleIds)) + + + + + + + + + + + + + + Available Mods + + + + + + + + + + +} + +@code { + + private DataGridPaging? _dataGridRef; + + private ProfileModel? _user; + private bool _isLoading; + private string _modUrl = string.Empty; + + protected override async Task OnInitializedAsync() + { + var userResponse = await _userClient.GetProfileAsync(); + _user = userResponse.Value; + + await base.OnInitializedAsync(); + } + private async Task OnSubmit() + { + _isLoading = true; + + if (await DoLinkMod()) + { + _modUrl = string.Empty; + if (_dataGridRef is not null) + await _dataGridRef.Reload(); + } + + _isLoading = false; + StateHasChanged(); + } + + private async Task DoLinkMod() + { + if (!SteamUtils.TryParseWorkshopId(_modUrl, out var modId)) + modId = _modUrl; + + return await _userClient.AddSteamWorkshopModLinkAsync(modId) is { Error: null }; + } + + private async Task DoUnlinkMod(UserLinkedSteamWorkshopModModel model) + { + return await _userClient.RemoveSteamWorkshopModLinkAsync(modId: model.SteamWorkshopModId) is { Error: null }; + } + + private async Task.ItemsResponse?> GetMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) + { + var response = await _userClient.GetSteamWorkshopModsPaginatedAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task.ItemsResponse?> GetAllowedMods(int page, int pageSize, ICollection filters, ICollection sortings, CancellationToken ct = default) + { + var response = await _userClient.GetSteamWorkshopModsPaginateAvailabledAsync(new(page: page, pageSize: pageSize, filters: filters, sortings: sortings), cancellationToken: ct); + return response is { Value: { } data } ? new(data.Metadata, data.Items, data.AdditionalMetadata) : null; + } + + private async Task OnClick(UserLinkedSteamWorkshopModModel? mod) + { + if (mod is null) + return; + + await _jsRuntime.InvokeVoidAsync("open", mod.Url(), "_blank"); + } + + private async Task OnDelete(ButtonRowContext context) + { + if (context.DeleteCommand.Item is not null && await DoUnlinkMod(context.DeleteCommand.Item)) + { + await context.DeleteCommand.Clicked.InvokeAsync(); + } + } +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Client/Services/NexusModsUserClientWithDemo.cs b/src/BUTR.Site.NexusMods.Client/Services/NexusModsUserClientWithDemo.cs index 6913929f..3150b81d 100644 --- a/src/BUTR.Site.NexusMods.Client/Services/NexusModsUserClientWithDemo.cs +++ b/src/BUTR.Site.NexusMods.Client/Services/NexusModsUserClientWithDemo.cs @@ -186,15 +186,30 @@ public async Task RemoveNexusModsModManualLinkAsync(int mo return await _implementation.RemoveNexusModsModManualLinkAsync(modId, userId, username, ct); } + + public async Task AddSteamWorkshopModManualLinkAsync(string modId, int? userId = null, string? username = null, CancellationToken ct = default(CancellationToken)) + { + return await _implementation.AddSteamWorkshopModManualLinkAsync(modId, userId, username, ct); + } + + public async Task RemoveSteamWorkshopModManualLinkAsync(string modId, int? userId = null, string? username = null, CancellationToken ct = default(CancellationToken)) + { + return await _implementation.RemoveSteamWorkshopModManualLinkAsync(modId, userId, username, ct); + } + + public async Task GetSteamWorkshopModManualLinkPaginatedAsync(PaginatedQuery? body = null, CancellationToken ct = default(CancellationToken)) + { + return await _implementation.GetSteamWorkshopModManualLinkPaginatedAsync(body, ct); + } - public async Task GetNexusModsModManualLinkPaginatedAsync(PaginatedQuery? body = null, CancellationToken ct = default) + public async Task GetNexusModsModManualLinkPaginatedAsync(PaginatedQuery? body = null, CancellationToken ct = default) { if (body is null) return await _implementation.GetNexusModsModManualLinkPaginatedAsync(body, ct); var token = await _tokenContainer.GetTokenAsync(ct); if (token?.Type.Equals("demo", StringComparison.OrdinalIgnoreCase) == true) - return new UserManuallyLinkedModModelPagingDataApiResultModel(new UserManuallyLinkedModModelPagingData(PagingAdditionalMetadata.Empty, new List(), new PagingMetadata(1, 1, body.PageSize, 1)), null!); + return new UserManuallyLinkedNexusModsModModelPagingDataApiResultModel(new UserManuallyLinkedNexusModsModModelPagingData(PagingAdditionalMetadata.Empty, new List(), new PagingMetadata(1, 1, body.PageSize, 1)), null!); return await _implementation.GetNexusModsModManualLinkPaginatedAsync(body, ct); } diff --git a/src/BUTR.Site.NexusMods.Server.Persistence/IUnitOfRead.cs b/src/BUTR.Site.NexusMods.Server.Persistence/IUnitOfRead.cs index ee5b50da..1e49ac4a 100644 --- a/src/BUTR.Site.NexusMods.Server.Persistence/IUnitOfRead.cs +++ b/src/BUTR.Site.NexusMods.Server.Persistence/IUnitOfRead.cs @@ -35,6 +35,7 @@ public interface IUnitOfRead : IDisposable, IAsyncDisposable INexusModsUserToNameEntityRepositoryRead NexusModsUserToName { get; } INexusModsUserToCrashReportEntityRepositoryRead NexusModsUserToCrashReports { get; } INexusModsUserToNexusModsModEntityRepositoryRead NexusModsUserToNexusModsMods { get; } + INexusModsUserToSteamWorkshopModEntityRepositoryRead NexusModsUserToSteamWorkshopMods { get; } INexusModsUserToModuleEntityRepositoryRead NexusModsUserToModules { get; } diff --git a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsModToModuleEntityRepository.cs b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsModToModuleEntityRepository.cs index 90430481..9e47f925 100644 --- a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsModToModuleEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsModToModuleEntityRepository.cs @@ -17,7 +17,7 @@ public sealed record LinkedByStaffNexusModsModModel public sealed record LinkedByStaffModuleNexusModsModsModel { public required ModuleId ModuleId { get; init; } - public required LinkedByStaffNexusModsModModel[] NexusModsMods { get; init; } + public required LinkedByStaffNexusModsModModel[] Mods { get; init; } } public sealed record LinkedByExposureModuleModel @@ -51,7 +51,7 @@ public sealed record LinkedByStaffSteamWorkshopModModel public sealed record LinkedByStaffModuleSteamWorkshopModsModel { public required ModuleId ModuleId { get; init; } - public required LinkedByStaffSteamWorkshopModModel[] NexusModsMods { get; init; } + public required LinkedByStaffSteamWorkshopModModel[] Mods { get; init; } } public sealed record LinkedByExposureSteamWorkshopModModelsModel diff --git a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToNexusModsModEntityRepository.cs b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToNexusModsModEntityRepository.cs index 7ee04b7e..342093ce 100644 --- a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToNexusModsModEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToNexusModsModEntityRepository.cs @@ -12,7 +12,7 @@ public sealed record UserManuallyLinkedModUserModel public required NexusModsUserId NexusModsUserId { get; init; } public required NexusModsUserName NexusModsUsername { get; init; } } -public sealed record UserManuallyLinkedModModel +public sealed record UserManuallyLinkedNexusModsModModel { public required NexusModsModId NexusModsModId { get; init; } public required UserManuallyLinkedModUserModel[] NexusModsUsers { get; init; } @@ -20,6 +20,6 @@ public sealed record UserManuallyLinkedModModel public interface INexusModsUserToNexusModsModEntityRepositoryRead : IRepositoryRead { - Task> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct); + Task> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct); } public interface INexusModsUserToNexusModsModEntityRepositoryWrite : IRepositoryWrite, INexusModsUserToNexusModsModEntityRepositoryRead; \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs index b7c659d4..1fdaddb2 100644 --- a/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server.Persistence/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs @@ -1,6 +1,20 @@ +using System.Threading; +using System.Threading.Tasks; +using BUTR.Site.NexusMods.Server.Models; +using BUTR.Site.NexusMods.Server.Models.API; using BUTR.Site.NexusMods.Server.Models.Database; namespace BUTR.Site.NexusMods.Server.Repositories; -public interface INexusModsUserToSteamWorkshopModEntityRepositoryRead : IRepositoryRead; +public sealed record UserManuallyLinkedSteamWorkshopModModel +{ + public required SteamWorkshopModId SteamWorkshopModId { get; init; } + public required UserManuallyLinkedModUserModel[] NexusModsUsers { get; init; } +} + +public interface INexusModsUserToSteamWorkshopModEntityRepositoryRead : IRepositoryRead +{ + Task> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct); +} + public interface INexusModsUserToSteamWorkshopModEntityRepositoryWrite : IRepositoryWrite, INexusModsUserToSteamWorkshopModEntityRepositoryRead; \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server/Contexts/BaseAppDbContext.cs b/src/BUTR.Site.NexusMods.Server/Contexts/BaseAppDbContext.cs index d1fb93a7..380cc053 100644 --- a/src/BUTR.Site.NexusMods.Server/Contexts/BaseAppDbContext.cs +++ b/src/BUTR.Site.NexusMods.Server/Contexts/BaseAppDbContext.cs @@ -143,7 +143,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) _entityConfigurationFactory.ApplyConfigurationWithTenant(modelBuilder); _entityConfigurationFactory.ApplyConfigurationWithTenant(modelBuilder); _entityConfigurationFactory.ApplyConfigurationWithTenant(modelBuilder); - + _entityConfigurationFactory.ApplyConfiguration(modelBuilder); _entityConfigurationFactory.ApplyConfigurationWithTenant(modelBuilder); diff --git a/src/BUTR.Site.NexusMods.Server/Controllers/NexusModsUserController.cs b/src/BUTR.Site.NexusMods.Server/Controllers/NexusModsUserController.cs index 86d5e562..08f7277c 100644 --- a/src/BUTR.Site.NexusMods.Server/Controllers/NexusModsUserController.cs +++ b/src/BUTR.Site.NexusMods.Server/Controllers/NexusModsUserController.cs @@ -544,7 +544,7 @@ public NexusModsUserController(ILogger logger, INexusMo } [HttpPost("NexusModsModManualLinks/Paginated")] - public async Task?>> GetNexusModsModManualLinkPaginatedAsync([FromBody] PaginatedQuery query, CancellationToken ct) + public async Task?>> GetNexusModsModManualLinkPaginatedAsync([FromBody] PaginatedQuery query, CancellationToken ct) { var userId = HttpContext.GetUserId(); @@ -554,4 +554,106 @@ public NexusModsUserController(ILogger logger, INexusMo return ApiPagingResult(paginated); } + + + [HttpPost("SteamWorkshopModManualLinks")] + public async Task> AddSteamWorkshopModManualLinkAsync([FromQuery, Required] SteamWorkshopModId modId, [FromQuery] NexusModsUserId? userId, [FromQuery] NexusModsUserName? username, [BindTenant] TenantId tenant, CancellationToken ct) + { + var nexusModsUserId = await GetUserIdAsync(userId, username, ct); + if (nexusModsUserId == NexusModsUserId.None) + return ApiBadRequest("User not found!"); + + var currentUserId = HttpContext.GetUserId(); + if (currentUserId != nexusModsUserId && HttpContext.GetRole() != ApplicationRoles.Moderator && HttpContext.GetRole() != ApplicationRoles.Administrator) + return ApiBadRequest("Permission denied!"); + + var tokens = HttpContext.GetSteamTokens(); + if (tokens is null) + return ApiBadRequest("Steam not linked!"); + + var steamUserId = SteamUserId.From(tokens.ExternalId); + + return await AddSteamWorkshopModManualLinkWithApiKeyAsync(steamUserId, modId, nexusModsUserId, tenant, ct); + } + private async Task> AddSteamWorkshopModManualLinkWithApiKeyAsync(SteamUserId steamUserId, SteamWorkshopModId modId, NexusModsUserId userId, TenantId tenant, CancellationToken ct) + { + var steamWorkshopItemInfo = default(SteamWorkshopItemInfo); + foreach (var steamAppId in TenantUtils.FromTenantToSteamAppIds(tenant.Value)) + { + steamWorkshopItemInfo = await _steamAPIClient.GetOwnedWorkshopItemAsync(steamUserId, steamAppId, modId, ct); + if (steamWorkshopItemInfo is not null) break; + } + + if (steamWorkshopItemInfo is null) + return ApiBadRequest("Steam Workshop Item not owned!"); + + await using var unitOfWrite = _unitOfWorkFactory.CreateUnitOfWrite(); + + var steamWorkshopModToName = new SteamWorkshopModToNameEntity + { + TenantId = tenant, + SteamWorkshopModId = modId, + SteamWorkshopMod = unitOfWrite.UpsertEntityFactory.GetOrCreateSteamWorkshopMod(modId), + Name = steamWorkshopItemInfo.Name, + }; + unitOfWrite.SteamWorkshopModName.Upsert(steamWorkshopModToName); + + var nexusModsUserToSteamWorkshopMod = new NexusModsUserToSteamWorkshopModEntity[] + { + new() + { + TenantId = tenant, + NexusModsUserId = userId, + NexusModsUser = unitOfWrite.UpsertEntityFactory.GetOrCreateNexusModsUser(userId), + SteamWorkshopModId = modId, + SteamWorkshopMod = unitOfWrite.UpsertEntityFactory.GetOrCreateSteamWorkshopMod(modId), + LinkType = NexusModsUserToModLinkType.ByAPIConfirmation, + }, + new() + { + TenantId = tenant, + NexusModsUserId = userId, + NexusModsUser = unitOfWrite.UpsertEntityFactory.GetOrCreateNexusModsUser(userId), + SteamWorkshopModId = modId, + SteamWorkshopMod = unitOfWrite.UpsertEntityFactory.GetOrCreateSteamWorkshopMod(modId), + LinkType = NexusModsUserToModLinkType.ByOwner, + }, + }; + unitOfWrite.NexusModsUserToSteamWorkshopMods.UpsertRange(nexusModsUserToSteamWorkshopMod); + + await unitOfWrite.SaveChangesAsync(CancellationToken.None); + return ApiResult("Allowed successful!"); + } + + [HttpDelete("SteamWorkshopModManualLinks")] + public async Task> RemoveSteamWorkshopModManualLinkAsync([FromQuery, Required] SteamWorkshopModId modId, [FromQuery] NexusModsUserId? userId, [FromQuery] NexusModsUserName? username, CancellationToken ct) + { + var nexusModsUserId = await GetUserIdAsync(userId, username, ct); + if (nexusModsUserId == NexusModsUserId.None) + return ApiBadRequest("User not found!"); + + var currentUserId = HttpContext.GetUserId(); + if (currentUserId != nexusModsUserId && HttpContext.GetRole() != ApplicationRoles.Moderator && HttpContext.GetRole() != ApplicationRoles.Administrator) + return ApiBadRequest("Permission denied!"); + + await using var unitOfWrite = _unitOfWorkFactory.CreateUnitOfWrite(); + + unitOfWrite.NexusModsUserToSteamWorkshopMods + .Remove(x => x.NexusModsUserId == nexusModsUserId && x.SteamWorkshopModId == modId && x.LinkType == NexusModsUserToModLinkType.ByOwner); + + await unitOfWrite.SaveChangesAsync(CancellationToken.None); + return ApiResult("Disallowed successful!"); + } + + [HttpPost("SteamWorkshopModManualLinks/Paginated")] + public async Task?>> GetSteamWorkshopModManualLinkPaginatedAsync([FromBody] PaginatedQuery query, CancellationToken ct) + { + var userId = HttpContext.GetUserId(); + + await using var unitOfRead = _unitOfWorkFactory.CreateUnitOfRead(); + + var paginated = await unitOfRead.NexusModsUserToSteamWorkshopMods.GetManuallyLinkedPaginatedAsync(userId, query, ct); + + return ApiPagingResult(paginated); + } } \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server/Controllers/SteamController.cs b/src/BUTR.Site.NexusMods.Server/Controllers/SteamController.cs index 758395b7..d055a06d 100644 --- a/src/BUTR.Site.NexusMods.Server/Controllers/SteamController.cs +++ b/src/BUTR.Site.NexusMods.Server/Controllers/SteamController.cs @@ -1,8 +1,12 @@ using BUTR.Site.NexusMods.Server.Extensions; using BUTR.Site.NexusMods.Server.Models; +using BUTR.Site.NexusMods.Server.Models.API; +using BUTR.Site.NexusMods.Server.Models.Database; using BUTR.Site.NexusMods.Server.Options; +using BUTR.Site.NexusMods.Server.Repositories; using BUTR.Site.NexusMods.Server.Services; using BUTR.Site.NexusMods.Server.Utils; +using BUTR.Site.NexusMods.Server.Utils.BindingSources; using BUTR.Site.NexusMods.Server.Utils.Http.ApiResults; using BUTR.Site.NexusMods.Shared.Helpers; @@ -15,10 +19,6 @@ using System.ComponentModel.DataAnnotations; using System.Threading; using System.Threading.Tasks; -using BUTR.Site.NexusMods.Server.Models.API; -using BUTR.Site.NexusMods.Server.Models.Database; -using BUTR.Site.NexusMods.Server.Repositories; -using BUTR.Site.NexusMods.Server.Utils.BindingSources; namespace BUTR.Site.NexusMods.Server.Controllers; @@ -111,8 +111,8 @@ public SteamController(ISteamStorage steamStorage, IOptions opt var result = await _steamAPIClient.GetUserInfoAsync(SteamUserId.From(tokens.ExternalId), ct); return ApiResult(result); } - - + + [HttpPost("ModuleManualLinks")] [ButrNexusModsAuthorization(Roles = $"{ApplicationRoles.Administrator},{ApplicationRoles.Moderator}")] public async Task> AddModuleManualLinkAsync([FromQuery, Required] SteamWorkshopModId modId, [FromQuery, Required] ModuleId moduleId, [BindTenant] TenantId tenant) diff --git a/src/BUTR.Site.NexusMods.Server/Migrations/20241016083519_SteamWorkshop.cs b/src/BUTR.Site.NexusMods.Server/Migrations/20241016083519_SteamWorkshop.cs index 1f933bfe..48b12b40 100644 --- a/src/BUTR.Site.NexusMods.Server/Migrations/20241016083519_SteamWorkshop.cs +++ b/src/BUTR.Site.NexusMods.Server/Migrations/20241016083519_SteamWorkshop.cs @@ -1,6 +1,7 @@ -using System; using Microsoft.EntityFrameworkCore.Migrations; +using System; + #nullable disable namespace BUTR.Site.NexusMods.Server.Migrations @@ -268,4 +269,4 @@ protected override void Down(MigrationBuilder migrationBuilder) newName: "nexusmods_mod_module_link_type_id"); } } -} +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server/Migrations/20241016101519_SteamWorkshop2.cs b/src/BUTR.Site.NexusMods.Server/Migrations/20241016101519_SteamWorkshop2.cs index 00713087..1d3b3dc1 100644 --- a/src/BUTR.Site.NexusMods.Server/Migrations/20241016101519_SteamWorkshop2.cs +++ b/src/BUTR.Site.NexusMods.Server/Migrations/20241016101519_SteamWorkshop2.cs @@ -1,4 +1,4 @@ -using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Migrations; #nullable disable @@ -14,28 +14,28 @@ protected override void Up(MigrationBuilder migrationBuilder) name: "FK_steamworkshop_mod_file_update_steamworkshop_mod_tenant_stea~", table: "steamworkshop_mod_file_update", schema: "steamworkshop_mod"); - + migrationBuilder.DropForeignKey( name: "FK_steamworkshop_mod_module_steamworkshop_mod_tenant_steamwork~", table: "steamworkshop_mod_module", schema: "steamworkshop_mod"); - + migrationBuilder.DropForeignKey( name: "FK_steamworkshop_mod_name_steamworkshop_mod_tenant_steamworksh~", table: "steamworkshop_mod_name", schema: "steamworkshop_mod"); - + migrationBuilder.DropForeignKey( name: "FK_nexusmods_user_steamworkshop_mod_steamworkshop_mod_tenant_s~", table: "nexusmods_user_steamworkshop_mod", schema: "nexusmods_user"); - + migrationBuilder.DropForeignKey( name: "FK_crash_report_module_info_steamworkshop_mod_tenant_steamwork~", table: "crash_report_module_info", schema: "crashreport"); - - + + migrationBuilder.AlterColumn( name: "steamworkshop_mod_name_id", schema: "steamworkshop_mod", @@ -90,8 +90,8 @@ protected override void Up(MigrationBuilder migrationBuilder) oldClrType: typeof(int), oldType: "integer", oldNullable: true); - - + + migrationBuilder.AddForeignKey( name: "FK_steamworkshop_mod_file_update_steamworkshop_mod_tenant_stea~", schema: "steamworkshop_mod", @@ -101,7 +101,7 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "steamworkshop_mod", principalColumns: ["tenant", "steamworkshop_mod_id"], onDelete: ReferentialAction.Cascade); - + migrationBuilder.AddForeignKey( name: "FK_steamworkshop_mod_module_steamworkshop_mod_tenant_steamwork~", schema: "steamworkshop_mod", @@ -111,7 +111,7 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "steamworkshop_mod", principalColumns: ["tenant", "steamworkshop_mod_id"], onDelete: ReferentialAction.Cascade); - + migrationBuilder.AddForeignKey( name: "FK_steamworkshop_mod_name_steamworkshop_mod_tenant_steamworksh~", schema: "steamworkshop_mod", @@ -121,7 +121,7 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "steamworkshop_mod", principalColumns: ["tenant", "steamworkshop_mod_id"], onDelete: ReferentialAction.Cascade); - + migrationBuilder.AddForeignKey( name: "FK_nexusmods_user_steamworkshop_mod_steamworkshop_mod_tenant_s~", schema: "nexusmods_user", @@ -131,7 +131,7 @@ protected override void Up(MigrationBuilder migrationBuilder) principalTable: "steamworkshop_mod", principalColumns: ["tenant", "steamworkshop_mod_id"], onDelete: ReferentialAction.Cascade); - + migrationBuilder.AddForeignKey( name: "FK_crash_report_module_info_steamworkshop_mod_tenant_steamwork~", schema: "crashreport", @@ -202,4 +202,4 @@ protected override void Down(MigrationBuilder migrationBuilder) oldNullable: true); } } -} +} \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfRead.cs b/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfRead.cs index 93cd78cb..1931a205 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfRead.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfRead.cs @@ -46,6 +46,7 @@ internal class UnitOfRead : IUnitOfRead public INexusModsUserToNameEntityRepositoryRead NexusModsUserToName { get; } public INexusModsUserToCrashReportEntityRepositoryRead NexusModsUserToCrashReports { get; } public INexusModsUserToNexusModsModEntityRepositoryRead NexusModsUserToNexusModsMods { get; } + public INexusModsUserToSteamWorkshopModEntityRepositoryRead NexusModsUserToSteamWorkshopMods { get; } public INexusModsUserToModuleEntityRepositoryRead NexusModsUserToModules { get; } public INexusModsUserToIntegrationGitHubEntityRepositoryRead NexusModsUserToGitHub { get; } @@ -87,7 +88,7 @@ public UnitOfRead(IServiceScopeFactory serviceScopeFactory) StatisticsCrashReportsPerMonth = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsArticles = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); - + NexusModsModModules = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsModName = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsModToModuleInfoHistory = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); @@ -100,6 +101,7 @@ public UnitOfRead(IServiceScopeFactory serviceScopeFactory) NexusModsUserToName = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsUserToCrashReports = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsUserToNexusModsMods = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); + NexusModsUserToSteamWorkshopMods = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsUserToModules = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); NexusModsUserToGitHub = ActivatorUtilities.CreateInstance(_serviceScope.ServiceProvider, dbContextProvider); diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfWrite.cs b/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfWrite.cs index 8bbd3d96..8f541cea 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfWrite.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/IUnitOfWrite.cs @@ -44,7 +44,7 @@ internal class UnitOfWrite : IUnitOfWrite public INexusModsModToNameEntityRepositoryWrite NexusModsModName { get; } public INexusModsModToModuleInfoHistoryEntityRepositoryWrite NexusModsModToModuleInfoHistory { get; } public INexusModsModToFileUpdateEntityRepositoryWrite NexusModsModToFileUpdates { get; } - + public ISteamWorkshopModToModuleEntityRepositoryWrite SteamWorkshopModModules { get; } public ISteamWorkshopModToNameEntityRepositoryWrite SteamWorkshopModName { get; } diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsModToModuleEntityRepository.cs b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsModToModuleEntityRepository.cs index c8840158..c8e1459f 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsModToModuleEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsModToModuleEntityRepository.cs @@ -29,7 +29,7 @@ public async Task> GetByStaffPagin .Select(x => new LinkedByStaffModuleNexusModsModsModel { ModuleId = x.Key.ModuleId, - NexusModsMods = x.Select(y => new LinkedByStaffNexusModsModModel + Mods = x.Select(y => new LinkedByStaffNexusModsModModel { NexusModsModId = y.NexusModsModId, LastCheckedDate = y.LastUpdateDate.ToUniversalTime(), diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToNexusModsModEntityRepository.cs b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToNexusModsModEntityRepository.cs index 8fce5e2e..e8740540 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToNexusModsModEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToNexusModsModEntityRepository.cs @@ -22,11 +22,11 @@ internal class NexusModsUserToNexusModsModEntityRepository : Repository> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct) => await _dbContext.NexusModsUserToNexusModsMods + public async Task> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct) => await _dbContext.NexusModsUserToNexusModsMods .Include(x => x.NexusModsUser).ThenInclude(x => x.Name) .Where(x => x.NexusModsUserId == userId && x.LinkType == NexusModsUserToModLinkType.ByOwner) .GroupBy(x => new { x.NexusModsModId }) - .Select(x => new UserManuallyLinkedModModel + .Select(x => new UserManuallyLinkedNexusModsModModel { NexusModsModId = x.Key.NexusModsModId, NexusModsUsers = x.Select(y => new UserManuallyLinkedModUserModel diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs index 4c9a1e35..d9a4cacd 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/NexusModsUserToSteamWorkshopModEntityRepository.cs @@ -1,10 +1,15 @@ using BUTR.Site.NexusMods.DependencyInjection; using BUTR.Site.NexusMods.Server.Contexts; +using BUTR.Site.NexusMods.Server.Extensions; +using BUTR.Site.NexusMods.Server.Models; +using BUTR.Site.NexusMods.Server.Models.API; using BUTR.Site.NexusMods.Server.Models.Database; using Microsoft.EntityFrameworkCore; using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace BUTR.Site.NexusMods.Server.Repositories; @@ -16,4 +21,19 @@ internal class NexusModsUserToSteamWorkshopModEntityRepository : Repository x.SteamWorkshopMod); public NexusModsUserToSteamWorkshopModEntityRepository(IAppDbContextProvider appDbContextProvider) : base(appDbContextProvider.Get()) { } + + public async Task> GetManuallyLinkedPaginatedAsync(NexusModsUserId userId, PaginatedQuery query, CancellationToken ct) => await _dbContext.NexusModsUserToSteamWorkshopMods + .Include(x => x.NexusModsUser).ThenInclude(x => x.Name) + .Where(x => x.NexusModsUserId == userId && x.LinkType == NexusModsUserToModLinkType.ByOwner) + .GroupBy(x => new { x.SteamWorkshopModId }) + .Select(x => new UserManuallyLinkedSteamWorkshopModModel + { + SteamWorkshopModId = x.Key.SteamWorkshopModId, + NexusModsUsers = x.Select(y => new UserManuallyLinkedModUserModel + { + NexusModsUserId = y.NexusModsUserId, + NexusModsUsername = y.NexusModsUser.Name!.Name, + }).ToArray(), + }) + .PaginatedAsync(query, 20, new() { Property = nameof(UserManuallyLinkedSteamWorkshopModModel.SteamWorkshopModId), Type = SortingType.Ascending }, ct); } \ No newline at end of file diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToModuleEntityRepository.cs b/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToModuleEntityRepository.cs index 13da1128..103ab33d 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToModuleEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToModuleEntityRepository.cs @@ -1,14 +1,16 @@ -using System.Linq; -using System.Threading; -using System.Threading.Tasks; using BUTR.Site.NexusMods.DependencyInjection; using BUTR.Site.NexusMods.Server.Contexts; using BUTR.Site.NexusMods.Server.Extensions; using BUTR.Site.NexusMods.Server.Models; using BUTR.Site.NexusMods.Server.Models.API; using BUTR.Site.NexusMods.Server.Models.Database; + using Microsoft.EntityFrameworkCore; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + namespace BUTR.Site.NexusMods.Server.Repositories; [ScopedService] @@ -26,7 +28,7 @@ public async Task> GetByStaffP .Select(x => new LinkedByStaffModuleSteamWorkshopModsModel { ModuleId = x.Key.ModuleId, - NexusModsMods = x.Select(y => new LinkedByStaffSteamWorkshopModModel + Mods = x.Select(y => new LinkedByStaffSteamWorkshopModModel { SteamWorkshopModId = y.SteamWorkshopModId, LastCheckedDate = y.LastUpdateDate.ToUniversalTime(), diff --git a/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToNameEntityRepository.cs b/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToNameEntityRepository.cs index 4977a2e6..41c0c809 100644 --- a/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToNameEntityRepository.cs +++ b/src/BUTR.Site.NexusMods.Server/Repositories/SteamWorkshopModToNameEntityRepository.cs @@ -1,9 +1,11 @@ -using System.Linq; using BUTR.Site.NexusMods.DependencyInjection; using BUTR.Site.NexusMods.Server.Contexts; using BUTR.Site.NexusMods.Server.Models.Database; + using Microsoft.EntityFrameworkCore; +using System.Linq; + namespace BUTR.Site.NexusMods.Server.Repositories; [ScopedService]