diff options
-rw-r--r-- | BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs | 6 | ||||
-rw-r--r-- | BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs | 119 | ||||
-rw-r--r-- | BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest.cs (renamed from BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest1.cs) | 4 | ||||
-rw-r--r-- | BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs | 60 | ||||
-rw-r--r-- | BackEnd/Timeline/Models/Http/HttpTimelineBookmarkMoveRequest.cs | 21 | ||||
-rw-r--r-- | BackEnd/Timeline/Models/Http/HttpTimelinebookmarkDeleteRequest.cs | 18 |
6 files changed, 223 insertions, 5 deletions
diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs index 95c1dd97..b701e4eb 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs @@ -65,7 +65,7 @@ namespace Timeline.Tests.IntegratedTests2 public async Task OtherUserCantSeePrivate() { await CreateUserAsync("user2", "user2pw"); - var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); + using var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks", expectedStatusCode: HttpStatusCode.Forbidden); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks/1", expectedStatusCode: HttpStatusCode.Forbidden); } @@ -92,7 +92,7 @@ namespace Timeline.Tests.IntegratedTests2 { await ChangeVisibilityAsync(TimelineVisibility.Register); await CreateUserAsync("user2", "user2pw"); - var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); + using var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks", expectedStatusCode: HttpStatusCode.OK); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks/1", expectedStatusCode: HttpStatusCode.OK); } @@ -120,7 +120,7 @@ namespace Timeline.Tests.IntegratedTests2 { await ChangeVisibilityAsync(TimelineVisibility.Public); await CreateUserAsync("user2", "user2pw"); - var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); + using var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks", expectedStatusCode: HttpStatusCode.OK); await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/user/bookmarks/1", expectedStatusCode: HttpStatusCode.OK); } diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs new file mode 100644 index 00000000..fbf7e2c8 --- /dev/null +++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs @@ -0,0 +1,119 @@ +using System; +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Timeline.Models.Http; +using Xunit; +using Xunit.Abstractions; + +namespace Timeline.Tests.IntegratedTests2 +{ + public class TimelineBookmarkTest3 : IntegratedTestBase + { + public TimelineBookmarkTest3(ITestOutputHelper testOutput) : base(testOutput) + { + } + + protected override async Task OnInitializeAsync() + { + using var client = CreateClientAsUser(); + await client.TestJsonSendAsync(HttpMethod.Post, "v2/timelines", new HttpTimelineCreateRequest + { + Name = "hello" + }, expectedStatusCode: HttpStatusCode.Created); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/timelines", new HttpTimelineCreateRequest + { + Name = "hello2" + }, expectedStatusCode: HttpStatusCode.Created); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.Created); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest + { + TimelineOwner = "user", + TimelineName = "hello2" + }, expectedStatusCode: HttpStatusCode.Created); + } + + [Fact] + public async Task DeleteTest() + { + using var client = CreateClientAsUser(); + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.NoContent); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.NoContent); + } + + [Fact] + public async Task DeleteNotExist() + { + using var client = CreateClientAsUser(); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "notexist", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.UnprocessableEntity); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "notexist" + }, expectedStatusCode: HttpStatusCode.UnprocessableEntity); + } + + [Fact] + public async Task DeleteNotLogin() + { + using var client = CreateDefaultClient(); + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.Unauthorized); + } + + [Fact] + public async Task DeleteForbid() + { + await CreateUserAsync("user2", "user2pw"); + using var client = CreateClientWithToken(await CreateTokenWithCredentialAsync("user2", "user2pw")); + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.Forbidden); + } + + [Fact] + public async Task DeleteAdmin() + { + using var client = CreateClientAsAdmin(); + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.NoContent); + + await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/notexist/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest + { + TimelineOwner = "user", + TimelineName = "hello" + }, expectedStatusCode: HttpStatusCode.NotFound); + } + } +} + diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest1.cs b/BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest.cs index d06da9d9..53a98eae 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest1.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest.cs @@ -12,9 +12,9 @@ using Xunit.Abstractions; namespace Timeline.Tests.IntegratedTests2 { - public class TimelinePostTest1 : IntegratedTestBase + public class TimelinePostTest : IntegratedTestBase { - public TimelinePostTest1(ITestOutputHelper testOutput) : base(testOutput) + public TimelinePostTest(ITestOutputHelper testOutput) : base(testOutput) { } diff --git a/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs b/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs index c9898b61..c2130b5a 100644 --- a/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs +++ b/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs @@ -84,6 +84,66 @@ namespace Timeline.Controllers return CreatedAtAction("Get", new { username, index = bookmark.Position }, bookmark); } + [Authorize] + [HttpPost("delete")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)] + public async Task<ActionResult> DeleteAsync([FromRoute][Username] string username, [FromBody] HttpTimelinebookmarkDeleteRequest body) + { + var userId = await _userService.GetUserIdByUsernameAsync(username); + if (!UserHasPermission(UserPermission.UserBookmarkManagement) && GetAuthUserId() != userId) + { + return Forbid(); + } + + long timelineId; + try + { + timelineId = await _timelineService.GetTimelineIdAsync(body.TimelineOwner, body.TimelineName); + } + catch (EntityNotExistException) + { + return UnprocessableEntity(); + } + + await _timelineBookmarkService.DeleteBookmarkAsync(userId, timelineId); + + return NoContent(); + } + + [Authorize] + [HttpPost("move")] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status401Unauthorized)] + [ProducesResponseType(StatusCodes.Status403Forbidden)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)] + public async Task<ActionResult<TimelineBookmark>> MoveAsync([FromRoute][Username] string username, [FromBody] HttpTimelineBookmarkMoveRequest body) + { + var userId = await _userService.GetUserIdByUsernameAsync(username); + if (!UserHasPermission(UserPermission.UserBookmarkManagement) && GetAuthUserId() != userId) + { + return Forbid(); + } + + long timelineId; + try + { + timelineId = await _timelineService.GetTimelineIdAsync(body.TimelineOwner, body.TimelineName); + } + catch (EntityNotExistException) + { + return UnprocessableEntity(); + } + + var bookmark = await _timelineBookmarkService.MoveBookmarkAsync(userId, timelineId, body.Position!.Value); + + return Ok(bookmark); + } + [HttpGet("visibility")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] diff --git a/BackEnd/Timeline/Models/Http/HttpTimelineBookmarkMoveRequest.cs b/BackEnd/Timeline/Models/Http/HttpTimelineBookmarkMoveRequest.cs new file mode 100644 index 00000000..5be7fd00 --- /dev/null +++ b/BackEnd/Timeline/Models/Http/HttpTimelineBookmarkMoveRequest.cs @@ -0,0 +1,21 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Timeline.Models.Validation; + +namespace Timeline.Models.Http +{ + public class HttpTimelineBookmarkMoveRequest + { + [Required] + [Username] + public string TimelineOwner { get; set; } = default!; + + [Required] + [TimelineName] + public string TimelineName { get; set; } = default!; + + [Required] + public int? Position { get; set; } + } +} + diff --git a/BackEnd/Timeline/Models/Http/HttpTimelinebookmarkDeleteRequest.cs b/BackEnd/Timeline/Models/Http/HttpTimelinebookmarkDeleteRequest.cs new file mode 100644 index 00000000..ab45f976 --- /dev/null +++ b/BackEnd/Timeline/Models/Http/HttpTimelinebookmarkDeleteRequest.cs @@ -0,0 +1,18 @@ +using System; +using System.ComponentModel.DataAnnotations; +using Timeline.Models.Validation; + +namespace Timeline.Models.Http +{ + public class HttpTimelinebookmarkDeleteRequest + { + [Required] + [Username] + public string TimelineOwner { get; set; } = default!; + + [Required] + [TimelineName] + public string TimelineName { get; set; } = default!; + } +} + |