From c3369742b6e68714d0a7df46a99a0798eb2d6940 Mon Sep 17 00:00:00 2001 From: crupest Date: Tue, 11 Aug 2020 01:48:57 +0800 Subject: Handle post deletion on user deletion correctly. --- Timeline/Services/TimelineService.cs | 35 +++++++++++++++++ Timeline/Services/UserDeleteService.cs | 69 ++++++++++++++++++++++++++++++++++ Timeline/Services/UserService.cs | 44 ---------------------- 3 files changed, 104 insertions(+), 44 deletions(-) create mode 100644 Timeline/Services/UserDeleteService.cs (limited to 'Timeline/Services') diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs index ad410d15..283938fb 100644 --- a/Timeline/Services/TimelineService.cs +++ b/Timeline/Services/TimelineService.cs @@ -219,6 +219,12 @@ namespace Timeline.Services /// Task DeletePost(string timelineName, long postId); + /// + /// Delete all posts of the given user. Used when delete a user. + /// + /// The id of the user. + Task DeleteAllPostsOfUser(long userId); + /// /// Change member of timeline. /// @@ -776,6 +782,35 @@ namespace Timeline.Services } } + public async Task DeleteAllPostsOfUser(long userId) + { + var posts = await _database.TimelinePosts.Where(p => p.AuthorId == userId).ToListAsync(); + + var now = _clock.GetCurrentTime(); + + var dataTags = new List(); + + foreach (var post in posts) + { + if (post.Content != null) + { + if (post.ContentType == TimelinePostContentTypes.Image) + { + dataTags.Add(post.Content); + } + post.Content = null; + } + post.LastUpdated = now; + } + + await _database.SaveChangesAsync(); + + foreach (var dataTag in dataTags) + { + await _dataManager.FreeEntry(dataTag); + } + } + public async Task ChangeProperty(string timelineName, TimelineChangePropertyRequest newProperties) { if (timelineName == null) diff --git a/Timeline/Services/UserDeleteService.cs b/Timeline/Services/UserDeleteService.cs new file mode 100644 index 00000000..845de573 --- /dev/null +++ b/Timeline/Services/UserDeleteService.cs @@ -0,0 +1,69 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Timeline.Entities; +using Timeline.Helpers; +using Timeline.Models.Validation; +using static Timeline.Resources.Services.UserService; + +namespace Timeline.Services +{ + public interface IUserDeleteService + { + /// + /// Delete a user of given username. + /// + /// Username of the user to delete. Can't be null. + /// True if user is deleted, false if user not exist. + /// Thrown if is null. + /// Thrown when is of bad format. + Task DeleteUser(string username); + } + + public class UserDeleteService : IUserDeleteService + { + private readonly ILogger _logger; + + private readonly DatabaseContext _databaseContext; + + private readonly ITimelineService _timelineService; + + private readonly UsernameValidator _usernameValidator = new UsernameValidator(); + + public UserDeleteService(ILogger logger, DatabaseContext databaseContext, ITimelineService timelineService) + { + _logger = logger; + _databaseContext = databaseContext; + _timelineService = timelineService; + } + + public async Task DeleteUser(string username) + { + if (username == null) + throw new ArgumentNullException(nameof(username)); + + if (!_usernameValidator.Validate(username, out var message)) + { + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ExceptionUsernameBadFormat, message), nameof(username)); + } + + var user = await _databaseContext.Users.Where(u => u.Username == username).SingleOrDefaultAsync(); + if (user == null) + return false; + + await _timelineService.DeleteAllPostsOfUser(user.Id); + + _databaseContext.Users.Remove(user); + + await _databaseContext.SaveChangesAsync(); + _logger.LogInformation(Log.Format(LogDatabaseRemove, ("Id", user.Id), ("Username", user.Username))); + + return true; + } + + } +} diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 4e56c86a..c186c170 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -126,22 +126,6 @@ namespace Timeline.Services /// Task ModifyUser(string username, User? info); - /// - /// Delete a user of given id. - /// - /// Id of the user to delete. - /// True if user is deleted, false if user not exist. - Task DeleteUser(long id); - - /// - /// Delete a user of given username. - /// - /// Username of the user to delete. Can't be null. - /// True if user is deleted, false if user not exist. - /// Thrown if is null. - /// Thrown when is of bad format. - Task DeleteUser(string username); - /// /// Try to change a user's password with old password. /// @@ -428,34 +412,6 @@ namespace Timeline.Services return CreateUserFromEntity(entity); } - public async Task DeleteUser(long id) - { - var user = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync(); - if (user == null) - return false; - - _databaseContext.Users.Remove(user); - await _databaseContext.SaveChangesAsync(); - _logger.LogInformation(Log.Format(LogDatabaseRemove, ("Id", id), ("Username", user.Username))); - return true; - } - - public async Task DeleteUser(string username) - { - if (username == null) - throw new ArgumentNullException(nameof(username)); - CheckUsernameFormat(username, nameof(username)); - - var user = await _databaseContext.Users.Where(u => u.Username == username).SingleOrDefaultAsync(); - if (user == null) - return false; - - _databaseContext.Users.Remove(user); - await _databaseContext.SaveChangesAsync(); - _logger.LogInformation(Log.Format(LogDatabaseRemove, ("Id", user.Id), ("Username", username))); - return true; - } - public async Task ChangePassword(long id, string oldPassword, string newPassword) { if (oldPassword == null) -- cgit v1.2.3