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/Models/Http/TimelineController.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Timeline/Models/Http/TimelineController.cs') diff --git a/Timeline/Models/Http/TimelineController.cs b/Timeline/Models/Http/TimelineController.cs index aad361ee..95bae3e6 100644 --- a/Timeline/Models/Http/TimelineController.cs +++ b/Timeline/Models/Http/TimelineController.cs @@ -56,6 +56,11 @@ namespace Timeline.Models.Http /// public class TimelinePatchRequest { + /// + /// New title. Null for not change. + /// + public string? Title { get; set; } + /// /// New description. Null for not change. /// -- 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/Models/Http/TimelineController.cs') 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