using AutoMapper; using LANCommander.Server.Data.Models; using LANCommander.Server.Extensions; using LANCommander.Server.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace LANCommander.Server.Controllers.Api { [Authorize(AuthenticationSchemes = "Bearer")] [Route("api/[controller]")] [ApiController] public class SavesController : BaseApiController { private readonly IMapper Mapper; private readonly GameService GameService; private readonly GameSaveService GameSaveService; private readonly UserService UserService; public SavesController( ILogger logger, IMapper mapper, GameService gameService, GameSaveService gameSaveService, UserService userService) : base(logger) { Mapper = mapper; GameService = gameService; GameSaveService = gameSaveService; UserService = userService; } [HttpGet] public async Task>> GetAsync() { return Ok(Mapper.Map>(await GameSaveService.GetAsync())); } [HttpGet("{id}")] public async Task> GetAsync(Guid id) { var gameSave = await GameSaveService.GetAsync(id); if (gameSave == null) return NotFound(); return Ok(Mapper.Map(gameSave)); } [HttpGet("Game/{gameId}")] public async Task>> GetGameSavesAsync(Guid gameId) { var user = await UserService.GetAsync(User?.Identity?.Name); if (user == null) return Unauthorized(); var userSaves = await GameSaveService.GetAsync(gs => gs.UserId == user.Id && gs.GameId == gameId); return Ok(Mapper.Map>(userSaves)); } [HttpGet("Latest/{gameId}")] public async Task> LatestAsync(Guid gameId) { var user = await UserService.GetAsync(User?.Identity?.Name); if (user == null) return Unauthorized(); var latestSave = await GameSaveService.Query(q => { return q.OrderByDescending(s => s.CreatedOn); }).FirstOrDefaultAsync(gs => gs.UserId == user.Id && gs.GameId == gameId); // Should probably return 404 if no latest save exists // Not sure if this will affect launcher stability return Ok(Mapper.Map(latestSave)); } [HttpGet("DownloadLatest/{gameId}")] public async Task DownloadLatestAsync(Guid gameId) { var user = await UserService.GetAsync(User?.Identity?.Name); if (user == null) return NotFound(); var save = await GameSaveService.Query(q => { return q.OrderByDescending(s => s.CreatedOn); }).FirstOrDefaultAsync(gs => gs.UserId == user.Id && gs.GameId == gameId); if (save == null) return NotFound(); var filename = save.GetUploadPath(); if (!System.IO.File.Exists(filename)) return NotFound(); return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{save.Id.ToString().SanitizeFilename()}.zip"); } [HttpGet("Download/{id}")] public async Task DownloadAsync(Guid id) { var save = await GameSaveService.GetAsync(id); if (save == null) return NotFound(); var filename = save.GetUploadPath(); if (!System.IO.File.Exists(filename)) return NotFound(); return File(new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read), "application/octet-stream", $"{save.Id.ToString().SanitizeFilename()}.zip"); } [HttpPost("Upload/{id}")] public async Task UploadAsync(Guid id) { var file = Request.Form.Files.First(); var user = await UserService.GetAsync(User?.Identity?.Name); var game = await GameService.GetAsync(id); if (game == null) return NotFound(); var save = new GameSave() { GameId = id, UserId = user.Id, Size = file.Length, }; save = await GameSaveService.AddAsync(save); var saveUploadPath = Path.GetDirectoryName(save.GetUploadPath()); if (!Directory.Exists(saveUploadPath)) Directory.CreateDirectory(saveUploadPath); using (var stream = System.IO.File.Create(save.GetUploadPath())) { await file.CopyToAsync(stream); } if (Settings.UserSaves.MaxSaves > 0) { var saves = (await GameSaveService.GetAsync(gs => gs.UserId == user.Id && gs.GameId == game.Id)).OrderByDescending(gs => gs.CreatedOn).Skip(Settings.UserSaves.MaxSaves).ToList(); foreach (var extraSave in saves) await GameSaveService.DeleteAsync(extraSave); } return Ok(Mapper.Map(save)); } [HttpDelete("Delete/{id}")] public async Task DeleteAsync(Guid id) { try { var save = await GameSaveService.GetAsync(id); await GameSaveService.DeleteAsync(save); return Ok(); } catch (Exception ex) { Logger.LogError(ex, "An unknown error occurred while trying to delete a game save with the ID {GameSaveId}", id); return BadRequest(); } } } }