From 4db131899145b7aca0ea5fd36984cf1542c9619b Mon Sep 17 00:00:00 2001 From: crupest Date: Sat, 9 Apr 2022 18:38:46 +0800 Subject: ... --- .../Timeline/Services/EntityDeletedException.cs | 24 ++++++ .../Services/Timeline/ITimelinePostService.cs | 25 +++++- .../Services/Timeline/TimelinePostService.cs | 90 ++++++++++++++++++---- 3 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 BackEnd/Timeline/Services/EntityDeletedException.cs (limited to 'BackEnd/Timeline/Services') diff --git a/BackEnd/Timeline/Services/EntityDeletedException.cs b/BackEnd/Timeline/Services/EntityDeletedException.cs new file mode 100644 index 00000000..a31da594 --- /dev/null +++ b/BackEnd/Timeline/Services/EntityDeletedException.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; + +namespace Timeline.Services +{ + /// + /// Thrown when an entity is deleted. + /// + [Serializable] + public class EntityDeletedException : EntityException + { + public EntityDeletedException() : base() { } + public EntityDeletedException(string? message) : base(message) { } + public EntityDeletedException(string? message, Exception? inner) : base(message, inner) { } + public EntityDeletedException(EntityType entityType, IDictionary constraints, string? message = null, Exception? inner = null) + : base(entityType, constraints, message ?? Resource.ExceptionEntityNotExist, inner) + { + + } + protected EntityDeletedException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } +} diff --git a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs index c0edf857..f595af87 100644 --- a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs @@ -4,7 +4,6 @@ using System.Threading.Tasks; using Timeline.Entities; using Timeline.Helpers.Cache; using Timeline.Models; -using Timeline.Services.Imaging; namespace Timeline.Services.Timeline { @@ -55,7 +54,29 @@ namespace Timeline.Services.Timeline /// Thrown when timeline does not exist. /// Thrown when post of does not exist or has been deleted. /// Thrown when data of that index does not exist. - Task GetPostDataAsync(long timelineId, long postId, long dataIndex); + Task GetPostDataAsync(long timelineId, long postId, long dataIndex); + + /// + /// Get posts of a timeline. + /// + /// The timeline id. + /// If not null, only posts modified since (including) the time will be returned. + /// The page to get. Starts from 1. + /// Number per page. + /// A task containing a page of post entity. + /// Thrown when timeline does not exist. + Task> GetPostsV2Async(long timelineId, DateTime? modifiedSince = null, int? page = null, int? numberPerPage = null); + + /// + /// Get a post of a timeline. + /// + /// The timeline id. + /// The post id. + /// A task containing a post entity. + /// Thrown when timeline does not exist. + /// Thrown when post does not exist. + /// Thrown when post is deleted. + Task GetPostV2Async(long timelineId, long postId); /// /// Create a new post in timeline. diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs index e6297d2c..40f226ce 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs @@ -20,8 +20,8 @@ namespace Timeline.Services.Timeline { private readonly ILogger _logger; private readonly DatabaseContext _database; - private readonly ITimelineService _basicTimelineService; - private readonly IUserService _basicUserService; + private readonly ITimelineService _timelineService; + private readonly IUserService _userService; private readonly IDataManager _dataManager; private readonly IImageService _imageValidator; private readonly IClock _clock; @@ -32,8 +32,8 @@ namespace Timeline.Services.Timeline { _logger = logger; _database = database; - _basicTimelineService = basicTimelineService; - _basicUserService = basicUserService; + _timelineService = basicTimelineService; + _userService = basicUserService; _dataManager = dataManager; _imageValidator = imageValidator; _clock = clock; @@ -53,6 +53,15 @@ namespace Timeline.Services.Timeline ["post-id"] = postId, ["deleted"] = deleted }); + } + + private static EntityNotExistException CreatePostDeletedException(long timelineId, long postId) + { + return new EntityNotExistException(EntityTypes.TimelinePost, new Dictionary + { + ["timeline-id"] = timelineId, + ["post-id"] = postId, + }); } private static EntityNotExistException CreatePostDataNotExistException(long timelineId, long postId, long dataIndex) @@ -73,7 +82,7 @@ namespace Timeline.Services.Timeline throw new ArgumentOutOfRangeException(nameof(numberPerPage), Resource.ExceptionNumberPerPageZeroOrNegative); - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); modifiedSince = modifiedSince?.MyToUtc(); @@ -102,7 +111,7 @@ namespace Timeline.Services.Timeline public async Task GetPostAsync(long timelineId, long postId, bool includeDeleted = false) { - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var post = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync(); @@ -121,7 +130,7 @@ namespace Timeline.Services.Timeline public async Task GetPostDataDigestAsync(long timelineId, long postId, long dataIndex) { - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var postEntity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).Select(p => new { p.Id, p.Deleted }).SingleOrDefaultAsync(); @@ -141,7 +150,7 @@ namespace Timeline.Services.Timeline public async Task GetPostDataAsync(long timelineId, long postId, long dataIndex) { - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var postEntity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).Select(p => new { p.Id, p.Deleted }).SingleOrDefaultAsync(); @@ -215,8 +224,8 @@ namespace Timeline.Services.Timeline request.Time = request.Time?.MyToUtc(); - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); - await _basicUserService.ThrowIfUserNotExist(authorId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); + await _userService.ThrowIfUserNotExist(authorId); var currentTime = _clock.GetCurrentTime(); var finalTime = request.Time ?? currentTime; @@ -274,7 +283,7 @@ namespace Timeline.Services.Timeline request.Time = request.Time?.MyToUtc(); - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var entity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync(); @@ -309,7 +318,7 @@ namespace Timeline.Services.Timeline public async Task DeletePostAsync(long timelineId, long postId) { - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var entity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync(); @@ -351,7 +360,7 @@ namespace Timeline.Services.Timeline public async Task HasPostModifyPermissionAsync(long timelineId, long postId, long modifierId, bool throwOnPostNotExist = false) { - await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); + await _timelineService.ThrowIfTimelineNotExist(timelineId); var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.OwnerId }).SingleAsync(); @@ -371,6 +380,59 @@ namespace Timeline.Services.Timeline } return timelineEntity.OwnerId == modifierId || postEntity.AuthorId == modifierId; - } + } + + public async Task> GetPostsV2Async(long timelineId, DateTime? modifiedSince = null, 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); + + + var timeline = await _timelineService.GetTimelineAsync(timelineId); + + modifiedSince = modifiedSince?.MyToUtc(); + + IQueryable query = _database.TimelinePosts.Where(p => p.TimelineId == timelineId); + + if (modifiedSince.HasValue) + { + query = query.Where(p => p.LastUpdated >= modifiedSince || (p.Author != null && p.Author.UsernameChangeTime >= modifiedSince)); + } + + query = query.OrderBy(p => p.Time); + + var pageNumber = page.GetValueOrDefault(1); + var pageSize = numberPerPage.GetValueOrDefault(20); + + if (pageNumber > 1) + { + query = query.Skip(pageSize * (pageNumber - 1)).Take(pageSize); + } + + var items = await query.ToListAsync(); + + return new Page(pageNumber, pageSize, timeline.CurrentPostLocalId, items); + } + + public async Task GetPostV2Async(long timelineId, long postId) + { + await _timelineService.ThrowIfTimelineNotExist(timelineId); + + var post = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync(); + + if (post is null) + { + throw CreatePostNotExistException(timelineId, postId, false); + } + + if (post.Deleted) + { + throw CreatePostDeletedException(timelineId, postId); + } + + return post; + } } } -- cgit v1.2.3