From 893ed4eee63997f2d91d6715d4355d9f767b2c40 Mon Sep 17 00:00:00 2001 From: crupest Date: Mon, 9 Mar 2020 00:21:28 +0800 Subject: ... --- .../Resources/Services/TimelineService.Designer.cs | 27 +++++++++++ Timeline/Resources/Services/TimelineService.resx | 9 ++++ Timeline/Services/TimelinePostNotExistException.cs | 11 +++-- Timeline/Services/TimelineService.cs | 55 ++++++++++++++++++++-- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/Timeline/Resources/Services/TimelineService.Designer.cs b/Timeline/Resources/Services/TimelineService.Designer.cs index f4d41fb8..4c3de1cd 100644 --- a/Timeline/Resources/Services/TimelineService.Designer.cs +++ b/Timeline/Resources/Services/TimelineService.Designer.cs @@ -87,6 +87,24 @@ namespace Timeline.Resources.Services { } } + /// + /// Looks up a localized string similar to The data entry of the tag of the image post does not exist.. + /// + internal static string ExceptionGetDataDataEntryNotExist { + get { + return ResourceManager.GetString("ExceptionGetDataDataEntryNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can't get data of a non-image post.. + /// + internal static string ExceptionGetDataNonImagePost { + get { + return ResourceManager.GetString("ExceptionGetDataNonImagePost", resourceCulture); + } + } + /// /// Looks up a localized string similar to The timeline name is of bad format because {0}.. /// @@ -104,5 +122,14 @@ namespace Timeline.Resources.Services { return ResourceManager.GetString("ExceptionTimelineNameConflict", resourceCulture); } } + + /// + /// Looks up a localized string similar to Image format type of the post does not exist in column "extra_content". Normally this couldn't be possible because it should be saved when post was created. However, we now re-detect the format and save it.. + /// + internal static string LogGetDataNoFormat { + get { + return ResourceManager.GetString("LogGetDataNoFormat", resourceCulture); + } + } } } diff --git a/Timeline/Resources/Services/TimelineService.resx b/Timeline/Resources/Services/TimelineService.resx index 7df55fdf..97269943 100644 --- a/Timeline/Resources/Services/TimelineService.resx +++ b/Timeline/Resources/Services/TimelineService.resx @@ -126,10 +126,19 @@ The owner username of personal timeline is of bad format. + + The data entry of the tag of the image post does not exist. + + + Can't get data of a non-image post. + The timeline name is of bad format because {0}. The timeline with given name already exists. + + Image format type of the post does not exist in column "extra_content". Normally this couldn't be possible because it should be saved when post was created. However, we now re-detect the format and save it. + \ No newline at end of file diff --git a/Timeline/Services/TimelinePostNotExistException.cs b/Timeline/Services/TimelinePostNotExistException.cs index 97e5d550..c542e63e 100644 --- a/Timeline/Services/TimelinePostNotExistException.cs +++ b/Timeline/Services/TimelinePostNotExistException.cs @@ -12,12 +12,17 @@ namespace Timeline.Services System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { } - public TimelinePostNotExistException(long id) : base(Resources.Services.Exception.TimelinePostNotExistException) { Id = id; } + public TimelinePostNotExistException(string timelineName, long id, bool isDelete = false) : base(Resources.Services.Exception.TimelinePostNotExistException) { TimelineName = timelineName; Id = id; IsDelete = isDelete; } - public TimelinePostNotExistException(long id, string message) : base(message) { Id = id; } + public TimelinePostNotExistException(string timelineName, long id, bool isDelete, string message) : base(message) { TimelineName = timelineName; Id = id; IsDelete = isDelete; } - public TimelinePostNotExistException(long id, string message, Exception inner) : base(message, inner) { Id = id; } + public TimelinePostNotExistException(string timelineName, long id, bool isDelete, string message, Exception inner) : base(message, inner) { TimelineName = timelineName; Id = id; IsDelete = isDelete; } + public string TimelineName { get; set; } = ""; public long Id { get; set; } + /// + /// True if the post is deleted. False if the post does not exist at all. + /// + public bool IsDelete { get; set; } = false; } } diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index ff2532ea..a2b7b5ea 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -1,6 +1,7 @@ using AutoMapper; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using SixLabors.ImageSharp; using System; using System.Collections.Generic; using System.Globalization; @@ -105,7 +106,7 @@ namespace Timeline.Services /// The data and its type. /// Thrown when is null. /// Thrown when is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service). - /// Thrown when post of does not exist. + /// Thrown when post of does not exist or has been deleted. /// Thrown when post has no data. See remarks. /// /// Use this method to retrieve the image of image post. @@ -332,6 +333,7 @@ namespace Timeline.Services { protected BaseTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IImageValidator imageValidator, IDataManager dataManager, IUserService userService, IMapper mapper, IClock clock) { + _logger = loggerFactory.CreateLogger(); Clock = clock; Database = database; ImageValidator = imageValidator; @@ -340,6 +342,8 @@ namespace Timeline.Services Mapper = mapper; } + private ILogger _logger; + protected IClock Clock { get; } protected UsernameValidator UsernameValidator { get; } = new UsernameValidator(); @@ -422,7 +426,6 @@ namespace Timeline.Services if (name == null) throw new ArgumentNullException(nameof(name)); - var timelineId = await FindTimelineId(name); var postEntities = await Database.TimelinePosts.OrderBy(p => p.Time).Where(p => p.TimelineId == timelineId && p.Content != null).ToListAsync(); @@ -454,6 +457,50 @@ namespace Timeline.Services } return posts; } + public async Task GetPostData(string name, long postId) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + var timelineId = await FindTimelineId(name); + var postEntity = await Database.TimelinePosts.Where(p => p.LocalId == postId).SingleOrDefaultAsync(); + + if (postEntity == null) + throw new TimelinePostNotExistException(name, postId); + + if (postEntity.Content == null) + throw new TimelinePostNotExistException(name, postId, true); + + if (postEntity.ContentType != TimelinePostContentTypes.Image) + throw new InvalidOperationException(ExceptionGetDataNonImagePost); + + var tag = postEntity.Content; + + byte[] data; + + try + { + data = await DataManager.GetEntry(tag); + } + catch (InvalidOperationException e) + { + throw new DatabaseCorruptedException(ExceptionGetDataDataEntryNotExist, e); + } + + if (postEntity.ExtraContent == null) + { + _logger.LogWarning(LogGetDataNoFormat); + var format = Image.DetectFormat(data); + postEntity.ExtraContent = format.DefaultMimeType; + await Database.SaveChangesAsync(); + } + + return new DataWithType + { + Data = data, + Type = postEntity.ExtraContent + }; + } public async Task CreateTextPost(string name, long authorId, string text, DateTime? time) { @@ -552,7 +599,7 @@ namespace Timeline.Services var post = await Database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == id).SingleOrDefaultAsync(); if (post == null) - throw new TimelinePostNotExistException(id); + throw new TimelinePostNotExistException(name, id); string? dataTag = null; @@ -721,7 +768,7 @@ namespace Timeline.Services var postEntity = await Database.TimelinePosts.Where(p => p.Id == id).Select(p => new { p.AuthorId }).SingleOrDefaultAsync(); if (postEntity == null) - throw new TimelinePostNotExistException(id); + throw new TimelinePostNotExistException(name, id); return timelineEntity.OwnerId == modifierId || postEntity.AuthorId == modifierId; } -- cgit v1.2.3