From 35f6584f47676353733f1cc9182d84ed4ded5cbc Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 27 Aug 2020 01:13:31 +0800 Subject: Timeline title feature. --- Timeline.Tests/IntegratedTests/TimelineTest.cs | 29 ++++++++++++++++++++++++++ Timeline.Tests/Services/TimelineServiceTest.cs | 27 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+) (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs index 3b4b1754..302b2195 100644 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -1407,5 +1407,34 @@ namespace Timeline.Tests.IntegratedTests .Which.Should().BeEquivalentTo(timeline); } } + + [Theory] + [MemberData(nameof(TimelineUrlGeneratorData))] + public async Task Title(TimelineUrlGenerator urlGenerator) + { + using var client = await CreateClientAsUser(); + + { + var res = await client.GetAsync(urlGenerator(1)); + var timeline = res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which; + timeline.Title.Should().Be(timeline.Name); + } + + { + var res = await client.PatchAsJsonAsync(urlGenerator(1), new TimelinePatchRequest { Title = "atitle" }); + res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which.Title.Should().Be("atitle"); + } + + { + var res = await client.GetAsync(urlGenerator(1)); + res.Should().HaveStatusCode(200) + .And.HaveJsonBody() + .Which.Title.Should().Be("atitle"); + } + } } } diff --git a/Timeline.Tests/Services/TimelineServiceTest.cs b/Timeline.Tests/Services/TimelineServiceTest.cs index 36e5ed0c..558ec597 100644 --- a/Timeline.Tests/Services/TimelineServiceTest.cs +++ b/Timeline.Tests/Services/TimelineServiceTest.cs @@ -271,5 +271,32 @@ namespace Timeline.Tests.Services posts.Should().HaveCount(4); } } + + [Theory] + [InlineData("@admin")] + [InlineData("tl")] + public async Task Title(string timelineName) + { + var _ = TimelineHelper.ExtractTimelineName(timelineName, out var isPersonal); + if (!isPersonal) + await _timelineService.CreateTimeline(timelineName, await _userService.GetUserIdByUsername("user")); + + { + var timeline = await _timelineService.GetTimeline(timelineName); + timeline.Title.Should().Be(timelineName); + } + + { + await _timelineService.ChangeProperty(timelineName, new TimelineChangePropertyRequest { Title = null }); + var timeline = await _timelineService.GetTimeline(timelineName); + timeline.Title.Should().Be(timelineName); + } + + { + await _timelineService.ChangeProperty(timelineName, new TimelineChangePropertyRequest { Title = "atitle" }); + var timeline = await _timelineService.GetTimeline(timelineName); + timeline.Title.Should().Be("atitle"); + } + } } } -- cgit v1.2.3 From bdff6f0ad414f1ec1352d1d4e36c78e06e02ab80 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 27 Aug 2020 23:20:14 +0800 Subject: Timeline service add change timeline name api. --- Timeline.Tests/Services/TimelineServiceTest.cs | 19 ++++++++++ Timeline/Services/TimelineService.cs | 50 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/Services/TimelineServiceTest.cs b/Timeline.Tests/Services/TimelineServiceTest.cs index 558ec597..3883cda9 100644 --- a/Timeline.Tests/Services/TimelineServiceTest.cs +++ b/Timeline.Tests/Services/TimelineServiceTest.cs @@ -298,5 +298,24 @@ namespace Timeline.Tests.Services timeline.Title.Should().Be("atitle"); } } + + [Fact] + public async Task ChangeName() + { + _clock.ForwardCurrentTime(); + + await _timelineService.CreateTimeline("tl", await _userService.GetUserIdByUsername("user")); + + var time = _clock.ForwardCurrentTime(); + + await _timelineService.ChangeTimelineName("tl", "newtl"); + + { + var timeline = await _timelineService.GetTimeline("newtl"); + timeline.Name.Should().Be("newtl"); + timeline.LastModified.Should().Be(time); + timeline.NameLastModified.Should().Be(time); + } + } } } diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index 2f0bf2c5..0a3a2076 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Timeline.Entities; using Timeline.Helpers; @@ -357,6 +358,21 @@ namespace Timeline.Services /// Thrown when timeline name is invalid. /// Thrown when the timeline does not exist. Task DeleteTimeline(string timelineName); + + /// + /// Change name of a timeline. + /// + /// The old timeline name. + /// The new timeline name. + /// The new timeline info. + /// Thrown when or is null. + /// Thrown when or is of invalid format. + /// Thrown when timeline does not exist. + /// Thrown when a timeline with new name already exists. + /// + /// You can only change name of general timeline. + /// + Task ChangeTimelineName(string oldTimelineName, string newTimelineName); } public class TimelineService : ITimelineService @@ -1111,5 +1127,39 @@ namespace Timeline.Services _database.Timelines.Remove(entity); await _database.SaveChangesAsync(); } + + public async Task ChangeTimelineName(string oldTimelineName, string newTimelineName) + { + if (oldTimelineName == null) + throw new ArgumentNullException(nameof(oldTimelineName)); + if (newTimelineName == null) + throw new ArgumentNullException(nameof(newTimelineName)); + + ValidateTimelineName(oldTimelineName, nameof(oldTimelineName)); + ValidateTimelineName(newTimelineName, nameof(newTimelineName)); + + var entity = await _database.Timelines.Where(t => t.Name == oldTimelineName).SingleOrDefaultAsync(); + + if (entity == null) + throw new TimelineNotExistException(oldTimelineName); + + if (oldTimelineName == newTimelineName) + return await MapTimelineFromEntity(entity); + + var conflict = await _database.Timelines.AnyAsync(t => t.Name == newTimelineName); + + if (conflict) + throw new EntityAlreadyExistException(EntityNames.Timeline, null, ExceptionTimelineNameConflict); + + var now = _clock.GetCurrentTime(); + + entity.Name = newTimelineName; + entity.NameLastModified = now; + entity.LastModified = now; + + await _database.SaveChangesAsync(); + + return await MapTimelineFromEntity(entity); + } } } -- cgit v1.2.3 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.Tests/IntegratedTests/TimelineTest.cs | 61 +++++++++++++++++++++++--- Timeline.Tests/Services/TimelineServiceTest.cs | 8 ++++ Timeline/Controllers/TimelineController.cs | 26 +++++++++++ Timeline/Filters/Timeline.cs | 13 ++++-- Timeline/Models/Http/TimelineController.cs | 19 ++++++++ Timeline/Services/TimelineService.cs | 3 +- 6 files changed, 120 insertions(+), 10 deletions(-) (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs index 302b2195..ac4f41a2 100644 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -488,7 +488,7 @@ namespace Timeline.Tests.IntegratedTests { var res = await client.DeleteAsync("timelines/t1"); - res.Should().HaveStatusCode(HttpStatusCode.NotFound); + res.Should().HaveStatusCode(400); } } } @@ -545,15 +545,15 @@ namespace Timeline.Tests.IntegratedTests } { var res = await client.PatchAsJsonAsync(generator("notexist", null), new TimelinePatchRequest { }); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); } { var res = await client.PutAsync(generator("notexist", "members/user1"), null); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); } { var res = await client.DeleteAsync(generator("notexist", "members/user1")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); } { var res = await client.GetAsync(generator("notexist", "posts")); @@ -561,11 +561,11 @@ namespace Timeline.Tests.IntegratedTests } { var res = await client.PostAsJsonAsync(generator("notexist", "posts"), TimelineHelper.TextPostCreateRequest("aaa")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); } { var res = await client.DeleteAsync(generator("notexist", "posts/123")); - res.Should().HaveStatusCode(404).And.HaveCommonBody(errorCode); + res.Should().HaveStatusCode(400).And.HaveCommonBody(errorCode); } { var res = await client.GetAsync(generator("notexist", "posts/123/data")); @@ -1436,5 +1436,54 @@ namespace Timeline.Tests.IntegratedTests .Which.Title.Should().Be("atitle"); } } + + [Fact] + public async Task ChangeName() + { + { + using var client = await CreateDefaultClient(); + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); + res.Should().HaveStatusCode(401); + } + + { + using var client = await CreateClientAs(2); + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "tttttttt" }); + res.Should().HaveStatusCode(403); + } + + using (var client = await CreateClientAsUser()) + { + { + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "!!!", NewName = "tttttttt" }); + res.Should().BeInvalidModel(); + } + + { + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttt", NewName = "!!!!" }); + res.Should().BeInvalidModel(); + } + + { + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "ttttt", NewName = "tttttttt" }); + res.Should().HaveStatusCode(400).And.HaveCommonBody().Which.Code.Should().Be(ErrorCodes.TimelineController.NotExist); + } + + { + var res = await client.PostAsJsonAsync("timelineop/changename", new TimelineChangeNameRequest { OldName = "t1", NewName = "newt" }); + res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); + } + + { + var res = await client.GetAsync("timelines/t1"); + res.Should().HaveStatusCode(404); + } + + { + var res = await client.GetAsync("timelines/newt"); + res.Should().HaveStatusCode(200).And.HaveJsonBody().Which.Name.Should().Be("newt"); + } + } + } } } diff --git a/Timeline.Tests/Services/TimelineServiceTest.cs b/Timeline.Tests/Services/TimelineServiceTest.cs index 3883cda9..5a774b78 100644 --- a/Timeline.Tests/Services/TimelineServiceTest.cs +++ b/Timeline.Tests/Services/TimelineServiceTest.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Timeline.Entities; using Timeline.Models; using Timeline.Services; +using Timeline.Services.Exceptions; using Timeline.Tests.Helpers; using Xunit; @@ -304,7 +305,14 @@ namespace Timeline.Tests.Services { _clock.ForwardCurrentTime(); + await _timelineService.Awaiting(s => s.ChangeTimelineName("!!!", "newtl")).Should().ThrowAsync(); + await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "!!!")).Should().ThrowAsync(); + await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "newtl")).Should().ThrowAsync(); + await _timelineService.CreateTimeline("tl", await _userService.GetUserIdByUsername("user")); + await _timelineService.CreateTimeline("tl2", await _userService.GetUserIdByUsername("user")); + + await _timelineService.Awaiting(s => s.ChangeTimelineName("tl", "tl2")).Should().ThrowAsync(); var time = _clock.ForwardCurrentTime(); 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()); + } + } } } diff --git a/Timeline/Filters/Timeline.cs b/Timeline/Filters/Timeline.cs index 90b87223..6a730ee7 100644 --- a/Timeline/Filters/Timeline.cs +++ b/Timeline/Filters/Timeline.cs @@ -1,4 +1,5 @@ -using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Timeline.Models.Http; using Timeline.Services.Exceptions; @@ -13,11 +14,17 @@ namespace Timeline.Filters { if (e.InnerException is UserNotExistException) { - context.Result = new NotFoundObjectResult(ErrorResponse.UserCommon.NotExist()); + if (HttpMethods.IsGet(context.HttpContext.Request.Method)) + context.Result = new NotFoundObjectResult(ErrorResponse.UserCommon.NotExist()); + else + context.Result = new BadRequestObjectResult(ErrorResponse.UserCommon.NotExist()); } else { - context.Result = new NotFoundObjectResult(ErrorResponse.TimelineController.NotExist()); + if (HttpMethods.IsGet(context.HttpContext.Request.Method)) + context.Result = new NotFoundObjectResult(ErrorResponse.TimelineController.NotExist()); + else + context.Result = new BadRequestObjectResult(ErrorResponse.TimelineController.NotExist()); } } } diff --git a/Timeline/Models/Http/TimelineController.cs b/Timeline/Models/Http/TimelineController.cs index 95bae3e6..7bd141ed 100644 --- a/Timeline/Models/Http/TimelineController.cs +++ b/Timeline/Models/Http/TimelineController.cs @@ -71,4 +71,23 @@ namespace Timeline.Models.Http /// public TimelineVisibility? Visibility { get; set; } } + + /// + /// Change timeline name request model. + /// + public class TimelineChangeNameRequest + { + /// + /// Old name of timeline. + /// + [Required] + [TimelineName] + public string OldName { get; set; } = default!; + /// + /// New name of timeline. + /// + [Required] + [TimelineName] + public string NewName { get; set; } = default!; + } } diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index 0a3a2076..4bcae596 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -411,6 +411,7 @@ namespace Timeline.Services } } + /// Remember to include Members when query. private async Task MapTimelineFromEntity(TimelineEntity entity) { var owner = await _userService.GetUserById(entity.OwnerId); @@ -1138,7 +1139,7 @@ namespace Timeline.Services ValidateTimelineName(oldTimelineName, nameof(oldTimelineName)); ValidateTimelineName(newTimelineName, nameof(newTimelineName)); - var entity = await _database.Timelines.Where(t => t.Name == oldTimelineName).SingleOrDefaultAsync(); + var entity = await _database.Timelines.Include(t => t.Members).Where(t => t.Name == oldTimelineName).SingleOrDefaultAsync(); if (entity == null) throw new TimelineNotExistException(oldTimelineName); -- 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.Tests') 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 From 7e414fb4a09e6d35fa32d48fdba38a537ffe1d23 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 31 Aug 2020 22:39:18 +0800 Subject: Post info now contain data etag. --- Timeline.Tests/IntegratedTests/TimelineTest.cs | 34 ++++++++++++++++++++++++++ Timeline/Models/Http/Timeline.cs | 7 +++++- Timeline/Models/Timeline.cs | 4 +++ 3 files changed, 44 insertions(+), 1 deletion(-) (limited to 'Timeline.Tests') diff --git a/Timeline.Tests/IntegratedTests/TimelineTest.cs b/Timeline.Tests/IntegratedTests/TimelineTest.cs index ac4f41a2..ec46b96a 100644 --- a/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -1485,5 +1485,39 @@ namespace Timeline.Tests.IntegratedTests } } } + + [Theory] + [MemberData(nameof(TimelineUrlGeneratorData))] + public async Task PostDataETag(TimelineUrlGenerator urlGenerator) + { + using var client = await CreateClientAsUser(); + + long id; + string etag; + + { + var res = await client.PostAsJsonAsync(urlGenerator(1, "posts"), new TimelinePostCreateRequest + { + Content = new TimelinePostCreateRequestContent + { + Type = TimelinePostContentTypes.Image, + Data = Convert.ToBase64String(ImageHelper.CreatePngWithSize(100, 50)) + } + }); + res.Should().HaveStatusCode(200); + var body = await res.ReadBodyAsJsonAsync(); + body.Content.ETag.Should().NotBeNullOrEmpty(); + + id = body.Id; + etag = body.Content.ETag; + } + + { + var res = await client.GetAsync(urlGenerator(1, $"posts/{id}/data")); + res.Should().HaveStatusCode(200); + res.Headers.ETag.Should().NotBeNull(); + res.Headers.ETag.ToString().Should().Be(etag); + } + } } } diff --git a/Timeline/Models/Http/Timeline.cs b/Timeline/Models/Http/Timeline.cs index 3596af18..a81b33f5 100644 --- a/Timeline/Models/Http/Timeline.cs +++ b/Timeline/Models/Http/Timeline.cs @@ -25,6 +25,10 @@ namespace Timeline.Models.Http /// If post is of image type. This is the image url. /// public string? Url { get; set; } + /// + /// If post has data (currently it means it's a image post), this is the data etag. + /// + public string? ETag { get; set; } } /// @@ -192,7 +196,8 @@ namespace Timeline.Models.Http Url = urlHelper.ActionLink( action: nameof(TimelineController.PostDataGet), controller: nameof(TimelineController)[0..^nameof(Controller).Length], - values: new { Name = source.TimelineName, Id = source.Id }) + values: new { Name = source.TimelineName, Id = source.Id }), + ETag = $"\"{imageContent.DataTag}\"" }; } else diff --git a/Timeline/Models/Timeline.cs b/Timeline/Models/Timeline.cs index 42906053..a5987577 100644 --- a/Timeline/Models/Timeline.cs +++ b/Timeline/Models/Timeline.cs @@ -43,6 +43,10 @@ namespace Timeline.Models public ImageTimelinePostContent(string dataTag) { DataTag = dataTag; } public string Type { get; } = TimelinePostContentTypes.Image; + + /// + /// The tag of the data. The tag of the entry in DataManager. Also the etag (not quoted). + /// public string DataTag { get; set; } } -- cgit v1.2.3