From 53291d2c16047d3eb4c5eeb9a216c106cf47ead3 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 18 Dec 2020 19:26:50 +0800 Subject: feat: Implement bookmark service. --- BackEnd/Timeline/Entities/DatabaseContext.cs | 1 + .../Timeline/Services/BookmarkTimelineService.cs | 127 ++++++++++++++++++++- 2 files changed, 124 insertions(+), 4 deletions(-) diff --git a/BackEnd/Timeline/Entities/DatabaseContext.cs b/BackEnd/Timeline/Entities/DatabaseContext.cs index 4205c2cf..513cdc95 100644 --- a/BackEnd/Timeline/Entities/DatabaseContext.cs +++ b/BackEnd/Timeline/Entities/DatabaseContext.cs @@ -30,6 +30,7 @@ namespace Timeline.Entities public DbSet TimelinePosts { get; set; } = default!; public DbSet TimelineMembers { get; set; } = default!; public DbSet HighlightTimelines { get; set; } = default!; + public DbSet BookmarkTimelines { get; set; } = default!; public DbSet JwtToken { get; set; } = default!; public DbSet Data { get; set; } = default!; diff --git a/BackEnd/Timeline/Services/BookmarkTimelineService.cs b/BackEnd/Timeline/Services/BookmarkTimelineService.cs index 7eb691b7..f65a1ff0 100644 --- a/BackEnd/Timeline/Services/BookmarkTimelineService.cs +++ b/BackEnd/Timeline/Services/BookmarkTimelineService.cs @@ -1,6 +1,9 @@ -using System; +using Microsoft.EntityFrameworkCore; +using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; +using Timeline.Entities; using Timeline.Models; using Timeline.Services.Exceptions; @@ -59,16 +62,132 @@ namespace Timeline.Services /// /// User id of bookmark owner. /// Timeline name. - /// New position. Starts at 1. + /// New position. Starts at 1. /// Thrown when is null. /// Thrown when is not a valid name. /// Thrown when user does not exist. /// Thrown when timeline does not exist. /// Thrown when the timeline is not a bookmark. - Task MoveBookmark(long userId, string timelineName, long position); + Task MoveBookmark(long userId, string timelineName, long newPosition); } - public class BookmarkTimelineService + public class BookmarkTimelineService : IBookmarkTimelineService { + private readonly DatabaseContext _database; + private readonly IBasicUserService _userService; + private readonly ITimelineService _timelineService; + + public BookmarkTimelineService(DatabaseContext database, IBasicUserService userService, ITimelineService timelineService) + { + _database = database; + _userService = userService; + _timelineService = timelineService; + } + + public async Task AddBookmark(long userId, string timelineName) + { + if (timelineName is null) + throw new ArgumentNullException(nameof(timelineName)); + + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + var timelineId = await _timelineService.GetTimelineIdByName(timelineName); + + _database.BookmarkTimelines.Add(new BookmarkTimelineEntity + { + TimelineId = timelineId, + UserId = userId, + Rank = (await _database.BookmarkTimelines.CountAsync(t => t.UserId == userId)) + 1 + }); + + await _database.SaveChangesAsync(); + } + + 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).Select(t => new { t.TimelineId }).ToListAsync(); + + List result = new(); + + foreach (var entity in entities) + { + result.Add(await _timelineService.GetTimelineById(entity.TimelineId)); + } + + return result; + } + + public async Task MoveBookmark(long userId, string timelineName, long newPosition) + { + if (timelineName == null) + throw new ArgumentNullException(nameof(timelineName)); + + var timelineId = await _timelineService.GetTimelineIdByName(timelineName); + + 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.HighlightTimelines.CountAsync(); + 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, string timelineName) + { + if (timelineName is null) + throw new ArgumentNullException(nameof(timelineName)); + + if (!await _userService.CheckUserExistence(userId)) + throw new UserNotExistException(userId); + + var timelineId = await _timelineService.GetTimelineIdByName(timelineName); + + 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