using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using MoonCore.Extended.Abstractions; using MoonlightServers.ApiServer.Database.Entities; using MoonlightServers.ApiServer.Services; using MoonlightServers.DaemonShared.Enums; using MoonlightServers.Shared.Constants; using MoonlightServers.Shared.Enums; using MoonlightServers.Shared.Http.Requests.Client.Servers.Files; using MoonlightServers.Shared.Http.Responses.Client.Servers.Files; namespace MoonlightServers.ApiServer.Http.Controllers.Client; [Authorize] [ApiController] [Route("api/client/servers/{serverId:int}/files")] public class FilesController : Controller { private readonly DatabaseRepository ServerRepository; private readonly ServerFileSystemService ServerFileSystemService; private readonly NodeService NodeService; private readonly ServerAuthorizeService AuthorizeService; public FilesController( DatabaseRepository serverRepository, ServerFileSystemService serverFileSystemService, NodeService nodeService, ServerAuthorizeService authorizeService ) { ServerRepository = serverRepository; ServerFileSystemService = serverFileSystemService; NodeService = nodeService; AuthorizeService = authorizeService; } [HttpGet("list")] public async Task> ListAsync([FromRoute] int serverId, [FromQuery] string path) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.Read); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); var entries = await ServerFileSystemService.ListAsync(server.Value, path); return entries.Select(x => new ServerFilesEntryResponse() { Name = x.Name, Size = x.Size, IsFolder = x.IsFolder, CreatedAt = x.CreatedAt, UpdatedAt = x.UpdatedAt }).ToArray(); } [HttpPost("move")] public async Task MoveAsync([FromRoute] int serverId, [FromQuery] string oldPath, [FromQuery] string newPath) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); await ServerFileSystemService.MoveAsync(server.Value, oldPath, newPath); return NoContent(); } [HttpDelete("delete")] public async Task DeleteAsync([FromRoute] int serverId, [FromQuery] string path) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); await ServerFileSystemService.DeleteAsync(server.Value, path); return NoContent(); } [HttpPost("mkdir")] public async Task MkdirAsync([FromRoute] int serverId, [FromQuery] string path) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); await ServerFileSystemService.MkdirAsync(server.Value, path); return NoContent(); } [HttpPost("touch")] public async Task TouchAsync([FromRoute] int serverId, [FromQuery] string path) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); await ServerFileSystemService.MkdirAsync(server.Value, path); return NoContent(); } [HttpGet("upload")] public async Task> UploadAsync([FromRoute] int serverId) { var serverResult = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (serverResult.Value == null) return serverResult.Result ?? Problem("Unable to retrieve server"); var server = serverResult.Value; var accessToken = NodeService.CreateAccessToken( server.Node, parameters => { parameters.Add("type", "upload"); parameters.Add("serverId", server.Id); }, TimeSpan.FromMinutes(1) ); var url = ""; url += server.Node.UseSsl ? "https://" : "http://"; url += $"{server.Node.Fqdn}:{server.Node.HttpPort}/"; url += $"api/servers/upload?access_token={accessToken}"; return new ServerFilesUploadResponse() { UploadUrl = url }; } [HttpGet("download")] public async Task> DownloadAsync([FromRoute] int serverId, [FromQuery] string path) { var serverResult = await GetServerByIdAsync(serverId, ServerPermissionLevel.Read); if (serverResult.Value == null) return serverResult.Result ?? Problem("Unable to retrieve server"); var server = serverResult.Value; var accessToken = NodeService.CreateAccessToken( server.Node, parameters => { parameters.Add("type", "download"); parameters.Add("path", path); parameters.Add("serverId", server.Id); }, TimeSpan.FromMinutes(1) ); var url = ""; url += server.Node.UseSsl ? "https://" : "http://"; url += $"{server.Node.Fqdn}:{server.Node.HttpPort}/"; url += $"api/servers/download?access_token={accessToken}"; return new ServerFilesDownloadResponse() { DownloadUrl = url }; } [HttpPost("compress")] public async Task CompressAsync([FromRoute] int serverId, [FromBody] ServerFilesCompressRequest request) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); if (!Enum.TryParse(request.Type, true, out CompressType type)) return Problem("Invalid compress type provided", statusCode: 400); await ServerFileSystemService.CompressAsync(server.Value, type, request.Items, request.Destination); return Ok(); } [HttpPost("decompress")] public async Task DecompressAsync([FromRoute] int serverId, [FromBody] ServerFilesDecompressRequest request) { var server = await GetServerByIdAsync(serverId, ServerPermissionLevel.ReadWrite); if (server.Value == null) return server.Result ?? Problem("Unable to retrieve server"); if (!Enum.TryParse(request.Type, true, out CompressType type)) return Problem("Invalid decompress type provided", statusCode: 400); await ServerFileSystemService.DecompressAsync(server.Value, type, request.Path, request.Destination); return NoContent(); } private async Task> GetServerByIdAsync(int serverId, ServerPermissionLevel level) { var server = await ServerRepository .Get() .Include(x => x.Node) .FirstOrDefaultAsync(x => x.Id == serverId); if (server == null) return Problem("No server with this id found", statusCode: 404); var authorizeResult = await AuthorizeService.AuthorizeAsync( User, server, ServerPermissionConstants.Files, level ); if (!authorizeResult.Succeeded) { return Problem( authorizeResult.Message ?? "No permission for the requested resource", statusCode: 403 ); } return server; } }