From 5f604b3052dab1d51dc130df2470bf330b283ec6 Mon Sep 17 00:00:00 2001 From: ivar Date: Tue, 19 Mar 2024 01:02:22 +0100 Subject: Max lenghts on db schema Use latest temporal from cdn Implement majority of translation functionality Major refinements/bugs --- code/api/Endpoints/Account/CreateEndpoint.cs | 84 +++++++--------- code/api/Endpoints/Account/DeleteEndpoint.cs | 24 ++--- code/api/Endpoints/Account/LoginEndpoint.cs | 52 ++++------ code/api/Endpoints/Account/LogoutEndpoint.cs | 14 +-- code/api/Endpoints/EndpointBase.cs | 38 +++---- code/api/Endpoints/Storage/Files/CreateEndpoint.cs | 2 +- code/api/Endpoints/Storage/Files/DeleteEndpoint.cs | 2 +- code/api/Endpoints/Storage/Files/PutEndpoint.cs | 2 +- .../Endpoints/Storage/Folders/CreateEndpoint.cs | 2 +- .../Endpoints/Storage/Folders/DeleteEndpoint.cs | 2 +- .../Storage/Shares/CreateShareEndpoint.cs | 2 +- .../Storage/Shares/DeleteShareEndpoint.cs | 2 +- .../Endpoints/Storage/Shares/EditShareEndpoint.cs | 2 +- code/api/Endpoints/Storage/TreeEndpoint.cs | 55 +++++----- code/api/Endpoints/Storage/UploadEndpoint.cs | 112 ++++++++++----------- code/api/Endpoints/_Root/SessionEndpoint.cs | 12 +-- 16 files changed, 182 insertions(+), 225 deletions(-) (limited to 'code/api/Endpoints') diff --git a/code/api/Endpoints/Account/CreateEndpoint.cs b/code/api/Endpoints/Account/CreateEndpoint.cs index 4cea8f1..59d954c 100644 --- a/code/api/Endpoints/Account/CreateEndpoint.cs +++ b/code/api/Endpoints/Account/CreateEndpoint.cs @@ -1,52 +1,42 @@ -namespace I2R.Storage.Api.Endpoints.Account; +namespace Quality.Storage.Api.Endpoints.Account; -public class CreateEndpoint : EndpointBase +public class CreateEndpoint(AppDatabase database, UserService userService, IStringLocalizer localizer) : EndpointBase { - private readonly AppDatabase _database; - private readonly UserService _userService; - private readonly IStringLocalizer _localizer; + public new class Request + { + public string Username { get; set; } + public string Password { get; set; } + public string FirstName { get; set; } + public string LastName { get; set; } + } - public CreateEndpoint(AppDatabase database, UserService userService, IStringLocalizer localizer) { - _database = database; - _userService = userService; - _localizer = localizer; - } + public new class Response + { + public Guid Id { get; set; } + public string Username { get; set; } + public UserRole Role { get; set; } + } - public new class Request - { - public string Username { get; set; } - public string Password { get; set; } - public string FirstName { get; set; } - public string LastName { get; set; } - } + [AllowAnonymous] + [HttpPost("~/account/create")] + public ActionResult Handle([FromBody] Request request) { + if (!userService.CanCreateAccount(request.Username)) { + return BadRequest(localizer["That username is already taken"]); + } - public new class Response - { - public Guid Id { get; set; } - public string Username { get; set; } - public EUserRole Role { get; set; } - } - - [AllowAnonymous] - [HttpPost("~/account/create")] - public ActionResult Handle([FromBody] Request request) { - if (!_userService.CanCreateAccount(request.Username)) { - return BadRequest(_localizer["That username is already taken"]); - } - - var user = new User() { - Username = request.Username, - Password = PasswordHelper.HashPassword(request.Password), - LastName = request.LastName, - FirstName = request.FirstName, - Role = EUserRole.LEAST_PRIVILEGED, - }; - _database.Users.Add(user); - _database.SaveChanges(); - return Ok(new Response { - Id = user.Id, - Username = user.Username, - Role = user.Role - }); - } -} \ No newline at end of file + var user = new User { + Username = request.Username, + Password = PasswordHelper.HashPassword(request.Password), + LastName = request.LastName, + FirstName = request.FirstName, + Role = UserRole.LEAST_PRIVILEGED, + }; + database.Users.Add(user); + database.SaveChanges(); + return Ok(new Response { + Id = user.Id, + Username = user.Username, + Role = user.Role + }); + } +} diff --git a/code/api/Endpoints/Account/DeleteEndpoint.cs b/code/api/Endpoints/Account/DeleteEndpoint.cs index 75a508a..daf55f2 100644 --- a/code/api/Endpoints/Account/DeleteEndpoint.cs +++ b/code/api/Endpoints/Account/DeleteEndpoint.cs @@ -1,17 +1,11 @@ -namespace I2R.Storage.Api.Endpoints.Account; +namespace Quality.Storage.Api.Endpoints.Account; -public class DeleteEndpoint : EndpointBase +public class DeleteEndpoint(UserService userService) : EndpointBase { - private readonly UserService _userService; - - public DeleteEndpoint(UserService userService) { - _userService = userService; - } - - [HttpDelete("~/account/delete")] - public async Task Handle() { - await _userService.MarkUserAsDeletedAsync(LoggedInUser.Id, LoggedInUser.Id); - await _userService.LogOutUserAsync(HttpContext); - return Ok(); - } -} \ No newline at end of file + [HttpDelete("~/account/delete")] + public async Task Handle() { + await userService.MarkUserAsDeletedAsync(LoggedInUser.Id, LoggedInUser.Id); + await userService.LogOutUserAsync(HttpContext); + return Ok(); + } +} diff --git a/code/api/Endpoints/Account/LoginEndpoint.cs b/code/api/Endpoints/Account/LoginEndpoint.cs index 4f8e434..6cda119 100644 --- a/code/api/Endpoints/Account/LoginEndpoint.cs +++ b/code/api/Endpoints/Account/LoginEndpoint.cs @@ -1,36 +1,26 @@ -namespace I2R.Storage.Api.Endpoints.Account; +namespace Quality.Storage.Api.Endpoints.Account; -public class LoginEndpoint : EndpointBase +public class LoginEndpoint(UserService userService, AppDatabase database, IStringLocalizer localizer) : EndpointBase { - private readonly AppDatabase _database; - private readonly UserService _userService; - private readonly IStringLocalizer _localizer; + public new class Request + { + public string Username { get; set; } + public string Password { get; set; } + } - public new class Request - { - public string Username { get; set; } - public string Password { get; set; } - } + [AllowAnonymous] + [HttpPost("~/account/login")] + public async Task Handle([FromBody] Request request) { + var user = database.Users.FirstOrDefault(c => c.Username == request.Username); + if (user == default) { + return KnownProblem(localizer["Invalid username or password"]); + } - public LoginEndpoint(UserService userService, AppDatabase database, IStringLocalizer localizer) { - _userService = userService; - _database = database; - _localizer = localizer; - } + if (!PasswordHelper.Verify(request.Password, user.Password)) { + return KnownProblem(localizer["Invalid username or password"]); + } - [AllowAnonymous] - [HttpPost("~/account/login")] - public async Task Handle([FromBody] Request request) { - var user = _database.Users.FirstOrDefault(c => c.Username == request.Username); - if (user == default) { - return KnownProblem(_localizer["Invalid username or password"]); - } - - if (!PasswordHelper.Verify(request.Password, user.Password)) { - return KnownProblem(_localizer["Invalid username or password"]); - } - - await _userService.LogInUserAsync(HttpContext, user.DefaultClaims()); - return Ok(); - } -} \ No newline at end of file + await userService.LogInUserAsync(HttpContext, user.DefaultClaims()); + return Ok(); + } +} diff --git a/code/api/Endpoints/Account/LogoutEndpoint.cs b/code/api/Endpoints/Account/LogoutEndpoint.cs index de03e8e..b392dbd 100644 --- a/code/api/Endpoints/Account/LogoutEndpoint.cs +++ b/code/api/Endpoints/Account/LogoutEndpoint.cs @@ -1,16 +1,10 @@ -namespace I2R.Storage.Api.Endpoints.Account; +namespace Quality.Storage.Api.Endpoints.Account; -public class LogoutEndpoint : EndpointBase +public class LogoutEndpoint(UserService userService) : EndpointBase { - private readonly UserService _userService; - - public LogoutEndpoint(UserService userService) { - _userService = userService; - } - - [HttpGet("~/account/logout")] + [HttpGet("~/account/logout")] public async Task Handle() { - await _userService.LogOutUserAsync(HttpContext); + await userService.LogOutUserAsync(HttpContext); return Ok(); } } \ No newline at end of file diff --git a/code/api/Endpoints/EndpointBase.cs b/code/api/Endpoints/EndpointBase.cs index 320ce8d..b2773e1 100644 --- a/code/api/Endpoints/EndpointBase.cs +++ b/code/api/Endpoints/EndpointBase.cs @@ -1,26 +1,26 @@ -namespace I2R.Storage.Api.Endpoints; +namespace Quality.Storage.Api.Endpoints; [ApiController] [Authorize] public class EndpointBase : ControllerBase { - protected LoggedInUserModel LoggedInUser => new(User); + protected LoggedInUserModel LoggedInUser => new(User); - [NonAction] - protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary errors = default) { - HttpContext.Response.Headers.Add(AppHeaders.IS_KNOWN_PROBLEM, "1"); - return BadRequest(new KnownProblemModel { - Title = title, - Subtitle = subtitle, - Errors = errors, - TraceId = HttpContext.TraceIdentifier - }); - } + [NonAction] + protected ActionResult KnownProblem(string title = default, string subtitle = default, Dictionary errors = default) { + HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1"); + return BadRequest(new KnownProblemModel { + Title = title, + Subtitle = subtitle, + Errors = errors, + TraceId = HttpContext.TraceIdentifier + }); + } - [NonAction] - protected ActionResult KnownProblem(KnownProblemModel problem) { - HttpContext.Response.Headers.Add(AppHeaders.IS_KNOWN_PROBLEM, "1"); - problem.TraceId = HttpContext.TraceIdentifier; - return BadRequest(problem); - } -} \ No newline at end of file + [NonAction] + protected ActionResult KnownProblem(KnownProblemModel problem) { + HttpContext.Response.Headers.Append(AppHeaders.IS_KNOWN_PROBLEM, "1"); + problem.TraceId = HttpContext.TraceIdentifier; + return BadRequest(problem); + } +} diff --git a/code/api/Endpoints/Storage/Files/CreateEndpoint.cs b/code/api/Endpoints/Storage/Files/CreateEndpoint.cs index c53a8e3..9206a36 100644 --- a/code/api/Endpoints/Storage/Files/CreateEndpoint.cs +++ b/code/api/Endpoints/Storage/Files/CreateEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Files; +namespace Quality.Storage.Api.Endpoints.Storage.Files; public class CreateEndpoint { diff --git a/code/api/Endpoints/Storage/Files/DeleteEndpoint.cs b/code/api/Endpoints/Storage/Files/DeleteEndpoint.cs index ab95d94..eae8f17 100644 --- a/code/api/Endpoints/Storage/Files/DeleteEndpoint.cs +++ b/code/api/Endpoints/Storage/Files/DeleteEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Files; +namespace Quality.Storage.Api.Endpoints.Storage.Files; public class DeleteEndpoint { diff --git a/code/api/Endpoints/Storage/Files/PutEndpoint.cs b/code/api/Endpoints/Storage/Files/PutEndpoint.cs index 129eeed..982d435 100644 --- a/code/api/Endpoints/Storage/Files/PutEndpoint.cs +++ b/code/api/Endpoints/Storage/Files/PutEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Files; +namespace Quality.Storage.Api.Endpoints.Storage.Files; public class PutEndpoint { diff --git a/code/api/Endpoints/Storage/Folders/CreateEndpoint.cs b/code/api/Endpoints/Storage/Folders/CreateEndpoint.cs index 2eb1352..398d500 100644 --- a/code/api/Endpoints/Storage/Folders/CreateEndpoint.cs +++ b/code/api/Endpoints/Storage/Folders/CreateEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Folders; +namespace Quality.Storage.Api.Endpoints.Storage.Folders; public class CreateEndpoint { diff --git a/code/api/Endpoints/Storage/Folders/DeleteEndpoint.cs b/code/api/Endpoints/Storage/Folders/DeleteEndpoint.cs index 73fa907..84d41c4 100644 --- a/code/api/Endpoints/Storage/Folders/DeleteEndpoint.cs +++ b/code/api/Endpoints/Storage/Folders/DeleteEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Folders; +namespace Quality.Storage.Api.Endpoints.Storage.Folders; public class DeleteEndpoint { diff --git a/code/api/Endpoints/Storage/Shares/CreateShareEndpoint.cs b/code/api/Endpoints/Storage/Shares/CreateShareEndpoint.cs index dd049e7..64eb97b 100644 --- a/code/api/Endpoints/Storage/Shares/CreateShareEndpoint.cs +++ b/code/api/Endpoints/Storage/Shares/CreateShareEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Shares; +namespace Quality.Storage.Api.Endpoints.Storage.Shares; public class CreateShareEndpoint { diff --git a/code/api/Endpoints/Storage/Shares/DeleteShareEndpoint.cs b/code/api/Endpoints/Storage/Shares/DeleteShareEndpoint.cs index ad85887..a8bf0fd 100644 --- a/code/api/Endpoints/Storage/Shares/DeleteShareEndpoint.cs +++ b/code/api/Endpoints/Storage/Shares/DeleteShareEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Shares; +namespace Quality.Storage.Api.Endpoints.Storage.Shares; public class DeleteShareEndpoint { diff --git a/code/api/Endpoints/Storage/Shares/EditShareEndpoint.cs b/code/api/Endpoints/Storage/Shares/EditShareEndpoint.cs index 30e4bf7..c1e8ea8 100644 --- a/code/api/Endpoints/Storage/Shares/EditShareEndpoint.cs +++ b/code/api/Endpoints/Storage/Shares/EditShareEndpoint.cs @@ -1,4 +1,4 @@ -namespace I2R.Storage.Api.Endpoints.Storage.Shares; +namespace Quality.Storage.Api.Endpoints.Storage.Shares; public class EditShareEndpoint { diff --git a/code/api/Endpoints/Storage/TreeEndpoint.cs b/code/api/Endpoints/Storage/TreeEndpoint.cs index f832034..df2ed5e 100644 --- a/code/api/Endpoints/Storage/TreeEndpoint.cs +++ b/code/api/Endpoints/Storage/TreeEndpoint.cs @@ -1,33 +1,26 @@ -namespace I2R.Storage.Api.Endpoints.Storage; +namespace Quality.Storage.Api.Endpoints.Storage; -public class TreeEndpoint : EndpointBase +public class TreeEndpoint(AppDatabase database, IPaginationService pagination) : EndpointBase { - private readonly AppDatabase _database; - private readonly IPaginationService _pagination; - - public TreeEndpoint(AppDatabase database, IPaginationService pagination) { - _database = database; - _pagination = pagination; - } - - [HttpGet("~/storage/tree")] - public async Task>> Handle(Guid parent = default) { - return Ok(await _pagination.KeysetPaginateAsync( - _database.Folders.Include(c => c.Files).ConditionalWhere(() => parent != default, folder => folder.ParentId == parent), - b => b.Descending(a => a.Name), - async id => await _database.Folders.FirstOrDefaultAsync(c => c.Id == id.AsGuid()), - query => query.Select(p => new FileSystemEntry() { - Id = p.Id, - Name = p.Name, - MimeType = SystemConstants.FolderMimeType, - SizeInBytes = -1, - Files = p.Files.Select(c => new FileSystemEntry() { - Id = c.Id, - Name = c.Name, - MimeType = c.MimeType, - SizeInBytes = c.SizeInBytes - }).ToList() - }) - )); - } -} \ No newline at end of file + [HttpGet("~/storage/tree")] + public async Task>> Handle(Guid parent = default) { + return Ok(await pagination.KeysetPaginateAsync(database.Folders + .Include(c => c.Files) + .ConditionalWhere(() => parent != default, folder => folder.ParentId == parent), + b => b.Descending(a => a.Name), + async id => await database.Folders.FirstOrDefaultAsync(c => c.Id == id.AsGuid()), + query => query.Select(p => new FileSystemEntry { + Id = p.Id, + Name = p.Name, + MimeType = SystemConstants.FolderMimeType, + SizeInBytes = -1, + Files = p.Files.Select(c => new FileSystemEntry { + Id = c.Id, + Name = c.Name, + MimeType = c.MimeType, + SizeInBytes = c.SizeInBytes + }) + .ToList() + }))); + } +} diff --git a/code/api/Endpoints/Storage/UploadEndpoint.cs b/code/api/Endpoints/Storage/UploadEndpoint.cs index e3feffb..fa828ae 100644 --- a/code/api/Endpoints/Storage/UploadEndpoint.cs +++ b/code/api/Endpoints/Storage/UploadEndpoint.cs @@ -1,61 +1,57 @@ -using File = I2R.Storage.Api.Database.Models.File; +using Quality.Storage.Api.Services.Abstractions; +using File = Quality.Storage.Api.Database.Models.File; -namespace I2R.Storage.Api.Endpoints.Storage; +namespace Quality.Storage.Api.Endpoints.Storage; -public class UploadEndpoint : EndpointBase +public class UploadEndpoint( + IResourceService resourceService, + IStringLocalizer localizer, + AppDatabase database, + StorageService storageService +) : EndpointBase { - private readonly DefaultResourceService _resourceService; - private readonly IStringLocalizer _localizer; - private readonly AppDatabase _database; - private readonly StorageService _storageService; - - public UploadEndpoint(DefaultResourceService resourceService, IStringLocalizer localizer, AppDatabase database, StorageService storageService) { - _resourceService = resourceService; - _localizer = localizer; - _database = database; - _storageService = storageService; - } - - public class Request - { - public IFormFileCollection FormFileCollection { get; set; } - public Guid FolderId { get; set; } - } - - [HttpPost("~/storage/upload")] - public async Task Handle(Request request) { - var folder = await _storageService.GetFileSystemEntryAsync(request.FolderId); - if (folder == default) { - return NotFound(); - } - - var problem = new KnownProblemModel(); - foreach (var formFile in request.FormFileCollection) { - if (!formFile.FileName.IsValidFileName()) { - problem.AddError("file_" + formFile.Name, _localizer["{fileName} is an invalid file name"]); - continue; - } - - if (problem.Errors.Any()) { - return KnownProblem(problem); - } - - var file = new File(LoggedInUser.Id) { - Name = formFile.FileName, - FolderId = folder.Id, - MimeType = formFile.ContentType, - SizeInBytes = formFile.Length, - OwningUserId = LoggedInUser.Id - }; - var id = new StorageBlobId() { - Id = file.Id, - Bucket = LoggedInUser.Id - }; - await _resourceService.SetBlobAsync(id, formFile.OpenReadStream()); - await _database.Files.AddAsync(file); - await _database.SaveChangesAsync(); - } - - return Ok(await _storageService.GetFileSystemEntryAsync(folder.Id)); - } -} \ No newline at end of file + public new class Request + { + public IFormFileCollection FormFileCollection { get; set; } + public Guid FolderId { get; set; } + } + + [HttpPost("~/storage/upload")] + public async Task Handle(Request request) { + var folder = await storageService.GetFileSystemEntryAsync(request.FolderId); + if (folder == default) { + return NotFound(); + } + + var problem = new KnownProblemModel(); + foreach (var formFile in request.FormFileCollection) { + if (!formFile.FileName.IsValidFileName()) { + problem.AddError("file_" + formFile.Name, localizer["{fileName} is an invalid file name"]); + continue; + } + + if (problem.Errors.Count != 0) { + return KnownProblem(problem); + } + + var file = new File(LoggedInUser.Id) { + Name = formFile.FileName, + FolderId = folder.Id, + MimeType = formFile.ContentType, + SizeInBytes = formFile.Length, + OwningUserId = LoggedInUser.Id + }; + + var id = new StorageBlobId { + Id = file.Id, + Bucket = LoggedInUser.Id + }; + + await resourceService.SetBlobAsync(id, formFile.OpenReadStream()); + await database.Files.AddAsync(file); + await database.SaveChangesAsync(); + } + + return Ok(await storageService.GetFileSystemEntryAsync(folder.Id)); + } +} diff --git a/code/api/Endpoints/_Root/SessionEndpoint.cs b/code/api/Endpoints/_Root/SessionEndpoint.cs index c596dce..ffa476f 100644 --- a/code/api/Endpoints/_Root/SessionEndpoint.cs +++ b/code/api/Endpoints/_Root/SessionEndpoint.cs @@ -1,9 +1,9 @@ -namespace I2R.Storage.Api.Endpoints._Root; +namespace Quality.Storage.Api.Endpoints._Root; public class SessionEndpoint : EndpointBase { - [HttpGet("~/session")] - public ActionResult Handle() { - return LoggedInUserModel.ForThePeople(HttpContext); - } -} \ No newline at end of file + [HttpGet("~/session")] + public ActionResult Handle() { + return LoggedInUserModel.ForThePeople(HttpContext); + } +} -- cgit v1.3