304 lines
No EOL
11 KiB
C#
304 lines
No EOL
11 KiB
C#
using AutoMapper;
|
|
using LANCommander.SDK.Enums;
|
|
using LANCommander.Server.Data.Models;
|
|
using LANCommander.Server.Extensions;
|
|
using LANCommander.Server.Services;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using System.DirectoryServices.AccountManagement;
|
|
using System.Security.Claims;
|
|
using File = System.IO.File;
|
|
using SortDirection = LANCommander.Server.Data.Enums.SortDirection;
|
|
|
|
namespace LANCommander.Server.Endpoints;
|
|
|
|
public static class SaveEndpoints
|
|
{
|
|
public static void MapSaveEndpoints(this IEndpointRouteBuilder routes)
|
|
{
|
|
var group = routes.MapGroup("/api/Saves");
|
|
|
|
group.MapGet("/", GetAsync);
|
|
group.MapGet("/{id:guid}", GetByIdAsync);
|
|
group.MapGet("/{id:guid}/Download", DownloadSaveByIdAsync);
|
|
group.MapDelete("/{id:guid}", DeleteByIdAsync);
|
|
group.MapGet("/Game/{gameId:guid}", GetSavesByGameAsync);
|
|
group.MapPost("/Game/{gameId:guid}/Upload", UploadSaveByGameAsync);
|
|
group.MapGet("/Game/{gameId:guid}/Latest", GetLatestSaveByGameAsync);
|
|
group.MapGet("/Game/{gameId:guid}/Latest/Download", DownloadLatestSaveByGameAsync);
|
|
}
|
|
|
|
public static async Task<IResult> GetAsync(
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var saves = await saveService.GetAsync<SDK.Models.GameSave>(gs => gs.UserId == user.Id);
|
|
|
|
return TypedResults.Ok(saves);
|
|
}
|
|
|
|
public static async Task<IResult> GetByIdAsync(
|
|
Guid id,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var save = await saveService.FirstOrDefaultAsync<SDK.Models.GameSave>(s => s.Id == id);
|
|
|
|
if (save == null)
|
|
return TypedResults.NotFound();
|
|
|
|
return TypedResults.Ok(save);
|
|
}
|
|
|
|
public static async Task<IResult> DeleteByIdAsync(
|
|
Guid id,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var save = await saveService.FirstOrDefaultAsync(s => s.Id == id && s.UserId == user.Id);
|
|
|
|
if (save == null)
|
|
return TypedResults.NotFound();
|
|
|
|
await saveService.DeleteAsync(save);
|
|
|
|
return TypedResults.NoContent();
|
|
}
|
|
|
|
public static async Task<IResult> GetSavesByGameAsync(
|
|
Guid gameId,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var userSaves = await saveService.GetAsync<SDK.Models.GameSave>(gs => gs.UserId == user.Id && gs.GameId == gameId);
|
|
|
|
return TypedResults.Ok(userSaves);
|
|
}
|
|
|
|
public static async Task<IResult> GetLatestSaveByGameAsync(
|
|
Guid gameId,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] IMapper mapper,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var latestSave = await saveService
|
|
.SortBy(s => s.CreatedOn, SortDirection.Descending)
|
|
.FirstOrDefaultAsync(gs => gs.GameId == gameId && gs.UserId == user.Id);
|
|
|
|
if (latestSave == null)
|
|
return TypedResults.NotFound();
|
|
|
|
return TypedResults.Ok(mapper.Map<SDK.Models.Save>(latestSave));
|
|
}
|
|
|
|
public static async Task<IResult> DownloadLatestSaveByGameAsync(
|
|
Guid gameId,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var latestSave = await saveService
|
|
.SortBy(s => s.CreatedOn, SortDirection.Descending)
|
|
.Include(gs => gs.Game)
|
|
.Include(gs => gs.StorageLocation)
|
|
.FirstOrDefaultAsync(gs => gs.GameId == gameId && gs.UserId == user.Id);
|
|
|
|
if (latestSave == null)
|
|
return TypedResults.NotFound();
|
|
|
|
var fileName = latestSave.GetUploadPath();
|
|
|
|
if (!File.Exists(fileName))
|
|
return TypedResults.NotFound();
|
|
|
|
var downloadName = $"{latestSave.Game.Title} - {user.UserName} - {latestSave.CreatedOn}".SanitizeFilename();
|
|
|
|
return TypedResults.File(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{downloadName}.lcs");
|
|
}
|
|
|
|
public static async Task<IResult> DownloadSaveByIdAsync(
|
|
Guid id,
|
|
ClaimsPrincipal userPrincipal,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var save = await saveService
|
|
.Include(s => s.Game)
|
|
.Include(s => s.StorageLocation)
|
|
.FirstOrDefaultAsync(s => s.Id == id && s.UserId == user.Id);
|
|
|
|
var fileName = save.GetUploadPath();
|
|
|
|
if (!File.Exists(fileName))
|
|
return TypedResults.NotFound();
|
|
|
|
var downloadName = $"{save.Game.Title} - {user.UserName} - {save.CreatedOn}".SanitizeFilename();
|
|
|
|
return TypedResults.File(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{downloadName}.lcs");
|
|
}
|
|
|
|
public static async Task<IResult> UploadSaveByGameAsync(
|
|
Guid gameId,
|
|
ClaimsPrincipal userPrincipal,
|
|
HttpContext httpContext,
|
|
[FromServices] ILogger<Program> logger,
|
|
[FromServices] SettingsProvider<Settings.Settings> settingsProvider,
|
|
[FromServices] IMapper mapper,
|
|
[FromServices] UserService userService,
|
|
[FromServices] GameService gameService,
|
|
[FromServices] StorageLocationService storageLocationService,
|
|
[FromServices] GameSaveService saveService)
|
|
{
|
|
var user = await userService.GetAsync(userPrincipal?.Identity?.Name ?? string.Empty);
|
|
|
|
if (user == null)
|
|
{
|
|
logger.LogError("Could not find user from claim principal: {UserName}", userPrincipal?.Identity?.Name);
|
|
|
|
return TypedResults.Unauthorized();
|
|
}
|
|
|
|
var game = await gameService.GetAsync(gameId);
|
|
|
|
if (game == null)
|
|
return TypedResults.NotFound();
|
|
|
|
var saveStorageLocation =
|
|
await storageLocationService.FirstOrDefaultAsync(l => l.Default && l.Type == StorageLocationType.Save);
|
|
|
|
if (saveStorageLocation == null)
|
|
return TypedResults.InternalServerError(
|
|
"There is no save location available on the server. Check your server settings!");
|
|
|
|
var form = await httpContext.Request.ReadFormAsync();
|
|
var file = form.Files.FirstOrDefault();
|
|
|
|
if (file == null)
|
|
return TypedResults.BadRequest("No file was provided in the request.");
|
|
|
|
using (var stream = file.OpenReadStream())
|
|
{
|
|
var save = new GameSave
|
|
{
|
|
Game = game,
|
|
User = user,
|
|
Size = stream.Length,
|
|
StorageLocation = saveStorageLocation,
|
|
};
|
|
|
|
stream.Seek(0, SeekOrigin.Begin);
|
|
|
|
save = await saveService.AddAsync(save);
|
|
|
|
try
|
|
{
|
|
var saveUploadFile = save.GetUploadPath();
|
|
var saveUploadPath = Path.GetDirectoryName(saveUploadFile);
|
|
|
|
if (!Directory.Exists(saveUploadPath))
|
|
Directory.CreateDirectory(saveUploadPath);
|
|
|
|
using (var fs = File.Create(saveUploadFile))
|
|
{
|
|
await stream.CopyToAsync(fs);
|
|
}
|
|
|
|
if (settingsProvider.CurrentValue.Server.UserSaves.MaxSaves > 0)
|
|
{
|
|
var savesToCull = await saveService
|
|
.Query(q =>
|
|
{
|
|
return q
|
|
.Where(s => s.UserId == user.Id && s.GameId == game.Id)
|
|
.OrderByDescending(s => s.CreatedOn)
|
|
.Skip(settingsProvider.CurrentValue.Server.UserSaves.MaxSaves);
|
|
})
|
|
.GetAsync();
|
|
|
|
foreach (var saveToCull in savesToCull)
|
|
await saveService.DeleteAsync(saveToCull);
|
|
}
|
|
|
|
return TypedResults.Ok(mapper.Map<SDK.Models.GameSave>(save));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return TypedResults.InternalServerError(ex);
|
|
}
|
|
}
|
|
}
|
|
} |