diff --git a/src/SF.PhotoPixels.API.Integration.Tests/IntegrationTest.cs b/src/SF.PhotoPixels.API.Integration.Tests/IntegrationTest.cs index 04574ef..fd8db8c 100644 --- a/src/SF.PhotoPixels.API.Integration.Tests/IntegrationTest.cs +++ b/src/SF.PhotoPixels.API.Integration.Tests/IntegrationTest.cs @@ -190,7 +190,7 @@ protected async Task PostTusWhiteImage() var response = await _httpClient.SendAsync(message); - return response.Headers.GetValues("Location").First().Substring(11); + return response.Headers.GetValues("Location").First().Replace("send_data", string.Empty).TrimStart('/'); } private async Task CleanUpDirectories() { diff --git a/src/SF.PhotoPixels.API.Integration.Tests/ResumableEndpoints/DeleteRequestTests.cs b/src/SF.PhotoPixels.API.Integration.Tests/ResumableEndpoints/DeleteRequestTests.cs index d14aa08..bd0b396 100644 --- a/src/SF.PhotoPixels.API.Integration.Tests/ResumableEndpoints/DeleteRequestTests.cs +++ b/src/SF.PhotoPixels.API.Integration.Tests/ResumableEndpoints/DeleteRequestTests.cs @@ -1,5 +1,5 @@ -using FluentAssertions; -using System.Net; +using System.Net; +using FluentAssertions; using Xunit; namespace SF.PhotoPixels.API.Integration.Tests.ResumableEndpoints; @@ -20,7 +20,7 @@ public async Task DeleteUpload_WithValidId_ShouldReturnNoContent() var message = new HttpRequestMessage() { Method = HttpMethod.Delete, - RequestUri = new Uri($"/send_data/{id}", UriKind.Relative) + RequestUri = new Uri($"send_data/{id}", UriKind.Relative) }; message.Headers.Add("Tus-Resumable", "1.0.0"); @@ -39,7 +39,7 @@ public async Task DeleteUpload_WithNonExistingId_ShouldReturnNotFound() var message = new HttpRequestMessage() { Method = HttpMethod.Delete, - RequestUri = new Uri($"/send_data/{Guid.NewGuid():N}", UriKind.Relative) + RequestUri = new Uri($"send_data/{Guid.NewGuid():N}", UriKind.Relative) }; message.Headers.Add("Tus-Resumable", "1.0.0"); diff --git a/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/CreateUploadEndpoint.cs b/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/CreateUploadEndpoint.cs index f5e4925..7ec78a9 100644 --- a/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/CreateUploadEndpoint.cs +++ b/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/CreateUploadEndpoint.cs @@ -1,4 +1,5 @@ using Ardalis.ApiEndpoints; +using JasperFx.Core; using Mediator; using Microsoft.AspNetCore.Mvc; using SF.PhotoPixels.Application.Commands.Tus; @@ -18,7 +19,7 @@ public CreateUploadEndpoint(IMediator mediator) } [UpdateMetadata] - [TusCreation("create_upload")] + [TusCreationPhotopixels("create_upload")] [SwaggerOperation( Summary = "Create and get info on a new upload resource", Tags = ["Tus"]), diff --git a/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/GetUserUploadsEndpoint.cs b/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/GetUserUploadsEndpoint.cs index 2cb8ac3..2587daa 100644 --- a/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/GetUserUploadsEndpoint.cs +++ b/src/SF.PhotoPixels.API/Endpoints/ResumableUploadsEndpoints/GetUserUploadsEndpoint.cs @@ -14,7 +14,7 @@ public GetUserUploadsEndpoint(IMediator mediator) { _mediator = mediator; } - [HttpGet("/resumable_uploads")] + [HttpGet("resumable_uploads")] [SwaggerOperation( Summary = "Get User current resumable uploads", Tags = ["Tus"]), diff --git a/src/SF.PhotoPixels.API/Extensions/TusCreationPhotopixelsAttribute.cs b/src/SF.PhotoPixels.API/Extensions/TusCreationPhotopixelsAttribute.cs new file mode 100644 index 0000000..098523f --- /dev/null +++ b/src/SF.PhotoPixels.API/Extensions/TusCreationPhotopixelsAttribute.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.Extensions.DependencyInjection; +using SolidTUS.Constants; +using SolidTUS.Models; +using SolidTUS.ProtocolFlows; +using SolidTUS.ProtocolHandlers; +using System.Diagnostics; +using System.Linq; +using Microsoft.AspNetCore.Routing; +using Endpoints = System.Collections.Generic.IEnumerable; + +using static Microsoft.AspNetCore.Http.HttpMethods; +using SolidTUS.Functional.Models; +namespace SolidTUS.Attributes; + +/// +/// Identifies an action that supports TUS resource creation. +/// +[AttributeUsage(AttributeTargets.Method)] +public class TusCreationPhotopixelsAttribute : TusCreationAttribute +{ + /// + /// Instantiate a new object of + /// + public TusCreationPhotopixelsAttribute() + { + } + + /// + /// Instantiate a new creation endpoint handler. + /// + /// The route template + public TusCreationPhotopixelsAttribute([StringSyntax("Route")] string template) : base(template) + { + + } + + public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + await base.OnActionExecutionAsync(context, next); + } + + /// + public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) + { + //base.OnResultExecutionAsync(context, next); + // Before sending headers --> + context.HttpContext.Response.OnStarting(state => + { + var ctx = (ResultExecutingContext)state; + var isPost = IsPost(ctx.HttpContext.Request.Method); + var response = ctx.HttpContext.Response; + var isSuccess = response.StatusCode >= 200 && response.StatusCode < 300; + if (isPost && isSuccess) + { + ctx.HttpContext.Response.StatusCode = 201; + string location = ctx.HttpContext.Response.Headers["Location"]!; + ctx.HttpContext.Response.Headers["Location"] = location.TrimStart('/'); + } + return Task.CompletedTask; + }, context); + + await next(); + } +}