From 1af0c82144a0f28f86922ecda04b159a553c699e Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 4 Feb 2021 20:54:18 +0800 Subject: ... --- .../Timeline/Controllers/TimelinePostController.cs | 4 +- BackEnd/Timeline/Models/Validation/Validator.cs | 2 +- BackEnd/Timeline/Services/TimelinePostService.cs | 122 ++++++++++++--------- 3 files changed, 71 insertions(+), 57 deletions(-) diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index afe9b36f..6b7ba411 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -142,7 +142,7 @@ namespace Timeline.Controllers { return BadRequest(ErrorResponse.Common.CustomMessage_InvalidModel(Resources.Messages.TimelineController_TextContentTextRequired)); } - post = await _postService.CreateTextPost(timelineId, userId, text, body.Time); + post = await _postService.CreateTextPost(timelineId, userId, text, new TimelinePostCommonProperties { Time = body.Time }); } else if (content.Type == TimelinePostContentTypes.Image) { @@ -163,7 +163,7 @@ namespace Timeline.Controllers try { - post = await _postService.CreateImagePost(timelineId, userId, data, body.Time); + post = await _postService.CreateImagePost(timelineId, userId, data, new TimelinePostCommonProperties { Time = body.Time }); } catch (ImageException) { diff --git a/BackEnd/Timeline/Models/Validation/Validator.cs b/BackEnd/Timeline/Models/Validation/Validator.cs index b7e754d3..ec6cc0af 100644 --- a/BackEnd/Timeline/Models/Validation/Validator.cs +++ b/BackEnd/Timeline/Models/Validation/Validator.cs @@ -51,7 +51,7 @@ namespace Timeline.Models.Validation public (bool, string) Validate(object? value) { - if (value == null) + if (value is null) { if (PermitNull) return (true, GetSuccessMessage()); diff --git a/BackEnd/Timeline/Services/TimelinePostService.cs b/BackEnd/Timeline/Services/TimelinePostService.cs index a8bdbf92..c2b773ff 100644 --- a/BackEnd/Timeline/Services/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/TimelinePostService.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Timeline.Entities; using Timeline.Helpers; using Timeline.Models; +using Timeline.Models.Validation; using Timeline.Services.Exceptions; using static Timeline.Resources.Services.TimelineService; @@ -23,6 +24,14 @@ namespace Timeline.Services public DateTime? LastModified { get; set; } // TODO: Why nullable? } + public class TimelinePostCommonProperties + { + public string? Color { get; set; } + + /// If not set, current time is used. + public DateTime? Time { get; set; } + } + public interface ITimelinePostService { /// @@ -64,12 +73,12 @@ namespace Timeline.Services /// The id of the timeline to create post against. /// The author's user id. /// The content text. - /// The time of the post. If null, then current time is used. + /// Some properties. /// The info of the created post. /// Thrown when is null. /// Thrown when timeline does not exist. /// Thrown if user of does not exist. - Task CreateTextPost(long timelineId, long authorId, string text, DateTime? time); + Task CreateTextPost(long timelineId, long authorId, string text, TimelinePostCommonProperties? properties = null); /// /// Create a new image post in timeline. @@ -77,13 +86,13 @@ namespace Timeline.Services /// The id of the timeline to create post against. /// The author's user id. /// The image data. - /// The time of the post. If null, then use current time. + /// Some properties. /// The info of the created post. /// Thrown when is null. /// Thrown when timeline does not exist. /// Thrown if user of does not exist. /// Thrown if data is not a image. Validated by . - Task CreateImagePost(long timelineId, long authorId, byte[] imageData, DateTime? time); + Task CreateImagePost(long timelineId, long authorId, byte[] imageData, TimelinePostCommonProperties? properties = null); /// /// Delete a post. @@ -128,17 +137,18 @@ namespace Timeline.Services private readonly ILogger _logger; private readonly DatabaseContext _database; private readonly IBasicTimelineService _basicTimelineService; - private readonly IUserService _userService; + private readonly IBasicUserService _basicUserService; private readonly IDataManager _dataManager; private readonly IImageValidator _imageValidator; private readonly IClock _clock; + private readonly ColorValidator _colorValidator = new ColorValidator(); - public TimelinePostService(ILogger logger, DatabaseContext database, IBasicTimelineService basicTimelineService, IUserService userService, IDataManager dataManager, IImageValidator imageValidator, IClock clock) + public TimelinePostService(ILogger logger, DatabaseContext database, IBasicTimelineService basicTimelineService, IBasicUserService basicUserService, IDataManager dataManager, IImageValidator imageValidator, IClock clock) { _logger = logger; _database = database; _basicTimelineService = basicTimelineService; - _userService = userService; + _basicUserService = basicUserService; _dataManager = dataManager; _imageValidator = imageValidator; _clock = clock; @@ -150,6 +160,12 @@ namespace Timeline.Services throw new TimelineNotExistException(timelineId); } + private async Task CheckUserExistence(long userId) + { + if (!await _basicUserService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + } + public async Task> GetPosts(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false) { await CheckTimelineExistence(timelineId); @@ -238,79 +254,77 @@ namespace Timeline.Services }; } - public async Task CreateTextPost(long timelineId, long authorId, string text, DateTime? time) + private async Task GeneralCreatePost(long timelineId, long authorId, TimelinePostCommonProperties? properties, Func saveContent) { - if (text is null) - throw new ArgumentNullException(nameof(text)); + if (properties is not null) + { + if (!_colorValidator.Validate(properties.Color, out var message)) + { + throw new ArgumentException(message, nameof(properties)); + } + properties.Time = properties.Time?.MyToUtc(); + } await CheckTimelineExistence(timelineId); - - time = time?.MyToUtc(); - - var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).SingleAsync(); - - var author = await _userService.GetUser(authorId); + await CheckUserExistence(authorId); var currentTime = _clock.GetCurrentTime(); - var finalTime = time ?? currentTime; - - timelineEntity.CurrentPostLocalId += 1; + var finalTime = properties?.Time ?? currentTime; var postEntity = new TimelinePostEntity { - LocalId = timelineEntity.CurrentPostLocalId, - ContentType = TimelinePostContentTypes.Text, - Content = text, AuthorId = authorId, TimelineId = timelineId, Time = finalTime, - LastUpdated = currentTime + LastUpdated = currentTime, + Color = properties?.Color }; + + await saveContent(postEntity); + + var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).SingleAsync(); + timelineEntity.CurrentPostLocalId += 1; + postEntity.LocalId = timelineEntity.CurrentPostLocalId; + _database.TimelinePosts.Add(postEntity); + await _database.SaveChangesAsync(); return postEntity; } - public async Task CreateImagePost(long timelineId, long authorId, byte[] data, DateTime? time) + public async Task CreateTextPost(long timelineId, long authorId, string text, TimelinePostCommonProperties? properties = null) { - if (data is null) - throw new ArgumentNullException(nameof(data)); - - await CheckTimelineExistence(timelineId); - - time = time?.MyToUtc(); - - var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).SingleAsync(); - - var author = await _userService.GetUser(authorId); - - var imageFormat = await _imageValidator.Validate(data); + if (text is null) + throw new ArgumentNullException(nameof(text)); - var imageFormatText = imageFormat.DefaultMimeType; + return await GeneralCreatePost(timelineId, authorId, properties, (entity) => + { + entity.ContentType = TimelinePostContentTypes.Text; + entity.Content = text; - var tag = await _dataManager.RetainEntry(data); + return Task.CompletedTask; + }); + } - var currentTime = _clock.GetCurrentTime(); - var finalTime = time ?? currentTime; + public async Task CreateImagePost(long timelineId, long authorId, byte[] data, TimelinePostCommonProperties? properties = null) + { + if (data is null) + throw new ArgumentNullException(nameof(data)); - timelineEntity.CurrentPostLocalId += 1; + await CheckTimelineExistence(timelineId); - var postEntity = new TimelinePostEntity + return await GeneralCreatePost(timelineId, authorId, properties, async (entity) => { - LocalId = timelineEntity.CurrentPostLocalId, - ContentType = TimelinePostContentTypes.Image, - Content = tag, - ExtraContent = imageFormatText, - AuthorId = authorId, - TimelineId = timelineId, - Time = finalTime, - LastUpdated = currentTime - }; - _database.TimelinePosts.Add(postEntity); - await _database.SaveChangesAsync(); + var imageFormat = await _imageValidator.Validate(data); + var imageFormatText = imageFormat.DefaultMimeType; - return postEntity; + var tag = await _dataManager.RetainEntry(data); + + entity.ContentType = TimelinePostContentTypes.Image; + entity.Content = tag; + entity.ExtraContent = imageFormatText; + }); } public async Task DeletePost(long timelineId, long postId) -- cgit v1.2.3