From 657fb589137099794e58fbd35beb7d942b376965 Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 25 Apr 2021 21:20:04 +0800 Subject: ... --- .../Services/Api/BookmarkTimelineService.cs | 205 +++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs (limited to 'BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs') diff --git a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs new file mode 100644 index 00000000..0d4cc0a6 --- /dev/null +++ b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs @@ -0,0 +1,205 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Entities; +using Timeline.Services.Timeline; +using Timeline.Services.User; + +namespace Timeline.Services.Api +{ + + [Serializable] + public class InvalidBookmarkException : Exception + { + public InvalidBookmarkException() { } + public InvalidBookmarkException(string message) : base(message) { } + public InvalidBookmarkException(string message, Exception inner) : base(message, inner) { } + protected InvalidBookmarkException( + System.Runtime.Serialization.SerializationInfo info, + System.Runtime.Serialization.StreamingContext context) : base(info, context) { } + } + + /// + /// Service interface that manages timeline bookmarks. + /// + public interface IBookmarkTimelineService + { + /// + /// Get bookmarks of a user. + /// + /// User id of bookmark owner. + /// Id of Bookmark timelines in order. + /// Thrown when user does not exist. + Task> GetBookmarks(long userId); + + /// + /// Check if a timeline is a bookmark. + /// + /// The user id. + /// Timeline id. + /// If true it will throw when user does not exist. + /// If true it will throw when timeline does not exist. + /// True if timeline is a bookmark. Otherwise false. + /// Throw if user does not exist and is true. + /// Thrown if timeline does not exist and is true. + Task IsBookmark(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true); + + /// + /// Add a bookmark to tail to a user. + /// + /// User id of bookmark owner. + /// Timeline id. + /// True if timeline is added to bookmark. False if it already is. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. + Task AddBookmark(long userId, long timelineId); + + /// + /// Remove a bookmark from a user. + /// + /// User id of bookmark owner. + /// Timeline id. + /// True if deletion is performed. False if bookmark does not exist. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. + Task RemoveBookmark(long userId, long timelineId); + + /// + /// Move bookmark to a new position. + /// + /// User id of bookmark owner. + /// Timeline name. + /// New position. Starts at 1. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. + /// Thrown when the timeline is not a bookmark. + Task MoveBookmark(long userId, long timelineId, long newPosition); + } + + public class BookmarkTimelineService : IBookmarkTimelineService + { + private readonly DatabaseContext _database; + private readonly IBasicUserService _userService; + private readonly IBasicTimelineService _timelineService; + + public BookmarkTimelineService(DatabaseContext database, IBasicUserService userService, IBasicTimelineService timelineService) + { + _database = database; + _userService = userService; + _timelineService = timelineService; + } + + public async Task AddBookmark(long userId, long timelineId) + { + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + if (!await _timelineService.CheckExistence(timelineId)) + throw new TimelineNotExistException(timelineId); + + if (await _database.BookmarkTimelines.AnyAsync(t => t.TimelineId == timelineId && t.UserId == userId)) + return false; + + _database.BookmarkTimelines.Add(new BookmarkTimelineEntity + { + TimelineId = timelineId, + UserId = userId, + Rank = (await _database.BookmarkTimelines.CountAsync(t => t.UserId == userId)) + 1 + }); + + await _database.SaveChangesAsync(); + return true; + } + + public async Task> GetBookmarks(long userId) + { + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + var entities = await _database.BookmarkTimelines.Where(t => t.UserId == userId).OrderBy(t => t.Rank).Select(t => new { t.TimelineId }).ToListAsync(); + + return entities.Select(e => e.TimelineId).ToList(); + } + + public async Task IsBookmark(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true) + { + if (checkUserExistence && !await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + if (checkTimelineExistence && !await _timelineService.CheckExistence(timelineId)) + throw new TimelineNotExistException(timelineId); + + return await _database.BookmarkTimelines.AnyAsync(b => b.TimelineId == timelineId && b.UserId == userId); + } + + public async Task MoveBookmark(long userId, long timelineId, long newPosition) + { + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + if (!await _timelineService.CheckExistence(timelineId)) + throw new TimelineNotExistException(timelineId); + + var entity = await _database.BookmarkTimelines.SingleOrDefaultAsync(t => t.TimelineId == timelineId && t.UserId == userId); + + if (entity == null) throw new InvalidBookmarkException("You can't move a non-bookmark timeline."); + + var oldPosition = entity.Rank; + + if (newPosition < 1) + { + newPosition = 1; + } + else + { + var totalCount = await _database.BookmarkTimelines.CountAsync(t => t.UserId == userId); + if (newPosition > totalCount) newPosition = totalCount; + } + + if (oldPosition == newPosition) return; + + await using var transaction = await _database.Database.BeginTransactionAsync(); + + if (newPosition > oldPosition) + { + await _database.Database.ExecuteSqlRawAsync("UPDATE `bookmark_timelines` SET `rank` = `rank` - 1 WHERE `rank` BETWEEN {0} AND {1} AND `user` = {2}", oldPosition + 1, newPosition, userId); + await _database.Database.ExecuteSqlRawAsync("UPDATE `bookmark_timelines` SET `rank` = {0} WHERE `id` = {1}", newPosition, entity.Id); + } + else + { + await _database.Database.ExecuteSqlRawAsync("UPDATE `bookmark_timelines` SET `rank` = `rank` + 1 WHERE `rank` BETWEEN {0} AND {1} AND `user` = {2}", newPosition, oldPosition - 1, userId); + await _database.Database.ExecuteSqlRawAsync("UPDATE `bookmark_timelines` SET `rank` = {0} WHERE `id` = {1}", newPosition, entity.Id); + } + + await transaction.CommitAsync(); + } + + public async Task RemoveBookmark(long userId, long timelineId) + { + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + if (!await _timelineService.CheckExistence(timelineId)) + throw new TimelineNotExistException(timelineId); + + var entity = await _database.BookmarkTimelines.SingleOrDefaultAsync(t => t.UserId == userId && t.TimelineId == timelineId); + + if (entity == null) return false; + + await using var transaction = await _database.Database.BeginTransactionAsync(); + + var rank = entity.Rank; + + _database.BookmarkTimelines.Remove(entity); + await _database.SaveChangesAsync(); + + await _database.Database.ExecuteSqlRawAsync("UPDATE `bookmark_timelines` SET `rank` = `rank` - 1 WHERE `rank` > {0}", rank); + + await transaction.CommitAsync(); + + return true; + } + } +} -- cgit v1.2.3