aboutsummaryrefslogtreecommitdiff
path: root/BackEnd
diff options
context:
space:
mode:
Diffstat (limited to 'BackEnd')
-rw-r--r--BackEnd/Timeline.Tests/IntegratedTests2/HttpClientTestExtensions.cs15
-rw-r--r--BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest.cs105
-rw-r--r--BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs138
-rw-r--r--BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs192
-rw-r--r--BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest.cs (renamed from BackEnd/Timeline.Tests/IntegratedTests2/TimelinePostTest1.cs)4
-rw-r--r--BackEnd/Timeline/Controllers/TimelineBookmark1Controller.cs76
-rw-r--r--BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs176
-rw-r--r--BackEnd/Timeline/Controllers/TimelinePostV2Controller.cs1
-rw-r--r--BackEnd/Timeline/Models/Http/HttpTimelineBookmarkMoveRequest.cs21
-rw-r--r--BackEnd/Timeline/Models/Http/HttpTimelineBookmarkVisibility.cs12
-rw-r--r--BackEnd/Timeline/Models/Http/HttpTimelinebookmarkDeleteRequest.cs18
-rw-r--r--BackEnd/Timeline/Services/Api/TimelineBookmarkService1.cs2
12 files changed, 672 insertions, 88 deletions
diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/HttpClientTestExtensions.cs b/BackEnd/Timeline.Tests/IntegratedTests2/HttpClientTestExtensions.cs
index cd7daf3e..48496853 100644
--- a/BackEnd/Timeline.Tests/IntegratedTests2/HttpClientTestExtensions.cs
+++ b/BackEnd/Timeline.Tests/IntegratedTests2/HttpClientTestExtensions.cs
@@ -12,7 +12,7 @@ namespace Timeline.Tests.IntegratedTests2
public static class HttpClientTestExtensions
{
- public static async Task<HttpResponseMessage> TestSendAsync(this HttpClient client, HttpMethod method, string url, HttpContent? body = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, RequestSetupAsync? requestSetup = null)
+ public static async Task<HttpResponseMessage> TestSendAsync(this HttpClient client, HttpMethod method, string url, HttpContent? body = null, HttpStatusCode? expectedStatusCode = null, RequestSetupAsync? requestSetup = null)
{
using var req = new HttpRequestMessage
{
@@ -23,7 +23,14 @@ namespace Timeline.Tests.IntegratedTests2
var task = requestSetup?.Invoke(req);
if (task is not null) await task;
var res = await client.SendAsync(req);
- res.StatusCode.Should().Be(expectedStatusCode);
+ if (expectedStatusCode is null)
+ {
+ ((int)res.StatusCode).Should().BeGreaterThanOrEqualTo(200).And.BeLessThan(300);
+ }
+ else
+ {
+ res.StatusCode.Should().Be(expectedStatusCode.Value);
+ }
return res;
}
@@ -34,13 +41,13 @@ namespace Timeline.Tests.IntegratedTests2
return body!;
}
- public static async Task TestJsonSendAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, RequestSetupAsync? requestSetup = null)
+ public static async Task TestJsonSendAsync(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode? expectedStatusCode = null, RequestSetupAsync? requestSetup = null)
{
using JsonContent? reqContent = jsonBody is null ? null : JsonContent.Create(jsonBody, options: CommonJsonSerializeOptions.Options);
await client.TestSendAsync(method, url, reqContent, expectedStatusCode, requestSetup);
}
- public static async Task<T> TestJsonSendAsync<T>(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode expectedStatusCode = HttpStatusCode.OK, RequestSetupAsync? requestSetup = null)
+ public static async Task<T> TestJsonSendAsync<T>(this HttpClient client, HttpMethod method, string url, object? jsonBody = null, HttpStatusCode? expectedStatusCode = null, RequestSetupAsync? requestSetup = null)
{
using JsonContent? reqContent = jsonBody == null ? null : JsonContent.Create(jsonBody, options: CommonJsonSerializeOptions.Options);
var res = await client.TestSendAsync(method, url, reqContent, expectedStatusCode, requestSetup);
diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest.cs b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest.cs
index fcf69364..903175c3 100644
--- a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest.cs
+++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest.cs
@@ -23,14 +23,13 @@ namespace Timeline.Tests.IntegratedTests2
{
Name = "hello"
}, expectedStatusCode: HttpStatusCode.Created);
-
}
[Fact]
- public async Task CreateAndGet()
+ public async Task CreateGetList()
{
using var client = CreateClientAsUser();
- var a = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Post, "users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ var a = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
{
TimelineOwner = "user",
TimelineName = "hello"
@@ -40,10 +39,108 @@ namespace Timeline.Tests.IntegratedTests2
a.TimelineName.Should().Be("hello");
a.Position.Should().Be(1);
- var b = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Get, "users/user/bookmarks/1");
+ var b = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Get, "v2/users/user/bookmarks/1");
b.TimelineName.Should().Be("hello");
b.TimelineOwner.Should().Be("user");
b.Position.Should().Be(1);
+
+ var c = await client.TestJsonSendAsync<Page<TimelineBookmark>>(HttpMethod.Get, "v2/users/user/bookmarks");
+ c.TotalCount.Should().Be(1);
+ c.Items.Should().ContainSingle();
+ c.Items[0].TimelineOwner.Should().Be("user");
+ c.Items[0].TimelineName.Should().Be("hello");
+ c.Items[0].Position.Should().Be(1);
+ }
+
+ [Fact]
+ public async Task ListGetNotExist()
+ {
+ using var client = CreateClientAsUser();
+
+ await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/notexist/bookmarks", expectedStatusCode: HttpStatusCode.NotFound);
+ await client.TestJsonSendAsync(HttpMethod.Get, "v2/users/notexist/bookmarks/1", expectedStatusCode: HttpStatusCode.NotFound);
+ }
+
+ [Fact]
+ public async Task CreateUserNotExist()
+ {
+ using var client = CreateClientAsUser();
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/notexist/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ }, expectedStatusCode: HttpStatusCode.NotFound);
+ }
+
+ [Fact]
+ public async Task CreateTimelineNotExist()
+ {
+ using var client = CreateClientAsUser();
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "notexist"
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "notexist",
+ TimelineName = "notexist"
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+ }
+
+ [Fact]
+ public async Task CreateAlreadyExist()
+ {
+ using var client = CreateClientAsUser();
+
+ await client.TestJsonSendAsync<TimelineBookmark>(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 = "hello"
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+ }
+
+ [Fact]
+ public async Task AnonymousCreateUnauthorized()
+ {
+ using var client = CreateDefaultClient();
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ }, expectedStatusCode: HttpStatusCode.Unauthorized);
+ }
+
+ [Fact]
+ public async Task OtherCreateForbid()
+ {
+ using var client = CreateClientAsUser();
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/admin/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ }, expectedStatusCode: HttpStatusCode.Forbidden);
+ }
+
+ [Fact]
+ public async Task AdminCanCreate()
+ {
+ using var client = CreateClientAsAdmin();
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ });
}
}
}
diff --git a/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs
new file mode 100644
index 00000000..b701e4eb
--- /dev/null
+++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest2.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Timeline.Models;
+using Timeline.Models.Http;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Timeline.Tests.IntegratedTests2
+{
+ public class TimelineBookmarkTest2 : IntegratedTestBase
+ {
+ public TimelineBookmarkTest2(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/users/user/bookmarks", new HttpTimelineBookmarkCreateRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ }, expectedStatusCode: HttpStatusCode.Created);
+ }
+
+ private async Task ChangeVisibilityAsync(TimelineVisibility visibility)
+ {
+ using var client = CreateClientAsUser();
+ await client.TestJsonSendAsync(HttpMethod.Put, "v2/users/user/bookmarks/visibility", new HttpTimelineBookmarkVisibility { Visibility = visibility }, expectedStatusCode: HttpStatusCode.NoContent);
+ }
+
+ [Fact]
+ public async Task ChangeVisibilityShouldWork()
+ {
+ using var client = CreateClientAsUser();
+ var a = await client.TestJsonSendAsync<HttpTimelineBookmarkVisibility>(HttpMethod.Get, "v2/users/user/bookmarks/visibility", expectedStatusCode: HttpStatusCode.OK);
+ a.Visibility.Should().Be(TimelineVisibility.Private);
+
+ await client.TestJsonSendAsync(HttpMethod.Put, "v2/users/user/bookmarks/visibility", new HttpTimelineBookmarkVisibility { Visibility = TimelineVisibility.Register }, expectedStatusCode: HttpStatusCode.NoContent);
+ var b = await client.TestJsonSendAsync<HttpTimelineBookmarkVisibility>(HttpMethod.Get, "v2/users/user/bookmarks/visibility", expectedStatusCode: HttpStatusCode.OK);
+ b.Visibility.Should().Be(TimelineVisibility.Register);
+
+ await client.TestJsonSendAsync(HttpMethod.Put, "v2/users/user/bookmarks/visibility", new HttpTimelineBookmarkVisibility { Visibility = TimelineVisibility.Public }, expectedStatusCode: HttpStatusCode.NoContent);
+ var c = await client.TestJsonSendAsync<HttpTimelineBookmarkVisibility>(HttpMethod.Get, "v2/users/user/bookmarks/visibility", expectedStatusCode: HttpStatusCode.OK);
+ c.Visibility.Should().Be(TimelineVisibility.Public);
+ }
+
+ [Fact]
+ public async Task AnonymousCantSeePrivate()
+ {
+ using var client = CreateDefaultClient();
+ 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);
+ }
+
+ [Fact]
+ public async Task OtherUserCantSeePrivate()
+ {
+ await CreateUserAsync("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);
+ }
+
+ [Fact]
+ public async Task AdminCanSeePrivate()
+ {
+ using var client = CreateClientAsAdmin();
+ 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);
+ }
+
+ [Fact]
+ public async Task AnonymousCantSeeRegister()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Register);
+ using var client = CreateDefaultClient();
+ 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);
+ }
+
+ [Fact]
+ public async Task OtherUserCanSeeRegister()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Register);
+ await CreateUserAsync("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);
+ }
+
+ [Fact]
+ public async Task AdminCanSeeRegister()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Register);
+ using var client = CreateClientAsAdmin();
+ 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);
+ }
+
+ [Fact]
+ public async Task AnonymousCanSeePublic()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Public);
+ using var client = CreateDefaultClient();
+ 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);
+ }
+
+ [Fact]
+ public async Task OtherUserCanSeePublic()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Public);
+ await CreateUserAsync("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);
+ }
+
+ [Fact]
+ public async Task AdminCanSeePublic()
+ {
+ await ChangeVisibilityAsync(TimelineVisibility.Public);
+ using var client = CreateClientAsAdmin();
+ 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..f2329bd9
--- /dev/null
+++ b/BackEnd/Timeline.Tests/IntegratedTests2/TimelineBookmarkTest3.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Timeline.Models;
+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 MoveTest()
+ {
+ using var client = CreateClientAsUser();
+ var a = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ Position = 2
+ });
+ a.Position.Should().Be(2);
+
+ var b = await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Get, "v2/users/user/bookmarks/2");
+ b.TimelineOwner.Should().Be("user");
+ b.TimelineName.Should().Be("hello");
+
+ await client.TestJsonSendAsync<TimelineBookmark>(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+ }
+
+ [Fact]
+ public async Task DeleteMoveNotExist()
+ {
+ 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);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "notexist",
+ TimelineName = "hello",
+ Position = 2
+
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "notexist",
+ Position = 2
+ }, expectedStatusCode: HttpStatusCode.UnprocessableEntity);
+ }
+
+ [Fact]
+ public async Task DeleteMoveNotLogin()
+ {
+ using var client = CreateDefaultClient();
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/delete", new HttpTimelinebookmarkDeleteRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello"
+ }, expectedStatusCode: HttpStatusCode.Unauthorized);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ Position = 2
+ }, expectedStatusCode: HttpStatusCode.Unauthorized);
+ }
+
+ [Fact]
+ public async Task DeleteMoveForbid()
+ {
+ 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);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ Position = 2
+ }, 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);
+ }
+
+ [Fact]
+ public async Task MoveAdmin()
+ {
+ using var client = CreateClientAsAdmin();
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/user/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ Position = 2
+ }, expectedStatusCode: HttpStatusCode.OK);
+
+ await client.TestJsonSendAsync(HttpMethod.Post, "v2/users/notexist/bookmarks/move", new HttpTimelineBookmarkMoveRequest
+ {
+ TimelineOwner = "user",
+ TimelineName = "hello",
+ Position = 2
+ }, 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/TimelineBookmark1Controller.cs b/BackEnd/Timeline/Controllers/TimelineBookmark1Controller.cs
deleted file mode 100644
index 73d2078f..00000000
--- a/BackEnd/Timeline/Controllers/TimelineBookmark1Controller.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System.Threading.Tasks;
-using Microsoft.AspNetCore.Authorization;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
-using Timeline.Models;
-using Timeline.Models.Http;
-using Timeline.Services.Api;
-using Timeline.Services.Timeline;
-using Timeline.Services.User;
-
-namespace Timeline.Controllers
-{
- [ApiController]
- [Route("users/{username}/bookmarks")]
- public class TimelineBookmark1Controller : MyControllerBase
- {
- private readonly IUserService _userService;
- private readonly ITimelineService _timelineService;
- private readonly ITimelineBookmarkService1 _timelineBookmarkService;
-
- public TimelineBookmark1Controller(IUserService userService, ITimelineService timelineService, ITimelineBookmarkService1 timelineBookmarkService)
- {
- _userService = userService;
- _timelineService = timelineService;
- _timelineBookmarkService = timelineBookmarkService;
- }
-
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
- [HttpGet]
- public async Task<ActionResult<Page<TimelineBookmark>>> ListAsync([FromRoute] string username, [FromQuery] int? page, [FromQuery] int? pageSize)
- {
- var userId = await _userService.GetUserIdByUsernameAsync(username);
- if (!UserHasPermission(UserPermission.UserBookmarkManagement) && !await _timelineBookmarkService.CanReadBookmarksAsync(userId, GetOptionalAuthUserId()))
- {
- return Forbid();
- }
- return await _timelineBookmarkService.GetBookmarksAsync(userId, page ?? 1, pageSize ?? 20);
- }
-
- [ProducesResponseType(StatusCodes.Status200OK)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
- [HttpGet("{index}")]
- public async Task<ActionResult<TimelineBookmark>> GetAsync([FromRoute] string username, [FromRoute] int index)
- {
- var userId = await _userService.GetUserIdByUsernameAsync(username);
- if (!UserHasPermission(UserPermission.UserBookmarkManagement) && !await _timelineBookmarkService.CanReadBookmarksAsync(userId, GetOptionalAuthUserId()))
- {
- return Forbid();
- }
- return await _timelineBookmarkService.GetBookmarkAtAsync(userId, index);
- }
-
- [ProducesResponseType(StatusCodes.Status201Created)]
- [ProducesResponseType(StatusCodes.Status401Unauthorized)]
- [ProducesResponseType(StatusCodes.Status403Forbidden)]
- [ProducesResponseType(StatusCodes.Status404NotFound)]
- [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
- [Authorize]
- public async Task<ActionResult<TimelineBookmark>> CreateAsync([FromRoute] string username, [FromBody] HttpTimelineBookmarkCreateRequest body)
- {
- var userId = await _userService.GetUserIdByUsernameAsync(username);
- if (!UserHasPermission(UserPermission.UserBookmarkManagement) && GetAuthUserId() != userId)
- {
- return Forbid();
- }
- var timelineId = await _timelineService.GetTimelineIdAsync(body.TimelineOwner, body.TimelineName);
- var bookmark = await _timelineBookmarkService.AddBookmarkAsync(userId, timelineId, body.Position);
- return CreatedAtAction("Get", new { username, index = bookmark.Position }, bookmark);
- }
- }
-}
diff --git a/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs b/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs
new file mode 100644
index 00000000..c2130b5a
--- /dev/null
+++ b/BackEnd/Timeline/Controllers/TimelineBookmarkV2Controller.cs
@@ -0,0 +1,176 @@
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Timeline.Models;
+using Timeline.Models.Http;
+using Timeline.Models.Validation;
+using Timeline.Services;
+using Timeline.Services.Api;
+using Timeline.Services.Timeline;
+using Timeline.Services.User;
+
+namespace Timeline.Controllers
+{
+ [ApiController]
+ [Route("v2/users/{username}/bookmarks")]
+ public class TimelineBookmarkV2Controller : MyControllerBase
+ {
+ private readonly IUserService _userService;
+ private readonly ITimelineService _timelineService;
+ private readonly ITimelineBookmarkService1 _timelineBookmarkService;
+
+ public TimelineBookmarkV2Controller(IUserService userService, ITimelineService timelineService, ITimelineBookmarkService1 timelineBookmarkService)
+ {
+ _userService = userService;
+ _timelineService = timelineService;
+ _timelineBookmarkService = timelineBookmarkService;
+ }
+
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
+ [HttpGet]
+ public async Task<ActionResult<Page<TimelineBookmark>>> ListAsync([FromRoute][Username] string username, [FromQuery] int? page, [FromQuery] int? pageSize)
+ {
+ var userId = await _userService.GetUserIdByUsernameAsync(username);
+ if (!UserHasPermission(UserPermission.UserBookmarkManagement) && !await _timelineBookmarkService.CanReadBookmarksAsync(userId, GetOptionalAuthUserId()))
+ {
+ return Forbid();
+ }
+ return await _timelineBookmarkService.GetBookmarksAsync(userId, page ?? 1, pageSize ?? 20);
+ }
+
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
+ [HttpGet("{index}")]
+ public async Task<ActionResult<TimelineBookmark>> GetAsync([FromRoute][Username] string username, [FromRoute] int index)
+ {
+ var userId = await _userService.GetUserIdByUsernameAsync(username);
+ if (!UserHasPermission(UserPermission.UserBookmarkManagement) && !await _timelineBookmarkService.CanReadBookmarksAsync(userId, GetOptionalAuthUserId()))
+ {
+ return Forbid();
+ }
+ return await _timelineBookmarkService.GetBookmarkAtAsync(userId, index);
+ }
+
+ [ProducesResponseType(StatusCodes.Status201Created)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
+ [Authorize]
+ [HttpPost]
+ public async Task<ActionResult<TimelineBookmark>> CreateAsync([FromRoute][Username] string username, [FromBody] HttpTimelineBookmarkCreateRequest 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.AddBookmarkAsync(userId, timelineId, body.Position);
+ 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)]
+ [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
+ public async Task<ActionResult<HttpTimelineBookmarkVisibility>> GetVisibilityAsync([FromRoute][Username] string username)
+ {
+ var userId = await _userService.GetUserIdByUsernameAsync(username);
+ var visibility = await _timelineBookmarkService.GetBookmarkVisibilityAsync(userId);
+ return Ok(new HttpTimelineBookmarkVisibility { Visibility = visibility });
+ }
+
+ [HttpPut("visibility")]
+ [Authorize]
+ [ProducesResponseType(StatusCodes.Status204NoContent)]
+ [ProducesResponseType(StatusCodes.Status401Unauthorized)]
+ [ProducesResponseType(StatusCodes.Status403Forbidden)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ [ProducesResponseType(StatusCodes.Status422UnprocessableEntity)]
+ public async Task<ActionResult> PutVisibilityAsync([FromRoute][Username] string username, [FromBody] HttpTimelineBookmarkVisibility body)
+ {
+ var userId = await _userService.GetUserIdByUsernameAsync(username);
+ if (!UserHasPermission(UserPermission.UserBookmarkManagement) && GetAuthUserId() != userId)
+ {
+ return Forbid();
+ }
+ await _timelineBookmarkService.SetBookmarkVisibilityAsync(userId, body.Visibility);
+ return NoContent();
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Controllers/TimelinePostV2Controller.cs b/BackEnd/Timeline/Controllers/TimelinePostV2Controller.cs
index 6e4b265f..435ffece 100644
--- a/BackEnd/Timeline/Controllers/TimelinePostV2Controller.cs
+++ b/BackEnd/Timeline/Controllers/TimelinePostV2Controller.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
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/HttpTimelineBookmarkVisibility.cs b/BackEnd/Timeline/Models/Http/HttpTimelineBookmarkVisibility.cs
new file mode 100644
index 00000000..d19c12f6
--- /dev/null
+++ b/BackEnd/Timeline/Models/Http/HttpTimelineBookmarkVisibility.cs
@@ -0,0 +1,12 @@
+using System;
+using System.ComponentModel.DataAnnotations;
+
+namespace Timeline.Models.Http
+{
+ public class HttpTimelineBookmarkVisibility
+ {
+ [Required]
+ public TimelineVisibility Visibility { 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!;
+ }
+}
+
diff --git a/BackEnd/Timeline/Services/Api/TimelineBookmarkService1.cs b/BackEnd/Timeline/Services/Api/TimelineBookmarkService1.cs
index 4b52d61c..648ea9ff 100644
--- a/BackEnd/Timeline/Services/Api/TimelineBookmarkService1.cs
+++ b/BackEnd/Timeline/Services/Api/TimelineBookmarkService1.cs
@@ -205,7 +205,7 @@ namespace Timeline.Services.Api
await transaction.CommitAsync();
}
- return new TimelineBookmark(user.Username, timeline.Name is null ? "self" : timeline.Name, (int)entity.Rank);
+ return new TimelineBookmark(user.Username, timeline.Name is null ? "self" : timeline.Name, position);
}
public async Task SetBookmarkVisibilityAsync(long userId, TimelineVisibility visibility)