diff --git a/Notesnook.API/Controllers/S3Controller.cs b/Notesnook.API/Controllers/S3Controller.cs index 9db9762..6ba6c50 100644 --- a/Notesnook.API/Controllers/S3Controller.cs +++ b/Notesnook.API/Controllers/S3Controller.cs @@ -1,127 +1,128 @@ -/* -This file is part of the Notesnook Sync Server project (https://notesnook.com/) - -Copyright (C) 2023 Streetwriters (Private) Limited - -This program is free software: you can redistribute it and/or modify -it under the terms of the Affero GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -Affero GNU General Public License for more details. - -You should have received a copy of the Affero GNU General Public License -along with this program. If not, see . -*/ - -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Amazon.S3.Model; -using System.Threading.Tasks; -using System.Security.Claims; -using Notesnook.API.Interfaces; -using System; - -namespace Notesnook.API.Controllers -{ - [ApiController] - [Route("s3")] - [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] - public class S3Controller : ControllerBase - { - private IS3Service S3Service { get; set; } - public S3Controller(IS3Service s3Service) - { - S3Service = s3Service; - } - - [HttpPut] - [Authorize("Pro")] - public IActionResult Upload([FromQuery] string name) - { - var userId = this.User.FindFirstValue("sub"); - var url = S3Service.GetUploadObjectUrl(userId, name); - if (url == null) return BadRequest("Could not create signed url."); - return Ok(url); - } - - - [HttpGet("multipart")] - [Authorize("Pro")] - public async Task MultipartUpload([FromQuery] string name, [FromQuery] int parts, [FromQuery] string uploadId) - { - var userId = this.User.FindFirstValue("sub"); - try - { - var meta = await S3Service.StartMultipartUploadAsync(userId, name, parts, uploadId); - return Ok(meta); - } - catch (Exception ex) { return BadRequest(ex.Message); } - } - - [HttpDelete("multipart")] - [Authorize("Pro")] - public async Task AbortMultipartUpload([FromQuery] string name, [FromQuery] string uploadId) - { - var userId = this.User.FindFirstValue("sub"); - try - { - await S3Service.AbortMultipartUploadAsync(userId, name, uploadId); - return Ok(); - } - catch (Exception ex) { return BadRequest(ex.Message); } - } - - [HttpPost("multipart")] - [Authorize("Pro")] - public async Task CompleteMultipartUpload([FromBody] CompleteMultipartUploadRequest uploadRequest) - { - var userId = this.User.FindFirstValue("sub"); - try - { - await S3Service.CompleteMultipartUploadAsync(userId, uploadRequest); - return Ok(); - } - catch (Exception ex) { return BadRequest(ex.Message); } - } - - [HttpGet] - [Authorize("Sync")] - public IActionResult Download([FromQuery] string name) - { - var userId = this.User.FindFirstValue("sub"); - var url = S3Service.GetDownloadObjectUrl(userId, name); - if (url == null) return BadRequest("Could not create signed url."); - return Ok(url); - } - - [HttpHead] - [Authorize("Sync")] - public async Task Info([FromQuery] string name) - { - var userId = this.User.FindFirstValue("sub"); - var size = await S3Service.GetObjectSizeAsync(userId, name); - HttpContext.Response.Headers.ContentLength = size; - return Ok(); - } - - [HttpDelete] - [Authorize("Sync")] - public async Task DeleteAsync([FromQuery] string name) - { - try - { - var userId = this.User.FindFirstValue("sub"); - await S3Service.DeleteObjectAsync(userId, name); - return Ok(); - } - catch (Exception ex) - { - return BadRequest(ex.Message); - } - } - } -} +/* +This file is part of the Notesnook Sync Server project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the Affero GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +Affero GNU General Public License for more details. + +You should have received a copy of the Affero GNU General Public License +along with this program. If not, see . +*/ + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Amazon.S3.Model; +using System.Threading.Tasks; +using System.Security.Claims; +using Notesnook.API.Interfaces; +using System; +using Notesnook.API.Models; + +namespace Notesnook.API.Controllers +{ + [ApiController] + [Route("s3")] + [ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)] + public class S3Controller : ControllerBase + { + private IS3Service S3Service { get; set; } + public S3Controller(IS3Service s3Service) + { + S3Service = s3Service; + } + + [HttpPut] + [Authorize("Pro")] + public IActionResult Upload([FromQuery] string name) + { + var userId = this.User.FindFirstValue("sub"); + var url = S3Service.GetUploadObjectUrl(userId, name); + if (url == null) return BadRequest("Could not create signed url."); + return Ok(url); + } + + + [HttpGet("multipart")] + [Authorize("Pro")] + public async Task MultipartUpload([FromQuery] string name, [FromQuery] int parts, [FromQuery] string uploadId) + { + var userId = this.User.FindFirstValue("sub"); + try + { + var meta = await S3Service.StartMultipartUploadAsync(userId, name, parts, uploadId); + return Ok(meta); + } + catch (Exception ex) { return BadRequest(ex.Message); } + } + + [HttpDelete("multipart")] + [Authorize("Pro")] + public async Task AbortMultipartUpload([FromQuery] string name, [FromQuery] string uploadId) + { + var userId = this.User.FindFirstValue("sub"); + try + { + await S3Service.AbortMultipartUploadAsync(userId, name, uploadId); + return Ok(); + } + catch (Exception ex) { return BadRequest(ex.Message); } + } + + [HttpPost("multipart")] + [Authorize("Pro")] + public async Task CompleteMultipartUpload([FromBody] CompleteMultipartUploadRequestWrapper uploadRequestWrapper) + { + var userId = this.User.FindFirstValue("sub"); + try + { + await S3Service.CompleteMultipartUploadAsync(userId, uploadRequestWrapper.ToRequest()); + return Ok(); + } + catch (Exception ex) { return BadRequest(ex.Message); } + } + + [HttpGet] + [Authorize("Sync")] + public IActionResult Download([FromQuery] string name) + { + var userId = this.User.FindFirstValue("sub"); + var url = S3Service.GetDownloadObjectUrl(userId, name); + if (url == null) return BadRequest("Could not create signed url."); + return Ok(url); + } + + [HttpHead] + [Authorize("Sync")] + public async Task Info([FromQuery] string name) + { + var userId = this.User.FindFirstValue("sub"); + var size = await S3Service.GetObjectSizeAsync(userId, name); + HttpContext.Response.Headers.ContentLength = size; + return Ok(); + } + + [HttpDelete] + [Authorize("Sync")] + public async Task DeleteAsync([FromQuery] string name) + { + try + { + var userId = this.User.FindFirstValue("sub"); + await S3Service.DeleteObjectAsync(userId, name); + return Ok(); + } + catch (Exception ex) + { + return BadRequest(ex.Message); + } + } + } +} \ No newline at end of file diff --git a/Notesnook.API/Models/CompleteMultipartUploadRequestWrapper.cs b/Notesnook.API/Models/CompleteMultipartUploadRequestWrapper.cs new file mode 100644 index 0000000..2fc9fd3 --- /dev/null +++ b/Notesnook.API/Models/CompleteMultipartUploadRequestWrapper.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Amazon.S3.Model; + +namespace Notesnook.API.Models; + +public class CompleteMultipartUploadRequestWrapper +{ + public string Key { get; set; } + public List PartETags { get; set; } + public string UploadId { get; set; } + + public CompleteMultipartUploadRequest ToRequest() + { + CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(); + completeMultipartUploadRequest.Key = Key; + completeMultipartUploadRequest.UploadId = UploadId; + completeMultipartUploadRequest.PartETags = []; + foreach (var partETagWrapper in PartETags) + { + var partETag = new PartETag + { + PartNumber = partETagWrapper.PartNumber, + ETag = partETagWrapper.ETag + }; + completeMultipartUploadRequest.PartETags.Add(partETag); + } + + return completeMultipartUploadRequest; + } +} \ No newline at end of file diff --git a/Notesnook.API/Models/PartETagWrapper.cs b/Notesnook.API/Models/PartETagWrapper.cs new file mode 100644 index 0000000..46b4c9f --- /dev/null +++ b/Notesnook.API/Models/PartETagWrapper.cs @@ -0,0 +1,7 @@ +namespace Notesnook.API.Models; + +public class PartETagWrapper +{ + public int PartNumber { get; set; } + public string ETag { get; set; } +} \ No newline at end of file