From c667c722ec081dfb651d3583236d7aa429c56941 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 13 May 2021 15:53:08 +0800 Subject: feat: Posts pagination. --- .../Timeline.Tests/IntegratedTests/TimelinePostTest.cs | 18 ++++++++++++++++++ BackEnd/Timeline/Controllers/TimelinePostController.cs | 6 ++++-- .../Timeline/Services/Timeline/ITimelinePostService.cs | 4 +++- .../Timeline/Services/Timeline/Resource.Designer.cs | 18 ++++++++++++++++++ BackEnd/Timeline/Services/Timeline/Resource.resx | 6 ++++++ .../Timeline/Services/Timeline/TimelinePostService.cs | 14 +++++++++++++- 6 files changed, 62 insertions(+), 4 deletions(-) (limited to 'BackEnd') diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs index c918f793..097275b0 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelinePostTest.cs @@ -634,5 +634,23 @@ namespace Timeline.Tests.IntegratedTests await client.TestDeleteAsync($"timelines/{generator(1)}/posts/{post.Id}"); } } + + [Theory] + [MemberData(nameof(TimelineNameGeneratorTestData))] + public async Task Post_List_Pagination_Test(TimelineNameGenerator generator) + { + using var client = await CreateClientAsUser(); + var posts = new List(); + for (int i = 0; i < 50; i++) + { + var post = await client.TestPostAsync($"timelines/{generator(1)}/posts", CreateTextPostRequest(i.ToString())); + posts.Add(post); + } + + { + var p = await client.TestGetAsync>($"timelines/{generator(1)}/posts?page=2&numberPerPage=10"); + p.Should().BeEquivalentTo(posts.Skip(10).Take(10)); + } + } } } diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index 21d3821a..da45cbea 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -57,12 +57,14 @@ namespace Timeline.Controllers /// The name of the timeline. /// If set, only posts modified since the time will return. /// If set to true, deleted post will also return. + /// Page number, starting from 0. Null to get all. + /// Post number per page. Default is 20. /// The post list. [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task>> List([FromRoute][GeneralTimelineName] string timeline, [FromQuery] DateTime? modifiedSince, [FromQuery] bool? includeDeleted) + public async Task>> List([FromRoute][GeneralTimelineName] string timeline, [FromQuery] DateTime? modifiedSince, [FromQuery] bool? includeDeleted, [FromQuery][Range(0, int.MaxValue)] int? page, [FromQuery][Range(1, int.MaxValue)] int? numberPerPage) { var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); @@ -71,7 +73,7 @@ namespace Timeline.Controllers return ForbidWithCommonResponse(); } - var posts = await _postService.GetPostsAsync(timelineId, modifiedSince, includeDeleted ?? false); + var posts = await _postService.GetPostsAsync(timelineId, modifiedSince, includeDeleted ?? false, page, numberPerPage); var result = await Map(posts); return result; diff --git a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs index 92984938..c0edf857 100644 --- a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs @@ -16,9 +16,11 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The time that posts have been modified since. /// Whether include deleted posts. + /// The page number. Starts from 0. If null, do not do pagination. + /// Count of entities per page. If null, 20. /// A list of all posts. /// Thrown when timeline does not exist. - Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false); + Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false, int? page = null, int? numberPerPage = null); /// /// Get a post of a timeline. diff --git a/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs b/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs index 5ad03011..f5112cd9 100644 --- a/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs +++ b/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs @@ -105,6 +105,24 @@ namespace Timeline.Services.Timeline { } } + /// + /// Looks up a localized string similar to Number per page can't be zero or negative.. + /// + internal static string ExceptionNumberPerPageZeroOrNegative { + get { + return ResourceManager.GetString("ExceptionNumberPerPageZeroOrNegative", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Page number can't be negative.. + /// + internal static string ExceptionPageNegative { + get { + return ResourceManager.GetString("ExceptionPageNegative", resourceCulture); + } + } + /// /// Looks up a localized string similar to Image validation failed.. /// diff --git a/BackEnd/Timeline/Services/Timeline/Resource.resx b/BackEnd/Timeline/Services/Timeline/Resource.resx index cc293d05..1d61a1bb 100644 --- a/BackEnd/Timeline/Services/Timeline/Resource.resx +++ b/BackEnd/Timeline/Services/Timeline/Resource.resx @@ -132,6 +132,12 @@ This timeline name is neither a valid personal timeline name nor a valid ordinary timeline name. {0} + + Number per page can't be zero or negative. + + + Page number can't be negative. + Image validation failed. diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs index a0961a8d..ee1002e0 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs @@ -64,8 +64,14 @@ namespace Timeline.Services.Timeline }); } - public async Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false) + public async Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false, int? page = null, int? numberPerPage = null) { + if (page.HasValue && page < 0) + throw new ArgumentOutOfRangeException(nameof(page), Resource.ExceptionPageNegative); + if (numberPerPage.HasValue && numberPerPage <= 0) + throw new ArgumentOutOfRangeException(nameof(numberPerPage), Resource.ExceptionNumberPerPageZeroOrNegative); + + await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); modifiedSince = modifiedSince?.MyToUtc(); @@ -84,6 +90,12 @@ namespace Timeline.Services.Timeline query = query.OrderBy(p => p.Time); + if (page.HasValue) + { + var npp = numberPerPage.GetValueOrDefault(20); + query = query.Skip(npp * (page.Value - 1)).Take(npp); + } + return await query.ToListAsync(); } -- cgit v1.2.3