From 315a5fa6eea7511618266877fca6aa1275caed1c Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 28 Aug 2020 00:01:04 +0800 Subject: Add change timeline name api to timeline controller. --- Timeline/Controllers/TimelineController.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'Timeline/Controllers') diff --git a/Timeline/Controllers/TimelineController.cs b/Timeline/Controllers/TimelineController.cs index 90b50bbb..9a3147ea 100644 --- a/Timeline/Controllers/TimelineController.cs +++ b/Timeline/Controllers/TimelineController.cs @@ -308,6 +308,7 @@ namespace Timeline.Controllers [HttpDelete("timelines/{name}/posts/{id}")] [Authorize] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> PostDelete([FromRoute][GeneralTimelineName] string name, [FromRoute] long id) @@ -336,6 +337,7 @@ namespace Timeline.Controllers [HttpPatch("timelines/{name}")] [Authorize] [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> TimelinePatch([FromRoute][GeneralTimelineName] string name, [FromBody] TimelinePatchRequest body) @@ -461,5 +463,29 @@ namespace Timeline.Controllers return CommonDeleteResponse.NotExist(); } } + + [HttpPost("timelineop/changename")] + [Authorize] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + public async Task> TimelineOpChangeName([FromBody] TimelineChangeNameRequest body) + { + if (!this.IsAdministrator() && !(await _service.HasManagePermission(body.OldName, this.GetUserId()))) + { + return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); + } + + try + { + var timeline = await _service.ChangeTimelineName(body.OldName, body.NewName); + return Ok(_mapper.Map(timeline)); + } + catch (EntityAlreadyExistException) + { + return BadRequest(ErrorResponse.TimelineController.NameConflict()); + } + } } } -- cgit v1.2.3 From 4dda5d088330e76844010a4f89049ea207652318 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 31 Aug 2020 22:22:57 +0800 Subject: Now uesr avatar put api returns etag. --- Timeline.Tests/Helpers/HttpResponseExtensions.cs | 35 ++++++++++++++++++++++++ Timeline.Tests/IntegratedTests/UserAvatarTest.cs | 25 +++++++++++++++++ Timeline/Controllers/UserAvatarController.cs | 6 +++- Timeline/Services/UserAvatarService.cs | 14 +++++----- 4 files changed, 72 insertions(+), 8 deletions(-) create mode 100644 Timeline.Tests/Helpers/HttpResponseExtensions.cs (limited to 'Timeline/Controllers') diff --git a/Timeline.Tests/Helpers/HttpResponseExtensions.cs b/Timeline.Tests/Helpers/HttpResponseExtensions.cs new file mode 100644 index 00000000..2bd497f1 --- /dev/null +++ b/Timeline.Tests/Helpers/HttpResponseExtensions.cs @@ -0,0 +1,35 @@ +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Timeline.Models.Converters; +using Timeline.Models.Http; + +namespace Timeline.Tests.Helpers +{ + public static class HttpResponseExtensions + { + public static JsonSerializerOptions JsonSerializerOptions { get; } + + static HttpResponseExtensions() + { + JsonSerializerOptions = new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }; + JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter()); + } + + public static async Task ReadBodyAsJsonAsync(this HttpResponseMessage response) + { + var stream = await response.Content.ReadAsStreamAsync(); + return await JsonSerializer.DeserializeAsync(stream, JsonSerializerOptions); + } + + public static Task ReadBodyAsCommonResponseAsync(this HttpResponseMessage response) + { + return response.ReadBodyAsJsonAsync(); + } + } +} diff --git a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index 507b05ba..f2796005 100644 --- a/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -10,6 +10,7 @@ using System.IO; using System.Net; using System.Net.Http; using System.Net.Http.Headers; +using System.Net.Mime; using System.Threading.Tasks; using Timeline.Models.Http; using Timeline.Services; @@ -222,5 +223,29 @@ namespace Timeline.Tests.IntegratedTests } } } + + [Fact] + public async Task AvatarPutReturnETag() + { + using var client = await CreateClientAsUser(); + + EntityTagHeaderValue etag; + + { + var image = ImageHelper.CreatePngWithSize(100, 100); + var res = await client.PutByteArrayAsync("users/user1/avatar", image, PngFormat.Instance.DefaultMimeType); + res.Should().HaveStatusCode(200); + etag = res.Headers.ETag; + etag.Should().NotBeNull(); + etag.Tag.Should().NotBeNullOrEmpty(); + } + + { + var res = await client.GetAsync("users/user1/avatar"); + res.Should().HaveStatusCode(200); + res.Headers.ETag.Should().Be(etag); + res.Headers.ETag.Tag.Should().Be(etag.Tag); + } + } } } \ No newline at end of file diff --git a/Timeline/Controllers/UserAvatarController.cs b/Timeline/Controllers/UserAvatarController.cs index 97c4bdb8..bc4afa30 100644 --- a/Timeline/Controllers/UserAvatarController.cs +++ b/Timeline/Controllers/UserAvatarController.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; +using Microsoft.Net.Http.Headers; using System; using System.Threading.Tasks; using Timeline.Auth; @@ -105,7 +106,7 @@ namespace Timeline.Controllers try { - await _service.SetAvatar(id, new Avatar + var etag = await _service.SetAvatar(id, new Avatar { Data = body.Data, Type = body.ContentType @@ -113,6 +114,9 @@ namespace Timeline.Controllers _logger.LogInformation(Log.Format(LogPutSuccess, ("Username", username), ("Mime Type", Request.ContentType))); + + Response.Headers.Append("ETag", new EntityTagHeaderValue($"\"{etag}\"").ToString()); + return Ok(); } catch (ImageException e) diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs index 2bf8bddc..b41c45fd 100644 --- a/Timeline/Services/UserAvatarService.cs +++ b/Timeline/Services/UserAvatarService.cs @@ -71,9 +71,10 @@ namespace Timeline.Services /// /// The id of the user to set avatar for. /// The avatar. Can be null to delete the saved avatar. + /// The etag of the avatar. /// Thrown if any field in is null when is not null. /// Thrown if avatar is of bad format. - Task SetAvatar(long id, Avatar? avatar); + Task SetAvatar(long id, Avatar? avatar); } // TODO! : Make this configurable. @@ -199,7 +200,7 @@ namespace Timeline.Services return defaultAvatar; } - public async Task SetAvatar(long id, Avatar? avatar) + public async Task SetAvatar(long id, Avatar? avatar) { if (avatar != null) { @@ -213,11 +214,7 @@ namespace Timeline.Services if (avatar == null) { - if (avatarEntity == null || avatarEntity.DataTag == null) - { - return; - } - else + if (avatarEntity != null && avatarEntity.DataTag != null) { await _dataManager.FreeEntry(avatarEntity.DataTag); avatarEntity.DataTag = null; @@ -226,6 +223,7 @@ namespace Timeline.Services await _database.SaveChangesAsync(); _logger.LogInformation(Resources.Services.UserAvatarService.LogUpdateEntity); } + return await _defaultUserAvatarProvider.GetDefaultAvatarETag(); } else { @@ -250,6 +248,8 @@ namespace Timeline.Services { await _dataManager.FreeEntry(oldTag); } + + return avatarEntity.DataTag; } } } -- cgit v1.2.3