aboutsummaryrefslogtreecommitdiff
path: root/BackEnd/Timeline/Services
diff options
context:
space:
mode:
Diffstat (limited to 'BackEnd/Timeline/Services')
-rw-r--r--BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs111
-rw-r--r--BackEnd/Timeline/Services/Api/HighlightTimelineService.cs98
-rw-r--r--BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs62
-rw-r--r--BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs59
-rw-r--r--BackEnd/Timeline/Services/Api/ISearchService.cs33
-rw-r--r--BackEnd/Timeline/Services/Api/InvalidBookmarkException.cs15
-rw-r--r--BackEnd/Timeline/Services/Api/InvalidHighlightTimelineException.cs15
-rw-r--r--BackEnd/Timeline/Services/Api/SearchResult.cs11
-rw-r--r--BackEnd/Timeline/Services/Api/SearchResultItem.cs18
-rw-r--r--BackEnd/Timeline/Services/Api/SearchService.cs55
-rw-r--r--BackEnd/Timeline/Services/EntityAlreadyExistException.cs21
-rw-r--r--BackEnd/Timeline/Services/EntityException.cs31
-rw-r--r--BackEnd/Timeline/Services/EntityNames.cs2
-rw-r--r--BackEnd/Timeline/Services/EntityNotExistException.cs16
-rw-r--r--BackEnd/Timeline/Services/EntityType.cs34
-rw-r--r--BackEnd/Timeline/Services/EntityTypes.cs11
-rw-r--r--BackEnd/Timeline/Services/Mapper/TimelineMapper.cs4
-rw-r--r--BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs22
-rw-r--r--BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs17
-rw-r--r--BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs8
-rw-r--r--BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs37
-rw-r--r--BackEnd/Timeline/Services/Timeline/ITimelineService.cs23
-rw-r--r--BackEnd/Timeline/Services/Timeline/Resource.Designer.cs135
-rw-r--r--BackEnd/Timeline/Services/Timeline/Resource.resx45
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelineAlreadyExistException.cs24
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelineNotExistException.cs27
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelinePostDataNotExistException.cs25
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelinePostNotExistException.cs36
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelinePostService.cs99
-rw-r--r--BackEnd/Timeline/Services/Timeline/TimelineService.cs48
-rw-r--r--BackEnd/Timeline/Services/Token/IUserTokenManager.cs2
-rw-r--r--BackEnd/Timeline/Services/Token/Resource.Designer.cs9
-rw-r--r--BackEnd/Timeline/Services/Token/Resource.resx3
-rw-r--r--BackEnd/Timeline/Services/Token/UserTokenHandler.cs2
-rw-r--r--BackEnd/Timeline/Services/Token/UserTokenManager.cs2
-rw-r--r--BackEnd/Timeline/Services/User/Avatar/IUserAvatarService.cs8
-rw-r--r--BackEnd/Timeline/Services/User/BasicUserService.cs28
-rw-r--r--BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs17
-rw-r--r--BackEnd/Timeline/Services/User/IBasicUserService.cs4
-rw-r--r--BackEnd/Timeline/Services/User/IUserPermissionService.cs6
-rw-r--r--BackEnd/Timeline/Services/User/IUserService.cs8
-rw-r--r--BackEnd/Timeline/Services/User/UserAlreadyExistException.cs24
-rw-r--r--BackEnd/Timeline/Services/User/UserNotExistException.cs37
-rw-r--r--BackEnd/Timeline/Services/User/UserPermissionService.cs10
-rw-r--r--BackEnd/Timeline/Services/User/UserService.cs19
45 files changed, 746 insertions, 575 deletions
diff --git a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs
index 37b55199..de70a9db 100644
--- a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs
+++ b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
-using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -10,74 +9,6 @@ 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) { }
- }
-
- /// <summary>
- /// Service interface that manages timeline bookmarks.
- /// </summary>
- public interface IBookmarkTimelineService
- {
- /// <summary>
- /// Get bookmarks of a user.
- /// </summary>
- /// <param name="userId">User id of bookmark owner.</param>
- /// <returns>Id of Bookmark timelines in order.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
- Task<List<long>> GetBookmarks(long userId);
-
- /// <summary>
- /// Check if a timeline is a bookmark.
- /// </summary>
- /// <param name="userId">The user id.</param>
- /// <param name="timelineId">Timeline id.</param>
- /// <param name="checkUserExistence">If true it will throw when user does not exist.</param>
- /// <param name="checkTimelineExistence">If true it will throw when timeline does not exist.</param>
- /// <returns>True if timeline is a bookmark. Otherwise false.</returns>
- /// <exception cref="UserNotExistException">Throw if user does not exist and <paramref name="checkUserExistence"/> is true.</exception>
- /// <exception cref="TimelineNotExistException">Thrown if timeline does not exist and <paramref name="checkTimelineExistence"/> is true.</exception>
- Task<bool> IsBookmark(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true);
-
- /// <summary>
- /// Add a bookmark to tail to a user.
- /// </summary>
- /// <param name="userId">User id of bookmark owner.</param>
- /// <param name="timelineId">Timeline id.</param>
- /// <returns>True if timeline is added to bookmark. False if it already is.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- Task<bool> AddBookmark(long userId, long timelineId);
-
- /// <summary>
- /// Remove a bookmark from a user.
- /// </summary>
- /// <param name="userId">User id of bookmark owner.</param>
- /// <param name="timelineId">Timeline id.</param>
- /// <returns>True if deletion is performed. False if bookmark does not exist.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- Task<bool> RemoveBookmark(long userId, long timelineId);
-
- /// <summary>
- /// Move bookmark to a new position.
- /// </summary>
- /// <param name="userId">User id of bookmark owner.</param>
- /// <param name="timelineId">Timeline name.</param>
- /// <param name="newPosition">New position. Starts at 1.</param>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="InvalidBookmarkException">Thrown when the timeline is not a bookmark.</exception>
- Task MoveBookmark(long userId, long timelineId, long newPosition);
- }
-
public class BookmarkTimelineService : IBookmarkTimelineService
{
private readonly DatabaseContext _database;
@@ -91,13 +22,10 @@ namespace Timeline.Services.Api
_timelineService = timelineService;
}
- public async Task<bool> AddBookmark(long userId, long timelineId)
+ public async Task<bool> AddBookmarkAsync(long userId, long timelineId)
{
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
-
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _userService.ThrowIfUserNotExist(userId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
if (await _database.BookmarkTimelines.AnyAsync(t => t.TimelineId == timelineId && t.UserId == userId))
return false;
@@ -113,34 +41,30 @@ namespace Timeline.Services.Api
return true;
}
- public async Task<List<long>> GetBookmarks(long userId)
+ public async Task<List<long>> GetBookmarksAsync(long userId)
{
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
+ await _userService.ThrowIfUserNotExist(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<bool> IsBookmark(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true)
+ public async Task<bool> IsBookmarkAsync(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true)
{
- if (checkUserExistence && !await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
+ if (checkUserExistence)
+ await _userService.ThrowIfUserNotExist(userId);
- if (checkTimelineExistence && !await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ if (checkTimelineExistence)
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
return await _database.BookmarkTimelines.AnyAsync(b => b.TimelineId == timelineId && b.UserId == userId);
}
- public async Task MoveBookmark(long userId, long timelineId, long newPosition)
+ public async Task MoveBookmarkAsync(long userId, long timelineId, long newPosition)
{
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
-
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _userService.ThrowIfUserNotExist(userId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
var entity = await _database.BookmarkTimelines.SingleOrDefaultAsync(t => t.TimelineId == timelineId && t.UserId == userId);
@@ -176,13 +100,10 @@ namespace Timeline.Services.Api
await transaction.CommitAsync();
}
- public async Task<bool> RemoveBookmark(long userId, long timelineId)
+ public async Task<bool> RemoveBookmarkAsync(long userId, long timelineId)
{
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
-
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _userService.ThrowIfUserNotExist(userId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
var entity = await _database.BookmarkTimelines.SingleOrDefaultAsync(t => t.UserId == userId && t.TimelineId == timelineId);
diff --git a/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs b/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs
index 8224f1fe..d4367e57 100644
--- a/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs
+++ b/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs
@@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
-using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -9,72 +8,6 @@ using Timeline.Services.User;
namespace Timeline.Services.Api
{
-
- [Serializable]
- public class InvalidHighlightTimelineException : Exception
- {
- public InvalidHighlightTimelineException() { }
- public InvalidHighlightTimelineException(string message) : base(message) { }
- public InvalidHighlightTimelineException(string message, Exception inner) : base(message, inner) { }
- protected InvalidHighlightTimelineException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- }
-
- /// <summary>
- /// Service that controls highlight timeline.
- /// </summary>
- public interface IHighlightTimelineService
- {
- /// <summary>
- /// Get all highlight timelines in order.
- /// </summary>
- /// <returns>Id list of all highlight timelines.</returns>
- Task<List<long>> GetHighlightTimelines();
-
- /// <summary>
- /// Check if a timeline is highlight timeline.
- /// </summary>
- /// <param name="timelineId">Timeline id.</param>
- /// <param name="checkTimelineExistence">If true it will throw if timeline does not exist.</param>
- /// <returns>True if timeline is highlight. Otherwise false.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist and <paramref name="checkTimelineExistence"/> is true.</exception>
- Task<bool> IsHighlightTimeline(long timelineId, bool checkTimelineExistence = true);
-
- /// <summary>
- /// Add a timeline to highlight list.
- /// </summary>
- /// <param name="timelineId">The timeline id.</param>
- /// <param name="operatorId">The user id of operator.</param>
- /// <returns>True if timeline is actually added to highligh. False if it already is.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline with given id does not exist.</exception>
- /// <exception cref="UserNotExistException">Thrown when user with given operator id does not exist.</exception>
- Task<bool> AddHighlightTimeline(long timelineId, long? operatorId);
-
- /// <summary>
- /// Remove a timeline from highlight list.
- /// </summary>
- /// <param name="timelineId">The timeline id.</param>
- /// <param name="operatorId">The user id of operator.</param>
- /// <returns>True if deletion is actually performed. Otherwise false (timeline was not in the list).</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline with given id does not exist.</exception>
- /// <exception cref="UserNotExistException">Thrown when user with given operator id does not exist.</exception>
- Task<bool> RemoveHighlightTimeline(long timelineId, long? operatorId);
-
- /// <summary>
- /// Move a highlight timeline to a new position.
- /// </summary>
- /// <param name="timelineId">The timeline name.</param>
- /// <param name="newPosition">The new position. Starts at 1.</param>
- /// <exception cref="TimelineNotExistException">Thrown when timeline with given id does not exist.</exception>
- /// <exception cref="InvalidHighlightTimelineException">Thrown when given timeline is not a highlight timeline.</exception>
- /// <remarks>
- /// If <paramref name="newPosition"/> is smaller than 1. Then move the timeline to head.
- /// If <paramref name="newPosition"/> is bigger than total count. Then move the timeline to tail.
- /// </remarks>
- Task MoveHighlightTimeline(long timelineId, long newPosition);
- }
-
public class HighlightTimelineService : IHighlightTimelineService
{
private readonly DatabaseContext _database;
@@ -90,14 +23,13 @@ namespace Timeline.Services.Api
_clock = clock;
}
- public async Task<bool> AddHighlightTimeline(long timelineId, long? operatorId)
+ public async Task<bool> AddHighlightTimelineAsync(long timelineId, long? operatorId)
{
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
- if (operatorId.HasValue && !await _userService.CheckUserExistenceAsync(operatorId.Value))
+ if (operatorId.HasValue)
{
- throw new UserNotExistException(null, operatorId.Value, "User with given operator id does not exist.", null);
+ await _userService.ThrowIfUserNotExist(operatorId.Value);
}
var alreadyIs = await _database.HighlightTimelines.AnyAsync(t => t.TimelineId == timelineId);
@@ -109,21 +41,20 @@ namespace Timeline.Services.Api
return true;
}
- public async Task<List<long>> GetHighlightTimelines()
+ public async Task<List<long>> GetHighlightTimelinesAsync()
{
var entities = await _database.HighlightTimelines.OrderBy(t => t.Order).Select(t => new { t.TimelineId }).ToListAsync();
return entities.Select(e => e.TimelineId).ToList();
}
- public async Task<bool> RemoveHighlightTimeline(long timelineId, long? operatorId)
+ public async Task<bool> RemoveHighlightTimelineAsync(long timelineId, long? operatorId)
{
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
- if (operatorId.HasValue && !await _userService.CheckUserExistenceAsync(operatorId.Value))
+ if (operatorId.HasValue)
{
- throw new UserNotExistException(null, operatorId.Value, "User with given operator id does not exist.", null);
+ await _userService.ThrowIfUserNotExist(operatorId.Value);
}
var entity = await _database.HighlightTimelines.SingleOrDefaultAsync(t => t.TimelineId == timelineId);
@@ -144,10 +75,9 @@ namespace Timeline.Services.Api
return true;
}
- public async Task MoveHighlightTimeline(long timelineId, long newPosition)
+ public async Task MoveHighlightTimelineAsync(long timelineId, long newPosition)
{
- if (!await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
var entity = await _database.HighlightTimelines.SingleOrDefaultAsync(t => t.TimelineId == timelineId);
@@ -183,10 +113,10 @@ namespace Timeline.Services.Api
await transaction.CommitAsync();
}
- public async Task<bool> IsHighlightTimeline(long timelineId, bool checkTimelineExistence = true)
+ public async Task<bool> IsHighlightTimelineAsync(long timelineId, bool checkTimelineExistence = true)
{
- if (checkTimelineExistence && !await _timelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ if (checkTimelineExistence)
+ await _timelineService.ThrowIfTimelineNotExist(timelineId);
return await _database.HighlightTimelines.AnyAsync(t => t.TimelineId == timelineId);
}
diff --git a/BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs b/BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs
new file mode 100644
index 00000000..c3cda450
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs
@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Api
+{
+ /// <summary>
+ /// Service interface that manages timeline bookmarks.
+ /// </summary>
+ public interface IBookmarkTimelineService
+ {
+ /// <summary>
+ /// Get bookmarks of a user.
+ /// </summary>
+ /// <param name="userId">User id of bookmark owner.</param>
+ /// <returns>Id of Bookmark timelines in order.</returns>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
+ Task<List<long>> GetBookmarksAsync(long userId);
+
+ /// <summary>
+ /// Check if a timeline is a bookmark.
+ /// </summary>
+ /// <param name="userId">The user id.</param>
+ /// <param name="timelineId">Timeline id.</param>
+ /// <param name="checkUserExistence">If true it will throw when user does not exist.</param>
+ /// <param name="checkTimelineExistence">If true it will throw when timeline does not exist.</param>
+ /// <returns>True if timeline is a bookmark. Otherwise false.</returns>
+ /// <exception cref="EntityNotExistException">Throw if user does not exist and <paramref name="checkUserExistence"/> is true.</exception>
+ /// <exception cref="EntityNotExistException">Thrown if timeline does not exist and <paramref name="checkTimelineExistence"/> is true.</exception>
+ Task<bool> IsBookmarkAsync(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true);
+
+ /// <summary>
+ /// Add a bookmark to tail to a user.
+ /// </summary>
+ /// <param name="userId">User id of bookmark owner.</param>
+ /// <param name="timelineId">Timeline id.</param>
+ /// <returns>True if timeline is added to bookmark. False if it already is.</returns>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ Task<bool> AddBookmarkAsync(long userId, long timelineId);
+
+ /// <summary>
+ /// Remove a bookmark from a user.
+ /// </summary>
+ /// <param name="userId">User id of bookmark owner.</param>
+ /// <param name="timelineId">Timeline id.</param>
+ /// <returns>True if deletion is performed. False if bookmark does not exist.</returns>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ Task<bool> RemoveBookmarkAsync(long userId, long timelineId);
+
+ /// <summary>
+ /// Move bookmark to a new position.
+ /// </summary>
+ /// <param name="userId">User id of bookmark owner.</param>
+ /// <param name="timelineId">Timeline name.</param>
+ /// <param name="newPosition">New position. Starts at 1.</param>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="InvalidBookmarkException">Thrown when the timeline is not a bookmark.</exception>
+ Task MoveBookmarkAsync(long userId, long timelineId, long newPosition);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs b/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs
new file mode 100644
index 00000000..56a0fb35
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs
@@ -0,0 +1,59 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Api
+{
+ /// <summary>
+ /// Service that controls highlight timeline.
+ /// </summary>
+ public interface IHighlightTimelineService
+ {
+ /// <summary>
+ /// Get all highlight timelines in order.
+ /// </summary>
+ /// <returns>Id list of all highlight timelines.</returns>
+ Task<List<long>> GetHighlightTimelinesAsync();
+
+ /// <summary>
+ /// Check if a timeline is highlight timeline.
+ /// </summary>
+ /// <param name="timelineId">Timeline id.</param>
+ /// <param name="checkTimelineExistence">If true it will throw if timeline does not exist.</param>
+ /// <returns>True if timeline is highlight. Otherwise false.</returns>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist and <paramref name="checkTimelineExistence"/> is true.</exception>
+ Task<bool> IsHighlightTimelineAsync(long timelineId, bool checkTimelineExistence = true);
+
+ /// <summary>
+ /// Add a timeline to highlight list.
+ /// </summary>
+ /// <param name="timelineId">The timeline id.</param>
+ /// <param name="operatorId">The user id of operator.</param>
+ /// <returns>True if timeline is actually added to highligh. False if it already is.</returns>
+ /// <exception cref="EntityNotExistException">Thrown when timeline with given id does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user with given operator id does not exist.</exception>
+ Task<bool> AddHighlightTimelineAsync(long timelineId, long? operatorId);
+
+ /// <summary>
+ /// Remove a timeline from highlight list.
+ /// </summary>
+ /// <param name="timelineId">The timeline id.</param>
+ /// <param name="operatorId">The user id of operator.</param>
+ /// <returns>True if deletion is actually performed. Otherwise false (timeline was not in the list).</returns>
+ /// <exception cref="EntityNotExistException">Thrown when timeline with given id does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user with given operator id does not exist.</exception>
+ Task<bool> RemoveHighlightTimelineAsync(long timelineId, long? operatorId);
+
+ /// <summary>
+ /// Move a highlight timeline to a new position.
+ /// </summary>
+ /// <param name="timelineId">The timeline name.</param>
+ /// <param name="newPosition">The new position. Starts at 1.</param>
+ /// <exception cref="EntityNotExistException">Thrown when timeline with given id does not exist.</exception>
+ /// <exception cref="InvalidHighlightTimelineException">Thrown when given timeline is not a highlight timeline.</exception>
+ /// <remarks>
+ /// If <paramref name="newPosition"/> is smaller than 1. Then move the timeline to head.
+ /// If <paramref name="newPosition"/> is bigger than total count. Then move the timeline to tail.
+ /// </remarks>
+ Task MoveHighlightTimelineAsync(long timelineId, long newPosition);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/ISearchService.cs b/BackEnd/Timeline/Services/Api/ISearchService.cs
new file mode 100644
index 00000000..d8b4bb44
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/ISearchService.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Threading.Tasks;
+using Timeline.Entities;
+
+namespace Timeline.Services.Api
+{
+ public interface ISearchService
+ {
+ /// <summary>
+ /// Search timelines whose name or title contains query string.
+ /// </summary>
+ /// <param name="query">String to contain.</param>
+ /// <returns>Search results.</returns>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="query"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="query"/> is empty.</exception>
+ /// <remarks>
+ /// Implementation should promise high score is at first.
+ /// </remarks>
+ Task<SearchResult<TimelineEntity>> SearchTimelineAsync(string query);
+
+ /// <summary>
+ /// Search users whose username or nickname contains query string.
+ /// </summary>
+ /// <param name="query">String to contain.</param>
+ /// <returns>Search results.</returns>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="query"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="query"/> is empty.</exception>
+ /// <remarks>
+ /// Implementation should promise high score is at first.
+ /// </remarks>
+ Task<SearchResult<UserEntity>> SearchUserAsync(string query);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/InvalidBookmarkException.cs b/BackEnd/Timeline/Services/Api/InvalidBookmarkException.cs
new file mode 100644
index 00000000..39572b38
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/InvalidBookmarkException.cs
@@ -0,0 +1,15 @@
+using System;
+
+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) { }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/InvalidHighlightTimelineException.cs b/BackEnd/Timeline/Services/Api/InvalidHighlightTimelineException.cs
new file mode 100644
index 00000000..13b04a6b
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/InvalidHighlightTimelineException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Timeline.Services.Api
+{
+ [Serializable]
+ public class InvalidHighlightTimelineException : Exception
+ {
+ public InvalidHighlightTimelineException() { }
+ public InvalidHighlightTimelineException(string message) : base(message) { }
+ public InvalidHighlightTimelineException(string message, Exception inner) : base(message, inner) { }
+ protected InvalidHighlightTimelineException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/SearchResult.cs b/BackEnd/Timeline/Services/Api/SearchResult.cs
new file mode 100644
index 00000000..7c95ae5d
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/SearchResult.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace Timeline.Services.Api
+{
+ public class SearchResult<TItem>
+ {
+#pragma warning disable CA2227 // Collection properties should be read only
+ public List<SearchResultItem<TItem>> Items { get; set; } = new();
+#pragma warning restore CA2227 // Collection properties should be read only
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/SearchResultItem.cs b/BackEnd/Timeline/Services/Api/SearchResultItem.cs
new file mode 100644
index 00000000..ac40281f
--- /dev/null
+++ b/BackEnd/Timeline/Services/Api/SearchResultItem.cs
@@ -0,0 +1,18 @@
+namespace Timeline.Services.Api
+{
+ public class SearchResultItem<TItem>
+ {
+ public SearchResultItem(TItem item, int score)
+ {
+ Item = item;
+ Score = score;
+ }
+
+ public TItem Item { get; set; } = default!;
+
+ /// <summary>
+ /// Bigger is better.
+ /// </summary>
+ public int Score { get; set; }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Api/SearchService.cs b/BackEnd/Timeline/Services/Api/SearchService.cs
index eec5001f..037f0490 100644
--- a/BackEnd/Timeline/Services/Api/SearchService.cs
+++ b/BackEnd/Timeline/Services/Api/SearchService.cs
@@ -1,62 +1,11 @@
using Microsoft.EntityFrameworkCore;
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
namespace Timeline.Services.Api
{
- public class SearchResultItem<TItem>
- {
- public SearchResultItem(TItem item, int score)
- {
- Item = item;
- Score = score;
- }
-
- public TItem Item { get; set; } = default!;
-
- /// <summary>
- /// Bigger is better.
- /// </summary>
- public int Score { get; set; }
- }
-
- public class SearchResult<TItem>
- {
-#pragma warning disable CA2227 // Collection properties should be read only
- public List<SearchResultItem<TItem>> Items { get; set; } = new();
-#pragma warning restore CA2227 // Collection properties should be read only
- }
-
- public interface ISearchService
- {
- /// <summary>
- /// Search timelines whose name or title contains query string.
- /// </summary>
- /// <param name="query">String to contain.</param>
- /// <returns>Search results.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="query"/> is null.</exception>
- /// <exception cref="ArgumentException">Thrown when <paramref name="query"/> is empty.</exception>
- /// <remarks>
- /// Implementation should promise high score is at first.
- /// </remarks>
- Task<SearchResult<TimelineEntity>> SearchTimeline(string query);
-
- /// <summary>
- /// Search users whose username or nickname contains query string.
- /// </summary>
- /// <param name="query">String to contain.</param>
- /// <returns>Search results.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="query"/> is null.</exception>
- /// <exception cref="ArgumentException">Thrown when <paramref name="query"/> is empty.</exception>
- /// <remarks>
- /// Implementation should promise high score is at first.
- /// </remarks>
- Task<SearchResult<UserEntity>> SearchUser(string query);
- }
-
public class SearchService : ISearchService
{
private readonly DatabaseContext _database;
@@ -66,7 +15,7 @@ namespace Timeline.Services.Api
_database = database;
}
- public async Task<SearchResult<TimelineEntity>> SearchTimeline(string query)
+ public async Task<SearchResult<TimelineEntity>> SearchTimelineAsync(string query)
{
if (query is null)
throw new ArgumentNullException(nameof(query));
@@ -83,7 +32,7 @@ namespace Timeline.Services.Api
return searchResult;
}
- public async Task<SearchResult<UserEntity>> SearchUser(string query)
+ public async Task<SearchResult<UserEntity>> SearchUserAsync(string query)
{
if (query is null)
throw new ArgumentNullException(nameof(query));
diff --git a/BackEnd/Timeline/Services/EntityAlreadyExistException.cs b/BackEnd/Timeline/Services/EntityAlreadyExistException.cs
index 2d3de368..0aaea012 100644
--- a/BackEnd/Timeline/Services/EntityAlreadyExistException.cs
+++ b/BackEnd/Timeline/Services/EntityAlreadyExistException.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace Timeline.Services
{
@@ -9,24 +10,18 @@ namespace Timeline.Services
/// For example, want to create a timeline but a timeline with the same name already exists.
/// </remarks>
[Serializable]
- public class EntityAlreadyExistException : Exception
+ public class EntityAlreadyExistException : EntityException
{
- public EntityAlreadyExistException() : this(null, null, null, null) { }
- public EntityAlreadyExistException(string? entityName) : this(entityName, null, null, null) { }
- public EntityAlreadyExistException(string? entityName, Exception? inner) : this(entityName, null, null, inner) { }
- public EntityAlreadyExistException(string? entityName, object? entity, Exception inner) : this(entityName, entity, null, inner) { }
- public EntityAlreadyExistException(string? entityName, object? entity, string? message, Exception? inner) : base(message ?? Resource.ExceptionEntityAlreadyExist, inner)
+ public EntityAlreadyExistException() : base() { }
+ public EntityAlreadyExistException(string? message) : base(message) { }
+ public EntityAlreadyExistException(string? message, Exception? inner) : base(message, inner) { }
+ public EntityAlreadyExistException(EntityType entityType, IDictionary<string, object> constraints, string? message = null, Exception? inner = null)
+ : base(entityType, constraints, message ?? Resource.ExceptionEntityNotExist, inner)
{
- EntityName = entityName;
- Entity = entity;
- }
+ }
protected EntityAlreadyExistException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public string? EntityName { get; }
-
- public object? Entity { get; }
}
}
diff --git a/BackEnd/Timeline/Services/EntityException.cs b/BackEnd/Timeline/Services/EntityException.cs
new file mode 100644
index 00000000..7a302e5a
--- /dev/null
+++ b/BackEnd/Timeline/Services/EntityException.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Timeline.Services
+{
+ [Serializable]
+ public class EntityException : Exception
+ {
+ public EntityException() { }
+ public EntityException(string? message) : base(message) { }
+ public EntityException(string? message, Exception? inner) : base(message, inner) { }
+ public EntityException(EntityType entityType, IDictionary<string, object> constraints, string? message = null, Exception? inner = null)
+ : base(message, inner)
+ {
+ EntityType = entityType;
+ Constraints = constraints;
+ }
+ protected EntityException(
+ System.Runtime.Serialization.SerializationInfo info,
+ System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
+
+ public EntityType EntityType { get; } = EntityTypes.Default;
+ public IDictionary<string, object> Constraints { get; } = new Dictionary<string, object>();
+
+ public string GenerateConstraintString()
+ {
+ return string.Join(' ', Constraints.Select(c => $"[{c.Key} = {c.Value}]"));
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/EntityNames.cs b/BackEnd/Timeline/Services/EntityNames.cs
index 7dae6a4a..5df5e615 100644
--- a/BackEnd/Timeline/Services/EntityNames.cs
+++ b/BackEnd/Timeline/Services/EntityNames.cs
@@ -2,8 +2,10 @@
{
public static class EntityNames
{
+ public const string Default = "Default";
public const string User = "User";
public const string Timeline = "Timeline";
public const string TimelinePost = "TimelinePost";
+ public const string TimelinePostData = "TimelinePostData";
}
}
diff --git a/BackEnd/Timeline/Services/EntityNotExistException.cs b/BackEnd/Timeline/Services/EntityNotExistException.cs
index 39a4f545..0c836fc4 100644
--- a/BackEnd/Timeline/Services/EntityNotExistException.cs
+++ b/BackEnd/Timeline/Services/EntityNotExistException.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace Timeline.Services
{
@@ -9,19 +10,18 @@ namespace Timeline.Services
/// For example, you want to get a timeline with given name but it does not exist.
/// </example>
[Serializable]
- public class EntityNotExistException : Exception
+ public class EntityNotExistException : EntityException
{
- public EntityNotExistException() : this(null, null) { }
- public EntityNotExistException(string? entityName) : this(entityName, null) { }
- public EntityNotExistException(string? entityName, Exception? inner) : this(entityName, null, inner) { }
- public EntityNotExistException(string? entityName, string? message, Exception? inner) : base(message ?? Resource.ExceptionEntityNotExist, inner)
+ public EntityNotExistException() : base() { }
+ public EntityNotExistException(string? message) : base(message) { }
+ public EntityNotExistException(string? message, Exception? inner) : base(message, inner) { }
+ public EntityNotExistException(EntityType entityType, IDictionary<string, object> constraints, string? message = null, Exception? inner = null)
+ : base(entityType, constraints, message ?? Resource.ExceptionEntityNotExist, inner)
{
- EntityName = entityName;
+
}
protected EntityNotExistException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public string? EntityName { get; }
}
}
diff --git a/BackEnd/Timeline/Services/EntityType.cs b/BackEnd/Timeline/Services/EntityType.cs
new file mode 100644
index 00000000..c379d211
--- /dev/null
+++ b/BackEnd/Timeline/Services/EntityType.cs
@@ -0,0 +1,34 @@
+using System.Reflection;
+
+namespace Timeline.Services
+{
+ public class EntityType
+ {
+ public EntityType(string name)
+ {
+ Name = name;
+ }
+
+ public string Name { get; }
+
+ public int NotExistErrorCode
+ {
+ get
+ {
+ var field = typeof(ErrorCodes.NotExist).GetField(Name, BindingFlags.Public | BindingFlags.Static);
+ if (field is not null) return (int)field.GetRawConstantValue()!;
+ return ErrorCodes.NotExist.Default;
+ }
+ }
+
+ public int ConflictErrorCode
+ {
+ get
+ {
+ var field = typeof(ErrorCodes.Conflict).GetField(Name, BindingFlags.Public | BindingFlags.Static);
+ if (field is not null) return (int)field.GetRawConstantValue()!;
+ return ErrorCodes.Conflict.Default;
+ }
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/EntityTypes.cs b/BackEnd/Timeline/Services/EntityTypes.cs
new file mode 100644
index 00000000..d4884fd6
--- /dev/null
+++ b/BackEnd/Timeline/Services/EntityTypes.cs
@@ -0,0 +1,11 @@
+namespace Timeline.Services
+{
+ public static class EntityTypes
+ {
+ public static EntityType Default { get; } = new EntityType(EntityNames.Default);
+ public static EntityType User { get; } = new EntityType(EntityNames.User);
+ public static EntityType Timeline { get; } = new EntityType(EntityNames.Timeline);
+ public static EntityType TimelinePost { get; } = new EntityType(EntityNames.TimelinePost);
+ public static EntityType TimelinePostData { get; } = new EntityType(EntityNames.TimelinePostData);
+ }
+}
diff --git a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs
index 5ee90a8f..d3159423 100644
--- a/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs
+++ b/BackEnd/Timeline/Services/Mapper/TimelineMapper.cs
@@ -85,8 +85,8 @@ namespace Timeline.Services.Mapper
color: entity.Color,
createTime: entity.CreateTime,
lastModified: entity.LastModified,
- isHighlight: await _highlightTimelineService.IsHighlightTimeline(entity.Id),
- isBookmark: userId is not null && await _bookmarkTimelineService.IsBookmark(userId.Value, entity.Id, false, false),
+ isHighlight: await _highlightTimelineService.IsHighlightTimelineAsync(entity.Id),
+ isBookmark: userId is not null && await _bookmarkTimelineService.IsBookmarkAsync(userId.Value, entity.Id, false, false),
manageable: manageable,
postable: postable,
links: new HttpTimelineLinks(
diff --git a/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs b/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs
index 7476a860..360f6c63 100644
--- a/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs
+++ b/BackEnd/Timeline/Services/Timeline/BasicTimelineService.cs
@@ -47,6 +47,22 @@ namespace Timeline.Services.Timeline
};
}
+ protected static EntityNotExistException CreateTimelineNotExistException(string name, Exception? inner = null)
+ {
+ return new EntityNotExistException(EntityTypes.Timeline, new Dictionary<string, object>
+ {
+ ["name"] = name
+ }, null, inner);
+ }
+
+ protected static EntityNotExistException CreateTimelineNotExistException(long id)
+ {
+ return new EntityNotExistException(EntityTypes.Timeline, new Dictionary<string, object>
+ {
+ ["id"] = id
+ });
+ }
+
protected void CheckGeneralTimelineName(string timelineName, string? paramName)
{
if (!_generalTimelineNameValidator.Validate(timelineName, out var message))
@@ -75,9 +91,9 @@ namespace Timeline.Services.Timeline
{
userId = await _basicUserService.GetUserIdByUsernameAsync(username);
}
- catch (UserNotExistException e)
+ catch (EntityNotExistException e)
{
- throw new TimelineNotExistException(timelineName, e);
+ throw CreateTimelineNotExistException(timelineName, e);
}
var timelineEntity = await _database.Timelines.Where(t => t.OwnerId == userId && t.Name == null).Select(t => new { t.Id }).SingleOrDefaultAsync();
@@ -103,7 +119,7 @@ namespace Timeline.Services.Timeline
if (timelineEntity == null)
{
- throw new TimelineNotExistException(timelineName);
+ throw CreateTimelineNotExistException(timelineName);
}
else
{
diff --git a/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs b/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs
new file mode 100644
index 00000000..4075c9c0
--- /dev/null
+++ b/BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.Timeline
+{
+ public static class BasicTimelineServiceExtensions
+ {
+ public static async Task ThrowIfTimelineNotExist(this IBasicTimelineService service, long timelineId)
+ {
+ if (!await service.CheckTimelineExistenceAsync(timelineId))
+ {
+ throw new EntityNotExistException(EntityTypes.Timeline,
+ new Dictionary<string, object> { ["id"] = timelineId });
+ }
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs b/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs
index b32fa3f7..b6f1e6de 100644
--- a/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs
+++ b/BackEnd/Timeline/Services/Timeline/IBasicTimelineService.cs
@@ -1,6 +1,5 @@
using System;
using System.Threading.Tasks;
-using Timeline.Services.User;
namespace Timeline.Services.Timeline
{
@@ -23,14 +22,9 @@ namespace Timeline.Services.Timeline
/// <returns>Id of the timeline.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="timelineName"/> is null.</exception>
/// <exception cref="ArgumentException">Throw when <paramref name="timelineName"/> is of bad format.</exception>
- /// <exception cref="TimelineNotExistException">
+ /// <exception cref="EntityNotExistException">
/// Thrown when timeline with name <paramref name="timelineName"/> does not exist.
- /// If it is a personal timeline, then inner exception is <see cref="UserNotExistException"/>.
/// </exception>
- /// <remarks>
- /// If name is of personal timeline and the timeline does not exist, it will be created if user exists.
- /// If the user does not exist, <see cref="TimelineNotExistException"/> will be thrown with <see cref="UserNotExistException"/> as inner exception.
- ///</remarks>
Task<long> GetTimelineIdByNameAsync(string timelineName);
}
}
diff --git a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs
index 50af9fc2..d746cf63 100644
--- a/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs
+++ b/BackEnd/Timeline/Services/Timeline/ITimelinePostService.cs
@@ -5,7 +5,6 @@ using Timeline.Entities;
using Timeline.Helpers.Cache;
using Timeline.Models;
using Timeline.Services.Imaging;
-using Timeline.Services.User;
namespace Timeline.Services.Timeline
{
@@ -18,7 +17,7 @@ namespace Timeline.Services.Timeline
/// <param name="modifiedSince">The time that posts have been modified since.</param>
/// <param name="includeDeleted">Whether include deleted posts.</param>
/// <returns>A list of all posts.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
Task<List<TimelinePostEntity>> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false);
/// <summary>
@@ -28,8 +27,8 @@ namespace Timeline.Services.Timeline
/// <param name="postId">The id of the post.</param>
/// <param name="includeDeleted">If true, return the entity even if it is deleted.</param>
/// <returns>The post.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
Task<TimelinePostEntity> GetPostAsync(long timelineId, long postId, bool includeDeleted = false);
/// <summary>
@@ -39,9 +38,9 @@ namespace Timeline.Services.Timeline
/// <param name="postId">The post id.</param>
/// <param name="dataIndex">The index of the data.</param>
/// <returns>The data digest.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
- /// <exception cref="TimelinePostDataNotExistException">Thrown when data of that index does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when data of that index does not exist.</exception>
Task<ICacheableDataDigest> GetPostDataDigestAsync(long timelineId, long postId, long dataIndex);
/// <summary>
@@ -51,9 +50,9 @@ namespace Timeline.Services.Timeline
/// <param name="postId">The post id.</param>
/// <param name="dataIndex">The index of the data.</param>
/// <returns>The data.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
- /// <exception cref="TimelinePostDataNotExistException">Thrown when data of that index does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when post of <paramref name="postId"/> does not exist or has been deleted.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when data of that index does not exist.</exception>
Task<ByteData> GetPostDataAsync(long timelineId, long postId, long dataIndex);
/// <summary>
@@ -65,8 +64,8 @@ namespace Timeline.Services.Timeline
/// <returns>The entity of the created post.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="request"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="request"/> is of invalid format.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="UserNotExistException">Thrown if user of <paramref name="authorId"/> does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown if user of <paramref name="authorId"/> does not exist.</exception>
/// <exception cref="ImageException">Thrown if data is not a image. Validated by <see cref="ImageService"/>.</exception>
Task<TimelinePostEntity> CreatePostAsync(long timelineId, long authorId, TimelinePostCreateRequest request);
@@ -79,8 +78,8 @@ namespace Timeline.Services.Timeline
/// <returns>The entity of the patched post.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="request"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="request"/> is of invalid format.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when post does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when post does not exist.</exception>
Task<TimelinePostEntity> PatchPostAsync(long timelineId, long postId, TimelinePostPatchRequest request);
/// <summary>
@@ -88,8 +87,8 @@ namespace Timeline.Services.Timeline
/// </summary>
/// <param name="timelineId">The id of the timeline to delete post against.</param>
/// <param name="postId">The id of the post to delete.</param>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when the post with given id does not exist or is deleted already.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the post with given id does not exist or is deleted already.</exception>
/// <remarks>
/// First use <see cref="HasPostModifyPermissionAsync(long, long, long, bool)"/> to check the permission.
/// </remarks>
@@ -107,10 +106,10 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">The id of the timeline.</param>
/// <param name="postId">The id of the post.</param>
/// <param name="modifierId">The id of the user to check on.</param>
- /// <param name="throwOnPostNotExist">True if you want it to throw <see cref="TimelinePostNotExistException"/>. Default false.</param>
+ /// <param name="throwOnPostNotExist">True if you want it to throw <see cref="EntityNotExistException"/>. Default false.</param>
/// <returns>True if can modify, false if can't modify.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="TimelinePostNotExistException">Thrown when the post with given id does not exist or is deleted already and <paramref name="throwOnPostNotExist"/> is true.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the post with given id does not exist or is deleted already and <paramref name="throwOnPostNotExist"/> is true.</exception>
/// <remarks>
/// Unless <paramref name="throwOnPostNotExist"/> is true, this method should return true if the post does not exist.
/// If the post is deleted, its author info still exists, so it is checked as the post is not deleted unless <paramref name="throwOnPostNotExist"/> is true.
diff --git a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs
index 9c313b0b..c5bd5abf 100644
--- a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs
+++ b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using Timeline.Entities;
using Timeline.Models;
-using Timeline.Services.User;
namespace Timeline.Services.Timeline
{
@@ -17,7 +16,7 @@ namespace Timeline.Services.Timeline
/// </summary>
/// <param name="id">Id of timeline.</param>
/// <returns>The timeline info.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
Task<TimelineEntity> GetTimelineAsync(long id);
/// <summary>
@@ -26,7 +25,7 @@ namespace Timeline.Services.Timeline
/// <param name="id">The id of the timeline.</param>
/// <param name="newProperties">The new properties. Null member means not to change.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="newProperties"/> is null.</exception>
- /// <exception cref="TimelineNotExistException">Thrown when timeline with given id does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline with given id does not exist.</exception>
/// <exception cref="EntityAlreadyExistException">Thrown when a timeline with new name already exists.</exception>
Task ChangePropertyAsync(long id, TimelineChangePropertyParams newProperties);
@@ -36,8 +35,8 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">Timeline id.</param>
/// <param name="userId">User id.</param>
/// <returns>True if the memeber was added. False if it is already a member.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user does not exist.</exception>
Task<bool> AddMemberAsync(long timelineId, long userId);
/// <summary>
@@ -46,8 +45,8 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">Timeline id.</param>
/// <param name="userId">User id.</param>
/// <returns>True if the memeber was removed. False if it was not a member before.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user does not exist.</exception>
Task<bool> RemoveMemberAsync(long timelineId, long userId);
/// <summary>
@@ -56,7 +55,7 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">The id of the timeline.</param>
/// <param name="userId">The id of the user to check on.</param>
/// <returns>True if the user can manage the timeline, otherwise false.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
/// <remarks>
/// This method does not check whether visitor is administrator.
/// Return false if user with user id does not exist.
@@ -69,7 +68,7 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">The id of the timeline.</param>
/// <param name="visitorId">The id of the user to check on. Null means visitor without account.</param>
/// <returns>True if can read, false if can't read.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
/// <remarks>
/// This method does not check whether visitor is administrator.
/// Return false if user with visitor id does not exist.
@@ -82,7 +81,7 @@ namespace Timeline.Services.Timeline
/// <param name="timelineId">The id of the timeline.</param>
/// <param name="userId">The id of user to check on.</param>
/// <returns>True if it is a member, false if not.</returns>
- /// <exception cref="TimelineNotExistException">Thrown when timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when timeline does not exist.</exception>
/// <remarks>
/// Timeline owner is also considered as a member.
/// Return false when user with user id does not exist.
@@ -109,14 +108,14 @@ namespace Timeline.Services.Timeline
/// <exception cref="ArgumentNullException">Thrown when <paramref name="timelineName"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when timeline name is invalid.</exception>
/// <exception cref="EntityAlreadyExistException">Thrown when the timeline already exists.</exception>
- /// <exception cref="UserNotExistException">Thrown when the owner user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the owner user does not exist.</exception>
Task<TimelineEntity> CreateTimelineAsync(string timelineName, long ownerId);
/// <summary>
/// Delete a timeline.
/// </summary>
/// <param name="id">The id of the timeline to delete.</param>
- /// <exception cref="TimelineNotExistException">Thrown when the timeline does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the timeline does not exist.</exception>
Task DeleteTimelineAsync(long id);
}
}
diff --git a/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs b/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs
index 6faea295..5ad03011 100644
--- a/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs
+++ b/BackEnd/Timeline/Services/Timeline/Resource.Designer.cs
@@ -61,6 +61,42 @@ namespace Timeline.Services.Timeline {
}
/// <summary>
+ /// Looks up a localized string similar to Color is not valid. {0}.
+ /// </summary>
+ internal static string ExceptionColorInvalid {
+ get {
+ return ResourceManager.GetString("ExceptionColorInvalid", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Data list can&apos;t be empty..
+ /// </summary>
+ internal static string ExceptionDataListEmpty {
+ get {
+ return ResourceManager.GetString("ExceptionDataListEmpty", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Data list can&apos;t be null..
+ /// </summary>
+ internal static string ExceptionDataListNull {
+ get {
+ return ResourceManager.GetString("ExceptionDataListNull", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Data list count can&apos;t be bigger than 100..
+ /// </summary>
+ internal static string ExceptionDataListTooLarge {
+ get {
+ return ResourceManager.GetString("ExceptionDataListTooLarge", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to This timeline name is neither a valid personal timeline name nor a valid ordinary timeline name. {0}.
/// </summary>
internal static string ExceptionGeneralTimelineNameBadFormat {
@@ -70,6 +106,33 @@ namespace Timeline.Services.Timeline {
}
/// <summary>
+ /// Looks up a localized string similar to Image validation failed..
+ /// </summary>
+ internal static string ExceptionPostDataImageInvalid {
+ get {
+ return ResourceManager.GetString("ExceptionPostDataImageInvalid", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to It is not a valid utf-8 sequence..
+ /// </summary>
+ internal static string ExceptionPostDataNotValidUtf8 {
+ get {
+ return ResourceManager.GetString("ExceptionPostDataNotValidUtf8", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Unsupported content type..
+ /// </summary>
+ internal static string ExceptionPostDataUnsupportedType {
+ get {
+ return ResourceManager.GetString("ExceptionPostDataUnsupportedType", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to Timeline with given constraints already exist..
/// </summary>
internal static string ExceptionTimelineAlreadyExist {
@@ -131,5 +194,77 @@ namespace Timeline.Services.Timeline {
return ResourceManager.GetString("LogPersonalTimelineAutoCreate", resourceCulture);
}
}
+
+ /// <summary>
+ /// Looks up a localized string similar to A member(user id={0}) is added to timeline(id={1})..
+ /// </summary>
+ internal static string LogTimelineAddMember {
+ get {
+ return ResourceManager.GetString("LogTimelineAddMember", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A timeline is created with name={0}, id={1}..
+ /// </summary>
+ internal static string LogTimelineCreate {
+ get {
+ return ResourceManager.GetString("LogTimelineCreate", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A timeline(id={0}) is deleted..
+ /// </summary>
+ internal static string LogTimelineDelete {
+ get {
+ return ResourceManager.GetString("LogTimelineDelete", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A timeline(id={0}) post(id={1}) is created..
+ /// </summary>
+ internal static string LogTimelinePostCreated {
+ get {
+ return ResourceManager.GetString("LogTimelinePostCreated", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A timeline(id={0}) post(id={1}) is deleted..
+ /// </summary>
+ internal static string LogTimelinePostDeleted {
+ get {
+ return ResourceManager.GetString("LogTimelinePostDeleted", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A timeline(id={0}) post(id={1}) is updated..
+ /// </summary>
+ internal static string LogTimelinePostUpdated {
+ get {
+ return ResourceManager.GetString("LogTimelinePostUpdated", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to A member(user id={0}) is removed from timeline(id={1})..
+ /// </summary>
+ internal static string LogTimelineRemoveMember {
+ get {
+ return ResourceManager.GetString("LogTimelineRemoveMember", resourceCulture);
+ }
+ }
+
+ /// <summary>
+ /// Looks up a localized string similar to Timeline with id={0} is updated..
+ /// </summary>
+ internal static string LogTimelineUpdated {
+ get {
+ return ResourceManager.GetString("LogTimelineUpdated", resourceCulture);
+ }
+ }
}
}
diff --git a/BackEnd/Timeline/Services/Timeline/Resource.resx b/BackEnd/Timeline/Services/Timeline/Resource.resx
index 3a233e55..cc293d05 100644
--- a/BackEnd/Timeline/Services/Timeline/Resource.resx
+++ b/BackEnd/Timeline/Services/Timeline/Resource.resx
@@ -117,9 +117,30 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="ExceptionColorInvalid" xml:space="preserve">
+ <value>Color is not valid. {0}</value>
+ </data>
+ <data name="ExceptionDataListEmpty" xml:space="preserve">
+ <value>Data list can't be empty.</value>
+ </data>
+ <data name="ExceptionDataListNull" xml:space="preserve">
+ <value>Data list can't be null.</value>
+ </data>
+ <data name="ExceptionDataListTooLarge" xml:space="preserve">
+ <value>Data list count can't be bigger than 100.</value>
+ </data>
<data name="ExceptionGeneralTimelineNameBadFormat" xml:space="preserve">
<value>This timeline name is neither a valid personal timeline name nor a valid ordinary timeline name. {0}</value>
</data>
+ <data name="ExceptionPostDataImageInvalid" xml:space="preserve">
+ <value>Image validation failed.</value>
+ </data>
+ <data name="ExceptionPostDataNotValidUtf8" xml:space="preserve">
+ <value>It is not a valid utf-8 sequence.</value>
+ </data>
+ <data name="ExceptionPostDataUnsupportedType" xml:space="preserve">
+ <value>Unsupported content type.</value>
+ </data>
<data name="ExceptionTimelineAlreadyExist" xml:space="preserve">
<value>Timeline with given constraints already exist.</value>
</data>
@@ -141,4 +162,28 @@
<data name="LogPersonalTimelineAutoCreate" xml:space="preserve">
<value>A personal timeline for user with username={0} is created automatically.</value>
</data>
+ <data name="LogTimelineAddMember" xml:space="preserve">
+ <value>A member(user id={0}) is added to timeline(id={1}).</value>
+ </data>
+ <data name="LogTimelineCreate" xml:space="preserve">
+ <value>A timeline is created with name={0}, id={1}.</value>
+ </data>
+ <data name="LogTimelineDelete" xml:space="preserve">
+ <value>A timeline(id={0}) is deleted.</value>
+ </data>
+ <data name="LogTimelinePostCreated" xml:space="preserve">
+ <value>A timeline(id={0}) post(id={1}) is created.</value>
+ </data>
+ <data name="LogTimelinePostDeleted" xml:space="preserve">
+ <value>A timeline(id={0}) post(id={1}) is deleted.</value>
+ </data>
+ <data name="LogTimelinePostUpdated" xml:space="preserve">
+ <value>A timeline(id={0}) post(id={1}) is updated.</value>
+ </data>
+ <data name="LogTimelineRemoveMember" xml:space="preserve">
+ <value>A member(user id={0}) is removed from timeline(id={1}).</value>
+ </data>
+ <data name="LogTimelineUpdated" xml:space="preserve">
+ <value>Timeline with id={0} is updated.</value>
+ </data>
</root> \ No newline at end of file
diff --git a/BackEnd/Timeline/Services/Timeline/TimelineAlreadyExistException.cs b/BackEnd/Timeline/Services/Timeline/TimelineAlreadyExistException.cs
deleted file mode 100644
index 11fc4ef8..00000000
--- a/BackEnd/Timeline/Services/Timeline/TimelineAlreadyExistException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-namespace Timeline.Services.Timeline
-{
- /// <summary>
- /// The user requested does not exist.
- /// </summary>
- [Serializable]
- public class TimelineAlreadyExistException : EntityAlreadyExistException
- {
- public TimelineAlreadyExistException() : this(null, null, null) { }
- public TimelineAlreadyExistException(object? entity) : this(entity, null, null) { }
- public TimelineAlreadyExistException(object? entity, Exception? inner) : this(entity, null, inner) { }
- public TimelineAlreadyExistException(object? entity, string? message, Exception? inner)
- : base(EntityNames.Timeline, entity, message ?? Resource.ExceptionTimelineAlreadyExist, inner)
- {
-
- }
-
- protected TimelineAlreadyExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- }
-}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelineNotExistException.cs b/BackEnd/Timeline/Services/Timeline/TimelineNotExistException.cs
deleted file mode 100644
index 2cfbdedf..00000000
--- a/BackEnd/Timeline/Services/Timeline/TimelineNotExistException.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-
-namespace Timeline.Services.Timeline
-{
- [Serializable]
- public class TimelineNotExistException : EntityNotExistException
- {
- public TimelineNotExistException() : this(null, null, null, null) { }
- public TimelineNotExistException(long? id) : this(null, id, null, null) { }
- public TimelineNotExistException(long? id, Exception? inner) : this(null, id, null, inner) { }
- public TimelineNotExistException(string? timelineName) : this(timelineName, null, null, null) { }
- public TimelineNotExistException(string? timelineName, Exception? inner) : this(timelineName, null, null, inner) { }
- public TimelineNotExistException(string? timelineName, long? timelineId, string? message, Exception? inner = null)
- : base(EntityNames.Timeline, message ?? Resource.ExceptionTimelineNotExist, inner)
- {
- TimelineId = timelineId;
- TimelineName = timelineName;
- }
-
- protected TimelineNotExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public string? TimelineName { get; set; }
- public long? TimelineId { get; set; }
- }
-}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostDataNotExistException.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostDataNotExistException.cs
deleted file mode 100644
index 177973a3..00000000
--- a/BackEnd/Timeline/Services/Timeline/TimelinePostDataNotExistException.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System;
-
-namespace Timeline.Services.Timeline
-{
- [Serializable]
- public class TimelinePostDataNotExistException : Exception
- {
- public TimelinePostDataNotExistException() : this(null, null) { }
- public TimelinePostDataNotExistException(string? message) : this(message, null) { }
- public TimelinePostDataNotExistException(string? message, Exception? inner) : base(message, inner) { }
- public TimelinePostDataNotExistException(long timelineId, long postId, long dataIndex, string? message = null, Exception? inner = null) : base(message, inner)
- {
- TimelineId = timelineId;
- PostId = postId;
- DataIndex = dataIndex;
- }
- protected TimelinePostDataNotExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public long TimelineId { get; set; }
- public long PostId { get; set; }
- public long DataIndex { get; set; }
- }
-}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostNotExistException.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostNotExistException.cs
deleted file mode 100644
index 87c190ab..00000000
--- a/BackEnd/Timeline/Services/Timeline/TimelinePostNotExistException.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace Timeline.Services.Timeline
-{
- [Serializable]
- public class TimelinePostNotExistException : EntityNotExistException
- {
- public TimelinePostNotExistException() : this(null, null, false, null, null) { }
- public TimelinePostNotExistException(string? message) : this(message, null) { }
- public TimelinePostNotExistException(string? message, Exception? inner) : this(null, null, false, message, inner) { }
- protected TimelinePostNotExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- public TimelinePostNotExistException(long? timelineId, long? postId, bool isDelete, string? message = null, Exception? inner = null)
- : base(EntityNames.TimelinePost, message ?? MakeMessage(isDelete), inner)
- {
- TimelineId = timelineId;
- PostId = postId;
- IsDelete = isDelete;
- }
-
- private static string MakeMessage(bool isDelete)
- {
- return string.Format(CultureInfo.CurrentCulture, Resource.ExceptionTimelinePostNoExist, isDelete ? Resource.ExceptionTimelinePostNoExistReasonDeleted : Resource.ExceptionTimelinePostNoExistReasonNotCreated);
- }
-
- public long? TimelineId { get; set; }
- public long? PostId { get; set; }
-
- /// <summary>
- /// True if the post is deleted. False if the post does not exist at all.
- /// </summary>
- public bool IsDelete { get; set; }
- }
-}
diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
index 65a01b37..a0961a8d 100644
--- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
+++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs
@@ -38,21 +38,35 @@ namespace Timeline.Services.Timeline
_clock = clock;
}
- private async Task CheckTimelineExistence(long timelineId)
+ private void CheckColor(string color, string paramName)
{
- if (!await _basicTimelineService.CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ if (!_colorValidator.Validate(color, out var message))
+ throw new ArgumentException(string.Format(Resource.ExceptionColorInvalid, message), paramName);
}
- private async Task CheckUserExistence(long userId)
+ private static EntityNotExistException CreatePostNotExistException(long timelineId, long postId, bool deleted)
{
- if (!await _basicUserService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
+ return new EntityNotExistException(EntityTypes.TimelinePost, new Dictionary<string, object>
+ {
+ ["timeline-id"] = timelineId,
+ ["post-id"] = postId,
+ ["deleted"] = deleted
+ });
+ }
+
+ private static EntityNotExistException CreatePostDataNotExistException(long timelineId, long postId, long dataIndex)
+ {
+ return new EntityNotExistException(EntityTypes.TimelinePost, new Dictionary<string, object>
+ {
+ ["timeline-id"] = timelineId,
+ ["post-id"] = postId,
+ ["data-index"] = dataIndex
+ });
}
public async Task<List<TimelinePostEntity>> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
modifiedSince = modifiedSince?.MyToUtc();
@@ -75,18 +89,18 @@ namespace Timeline.Services.Timeline
public async Task<TimelinePostEntity> GetPostAsync(long timelineId, long postId, bool includeDeleted = false)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var post = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync();
if (post is null)
{
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
}
if (!includeDeleted && post.Deleted)
{
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
}
return post;
@@ -94,40 +108,40 @@ namespace Timeline.Services.Timeline
public async Task<ICacheableDataDigest> GetPostDataDigestAsync(long timelineId, long postId, long dataIndex)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var postEntity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).Select(p => new { p.Id, p.Deleted }).SingleOrDefaultAsync();
if (postEntity is null)
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
if (postEntity.Deleted)
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
var dataEntity = await _database.TimelinePostData.Where(d => d.PostId == postEntity.Id && d.Index == dataIndex).SingleOrDefaultAsync();
if (dataEntity is null)
- throw new TimelinePostDataNotExistException(timelineId, postId, dataIndex);
+ throw CreatePostDataNotExistException(timelineId, postId, dataIndex);
return new CacheableDataDigest(dataEntity.DataTag, dataEntity.LastUpdated);
}
public async Task<ByteData> GetPostDataAsync(long timelineId, long postId, long dataIndex)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var postEntity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).Select(p => new { p.Id, p.Deleted }).SingleOrDefaultAsync();
if (postEntity is null)
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
if (postEntity.Deleted)
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
var dataEntity = await _database.TimelinePostData.Where(d => d.PostId == postEntity.Id && d.Index == dataIndex).SingleOrDefaultAsync();
if (dataEntity is null)
- throw new TimelinePostDataNotExistException(timelineId, postId, dataIndex);
+ throw CreatePostDataNotExistException(timelineId, postId, dataIndex);
var data = await _dataManager.GetEntryAndCheck(dataEntity.DataTag, $"Timeline {timelineId}, post {postId}, data {dataIndex} requires this data.");
@@ -139,19 +153,17 @@ namespace Timeline.Services.Timeline
if (request is null)
throw new ArgumentNullException(nameof(request));
- {
- if (!_colorValidator.Validate(request.Color, out var message))
- throw new ArgumentException("Color is not valid.", nameof(request));
- }
+ if (request.Color is not null)
+ CheckColor(request.Color, nameof(request));
if (request.DataList is null)
- throw new ArgumentException("Data list can't be null.", nameof(request));
+ throw new ArgumentException(Resource.ExceptionDataListNull, nameof(request));
if (request.DataList.Count == 0)
- throw new ArgumentException("Data list can't be empty.", nameof(request));
+ throw new ArgumentException(Resource.ExceptionDataListEmpty, nameof(request));
if (request.DataList.Count > 100)
- throw new ArgumentException("Data list count can't be bigger than 100.", nameof(request));
+ throw new ArgumentException(Resource.ExceptionDataListTooLarge, nameof(request));
for (int index = 0; index < request.DataList.Count; index++)
{
@@ -169,7 +181,7 @@ namespace Timeline.Services.Timeline
}
catch (ImageException e)
{
- throw new TimelinePostCreateDataException(index, "Image validation failed.", e);
+ throw new TimelinePostCreateDataException(index, Resource.ExceptionPostDataImageInvalid, e);
}
break;
case MimeTypes.TextPlain:
@@ -180,18 +192,18 @@ namespace Timeline.Services.Timeline
}
catch (DecoderFallbackException e)
{
- throw new TimelinePostCreateDataException(index, "Text is not a valid utf-8 sequence.", e);
+ throw new TimelinePostCreateDataException(index, Resource.ExceptionPostDataNotValidUtf8, e);
}
break;
default:
- throw new TimelinePostCreateDataException(index, "Unsupported content type.");
+ throw new TimelinePostCreateDataException(index, Resource.ExceptionPostDataUnsupportedType);
}
}
request.Time = request.Time?.MyToUtc();
- await CheckTimelineExistence(timelineId);
- await CheckUserExistence(authorId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
+ await _basicUserService.ThrowIfUserNotExist(authorId);
var currentTime = _clock.GetCurrentTime();
var finalTime = request.Time ?? currentTime;
@@ -234,6 +246,7 @@ namespace Timeline.Services.Timeline
await _database.SaveChangesAsync();
await transaction.CommitAsync();
+ _logger.LogInformation(Resource.LogTimelinePostCreated, timelineId, postEntity.Id);
return postEntity;
}
@@ -243,22 +256,20 @@ namespace Timeline.Services.Timeline
if (request is null)
throw new ArgumentNullException(nameof(request));
- {
- if (!_colorValidator.Validate(request.Color, out var message))
- throw new ArgumentException("Color is not valid.", nameof(request));
- }
+ if (request.Color is not null)
+ CheckColor(request.Color, nameof(request));
request.Time = request.Time?.MyToUtc();
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var entity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
if (entity.Deleted)
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
if (request.Time.HasValue)
entity.Time = request.Time.Value;
@@ -269,21 +280,22 @@ namespace Timeline.Services.Timeline
entity.LastUpdated = _clock.GetCurrentTime();
await _database.SaveChangesAsync();
+ _logger.LogInformation(Resource.LogTimelinePostUpdated, timelineId, postId);
return entity;
}
public async Task DeletePostAsync(long timelineId, long postId)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var entity = await _database.TimelinePosts.Where(p => p.TimelineId == timelineId && p.LocalId == postId).SingleOrDefaultAsync();
if (entity == null)
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
if (entity.Deleted)
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
await using var transaction = await _database.Database.BeginTransactionAsync();
@@ -302,6 +314,7 @@ namespace Timeline.Services.Timeline
await _database.SaveChangesAsync();
await transaction.CommitAsync();
+ _logger.LogWarning(Resource.LogTimelinePostDeleted, timelineId, postId);
}
public async Task DeleteAllPostsOfUserAsync(long userId)
@@ -316,7 +329,7 @@ namespace Timeline.Services.Timeline
public async Task<bool> HasPostModifyPermissionAsync(long timelineId, long postId, long modifierId, bool throwOnPostNotExist = false)
{
- await CheckTimelineExistence(timelineId);
+ await _basicTimelineService.ThrowIfTimelineNotExist(timelineId);
var timelineEntity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.OwnerId }).SingleAsync();
@@ -325,14 +338,14 @@ namespace Timeline.Services.Timeline
if (postEntity is null)
{
if (throwOnPostNotExist)
- throw new TimelinePostNotExistException(timelineId, postId, false);
+ throw CreatePostNotExistException(timelineId, postId, false);
else
return true;
}
if (postEntity.Deleted && throwOnPostNotExist)
{
- throw new TimelinePostNotExistException(timelineId, postId, true);
+ throw CreatePostNotExistException(timelineId, postId, true);
}
return timelineEntity.OwnerId == modifierId || postEntity.AuthorId == modifierId;
diff --git a/BackEnd/Timeline/Services/Timeline/TimelineService.cs b/BackEnd/Timeline/Services/Timeline/TimelineService.cs
index cea93272..920fcc74 100644
--- a/BackEnd/Timeline/Services/Timeline/TimelineService.cs
+++ b/BackEnd/Timeline/Services/Timeline/TimelineService.cs
@@ -23,7 +23,6 @@ namespace Timeline.Services.Timeline
private readonly IClock _clock;
private readonly TimelineNameValidator _timelineNameValidator = new TimelineNameValidator();
-
private readonly ColorValidator _colorValidator = new ColorValidator();
public TimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IBasicUserService userService, IClock clock)
@@ -35,8 +34,15 @@ namespace Timeline.Services.Timeline
_clock = clock;
}
+ private static EntityAlreadyExistException CreateTimelineConflictException(string name)
+ {
+ return new EntityAlreadyExistException(EntityTypes.Timeline, new Dictionary<string, object>
+ {
+ ["name"] = name
+ });
+ }
- private void ValidateTimelineName(string name, string paramName)
+ private void CheckTimelineName(string name, string paramName)
{
if (!_timelineNameValidator.Validate(name, out var message))
{
@@ -49,7 +55,7 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == id).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(id);
+ throw CreateTimelineNotExistException(id);
return entity;
}
@@ -60,7 +66,7 @@ namespace Timeline.Services.Timeline
throw new ArgumentNullException(nameof(newProperties));
if (newProperties.Name is not null)
- ValidateTimelineName(newProperties.Name, nameof(newProperties));
+ CheckTimelineName(newProperties.Name, nameof(newProperties));
if (newProperties.Color is not null)
{
@@ -74,7 +80,7 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == id).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(id);
+ throw CreateTimelineNotExistException(id);
var changed = false;
var nameChanged = false;
@@ -84,7 +90,7 @@ namespace Timeline.Services.Timeline
var conflict = await _database.Timelines.AnyAsync(t => t.Name == newProperties.Name);
if (conflict)
- throw new TimelineAlreadyExistException();
+ throw CreateTimelineConflictException(newProperties.Name);
entity.Name = newProperties.Name;
@@ -125,20 +131,19 @@ namespace Timeline.Services.Timeline
}
await _database.SaveChangesAsync();
+ _logger.LogInformation(Resource.LogTimelineUpdated, id);
}
public async Task<bool> AddMemberAsync(long timelineId, long userId)
{
if (!await CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ throw CreateTimelineNotExistException(timelineId);
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
+ await _userService.ThrowIfUserNotExist(userId);
if (await _database.TimelineMembers.AnyAsync(m => m.TimelineId == timelineId && m.UserId == userId))
return false;
-
var entity = new TimelineMemberEntity { UserId = userId, TimelineId = timelineId };
_database.TimelineMembers.Add(entity);
@@ -146,16 +151,17 @@ namespace Timeline.Services.Timeline
timelineEntity.LastModified = _clock.GetCurrentTime();
await _database.SaveChangesAsync();
+ _logger.LogInformation(Resource.LogTimelineAddMember, userId, timelineId);
+
return true;
}
public async Task<bool> RemoveMemberAsync(long timelineId, long userId)
{
if (!await CheckTimelineExistenceAsync(timelineId))
- throw new TimelineNotExistException(timelineId);
+ throw CreateTimelineNotExistException(timelineId);
- if (!await _userService.CheckUserExistenceAsync(userId))
- throw new UserNotExistException(userId);
+ await _userService.ThrowIfUserNotExist(userId);
var entity = await _database.TimelineMembers.SingleOrDefaultAsync(m => m.TimelineId == timelineId && m.UserId == userId);
if (entity is null) return false;
@@ -166,6 +172,8 @@ namespace Timeline.Services.Timeline
timelineEntity.LastModified = _clock.GetCurrentTime();
await _database.SaveChangesAsync();
+ _logger.LogInformation(Resource.LogTimelineRemoveMember, userId, timelineId);
+
return true;
}
@@ -174,7 +182,7 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.OwnerId }).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(timelineId);
+ throw CreateTimelineNotExistException(timelineId);
return entity.OwnerId == userId;
}
@@ -184,7 +192,7 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.Visibility }).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(timelineId);
+ throw CreateTimelineNotExistException(timelineId);
if (entity.Visibility == TimelineVisibility.Public)
return true;
@@ -208,7 +216,7 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.OwnerId }).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(timelineId);
+ throw CreateTimelineNotExistException(timelineId);
if (userId == entity.OwnerId)
return true;
@@ -258,17 +266,18 @@ namespace Timeline.Services.Timeline
if (name == null)
throw new ArgumentNullException(nameof(name));
- ValidateTimelineName(name, nameof(name));
+ CheckTimelineName(name, nameof(name));
var conflict = await _database.Timelines.AnyAsync(t => t.Name == name);
if (conflict)
- throw new TimelineAlreadyExistException();
+ throw CreateTimelineConflictException(name);
var entity = CreateNewTimelineEntity(name, owner);
_database.Timelines.Add(entity);
await _database.SaveChangesAsync();
+ _logger.LogInformation(Resource.LogTimelineCreate, name, entity.Id);
return entity;
}
@@ -278,10 +287,11 @@ namespace Timeline.Services.Timeline
var entity = await _database.Timelines.Where(t => t.Id == id).SingleOrDefaultAsync();
if (entity is null)
- throw new TimelineNotExistException(id);
+ throw CreateTimelineNotExistException(id);
_database.Timelines.Remove(entity);
await _database.SaveChangesAsync();
+ _logger.LogWarning(Resource.LogTimelineDelete, id);
}
}
}
diff --git a/BackEnd/Timeline/Services/Token/IUserTokenManager.cs b/BackEnd/Timeline/Services/Token/IUserTokenManager.cs
index bdc1add3..39009d69 100644
--- a/BackEnd/Timeline/Services/Token/IUserTokenManager.cs
+++ b/BackEnd/Timeline/Services/Token/IUserTokenManager.cs
@@ -16,7 +16,7 @@ namespace Timeline.Services.Token
/// <returns>The created token and the user info.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user with <paramref name="username"/> does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user with <paramref name="username"/> does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown when <paramref name="password"/> is wrong.</exception>
public Task<UserTokenCreateResult> CreateTokenAsync(string username, string password, DateTime? expireAt = null);
diff --git a/BackEnd/Timeline/Services/Token/Resource.Designer.cs b/BackEnd/Timeline/Services/Token/Resource.Designer.cs
index 07b0057f..ac6f3707 100644
--- a/BackEnd/Timeline/Services/Token/Resource.Designer.cs
+++ b/BackEnd/Timeline/Services/Token/Resource.Designer.cs
@@ -61,6 +61,15 @@ namespace Timeline.Services.Token {
}
/// <summary>
+ /// Looks up a localized string similar to Jwt key is not found. Maybe you forget to do the migration..
+ /// </summary>
+ internal static string ExceptionJwtKeyNotExist {
+ get {
+ return ResourceManager.GetString("ExceptionJwtKeyNotExist", resourceCulture);
+ }
+ }
+
+ /// <summary>
/// Looks up a localized string similar to The token didn&apos;t pass verification because {0}..
/// </summary>
internal static string ExceptionJwtUserTokenBadFormat {
diff --git a/BackEnd/Timeline/Services/Token/Resource.resx b/BackEnd/Timeline/Services/Token/Resource.resx
index 7abf2e75..06bf03f6 100644
--- a/BackEnd/Timeline/Services/Token/Resource.resx
+++ b/BackEnd/Timeline/Services/Token/Resource.resx
@@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
+ <data name="ExceptionJwtKeyNotExist" xml:space="preserve">
+ <value>Jwt key is not found. Maybe you forget to do the migration.</value>
+ </data>
<data name="ExceptionJwtUserTokenBadFormat" xml:space="preserve">
<value>The token didn't pass verification because {0}.</value>
</data>
diff --git a/BackEnd/Timeline/Services/Token/UserTokenHandler.cs b/BackEnd/Timeline/Services/Token/UserTokenHandler.cs
index 7b57a06c..c1633f4a 100644
--- a/BackEnd/Timeline/Services/Token/UserTokenHandler.cs
+++ b/BackEnd/Timeline/Services/Token/UserTokenHandler.cs
@@ -29,7 +29,7 @@ namespace Timeline.Services.Token
if (key == null)
{
- throw new InvalidOperationException(Resources.Services.UserTokenService.JwtKeyNotExist);
+ throw new InvalidOperationException(Resource.ExceptionJwtKeyNotExist);
}
_tokenSecurityKey = new SymmetricSecurityKey(key);
diff --git a/BackEnd/Timeline/Services/Token/UserTokenManager.cs b/BackEnd/Timeline/Services/Token/UserTokenManager.cs
index 5aa85a5e..7ccdfe0a 100644
--- a/BackEnd/Timeline/Services/Token/UserTokenManager.cs
+++ b/BackEnd/Timeline/Services/Token/UserTokenManager.cs
@@ -91,7 +91,7 @@ namespace Timeline.Services.Token
return user;
}
- catch (UserNotExistException e)
+ catch (EntityNotExistException e)
{
var exception = new UserTokenUserNotExistException(token, e);
_logger.LogInformation(exception, Resource.LogTokenVerifiedFail);
diff --git a/BackEnd/Timeline/Services/User/Avatar/IUserAvatarService.cs b/BackEnd/Timeline/Services/User/Avatar/IUserAvatarService.cs
index 7ec855aa..92f2429c 100644
--- a/BackEnd/Timeline/Services/User/Avatar/IUserAvatarService.cs
+++ b/BackEnd/Timeline/Services/User/Avatar/IUserAvatarService.cs
@@ -13,7 +13,7 @@ namespace Timeline.Services.User.Avatar
/// </summary>
/// <param name="userId">User id.</param>
/// <returns>The avatar digest.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
Task<ICacheableDataDigest> GetAvatarDigestAsync(long userId);
/// <summary>
@@ -21,7 +21,7 @@ namespace Timeline.Services.User.Avatar
/// </summary>
/// <param name="userId">User id.</param>
/// <returns>The avatar.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
Task<ByteData> GetAvatarAsync(long userId);
/// <summary>
@@ -31,7 +31,7 @@ namespace Timeline.Services.User.Avatar
/// <param name="avatar">The new avatar data.</param>
/// <returns>The digest of the avatar.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="avatar"/> is null.</exception>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
/// <exception cref="ImageException">Thrown if avatar is of bad format.</exception>
Task<ICacheableDataDigest> SetAvatarAsync(long userId, ByteData avatar);
@@ -39,7 +39,7 @@ namespace Timeline.Services.User.Avatar
/// Remove avatar of a user.
/// </summary>
/// <param name="userId">User id.</param>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
Task DeleteAvatarAsync(long userId);
}
}
diff --git a/BackEnd/Timeline/Services/User/BasicUserService.cs b/BackEnd/Timeline/Services/User/BasicUserService.cs
index 1f1b25f5..0ee8dabd 100644
--- a/BackEnd/Timeline/Services/User/BasicUserService.cs
+++ b/BackEnd/Timeline/Services/User/BasicUserService.cs
@@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore;
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
@@ -18,6 +19,18 @@ namespace Timeline.Services.User
_database = database;
}
+ protected static EntityNotExistException CreateUserNotExistException(string username)
+ {
+ return new EntityNotExistException(EntityTypes.User,
+ new Dictionary<string, object> { ["username"] = username });
+ }
+
+ protected static EntityNotExistException CreateUserNotExistException(long id)
+ {
+ return new EntityNotExistException(EntityTypes.User,
+ new Dictionary<string, object> { ["id"] = id });
+ }
+
public async Task<bool> CheckUserExistenceAsync(long id)
{
return await _database.Users.AnyAsync(u => u.Id == id);
@@ -34,7 +47,7 @@ namespace Timeline.Services.User
var entity = await _database.Users.Where(user => user.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
if (entity == null)
- throw new UserNotExistException(username);
+ throw CreateUserNotExistException(username);
return entity.Id;
}
@@ -44,20 +57,9 @@ namespace Timeline.Services.User
var entity = await _database.Users.Where(u => u.Id == userId).Select(u => new { u.UsernameChangeTime }).SingleOrDefaultAsync();
if (entity is null)
- throw new UserNotExistException(userId);
+ throw CreateUserNotExistException(userId);
return entity.UsernameChangeTime;
}
}
-
- public static class BasicUserServiceExtensions
- {
- public static async Task ThrowIfUserNotExist(this IBasicUserService service, long userId)
- {
- if (!await service.CheckUserExistenceAsync(userId))
- {
- throw new UserNotExistException(userId);
- }
- }
- }
}
diff --git a/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs b/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs
new file mode 100644
index 00000000..8a05f452
--- /dev/null
+++ b/BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs
@@ -0,0 +1,17 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace Timeline.Services.User
+{
+ public static class BasicUserServiceExtensions
+ {
+ public static async Task ThrowIfUserNotExist(this IBasicUserService service, long userId)
+ {
+ if (!await service.CheckUserExistenceAsync(userId))
+ {
+ throw new EntityNotExistException(EntityTypes.User,
+ new Dictionary<string, object> { ["id"] = userId });
+ }
+ }
+ }
+}
diff --git a/BackEnd/Timeline/Services/User/IBasicUserService.cs b/BackEnd/Timeline/Services/User/IBasicUserService.cs
index 0e30d733..0ae3fdff 100644
--- a/BackEnd/Timeline/Services/User/IBasicUserService.cs
+++ b/BackEnd/Timeline/Services/User/IBasicUserService.cs
@@ -22,7 +22,7 @@ namespace Timeline.Services.User
/// <returns>The id of the user.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user with given username does not exist.</exception>
Task<long> GetUserIdByUsernameAsync(string username);
/// <summary>
@@ -30,7 +30,7 @@ namespace Timeline.Services.User
/// </summary>
/// <param name="userId">User id.</param>
/// <returns>The time.</returns>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
Task<DateTime> GetUsernameLastModifiedTimeAsync(long userId);
}
}
diff --git a/BackEnd/Timeline/Services/User/IUserPermissionService.cs b/BackEnd/Timeline/Services/User/IUserPermissionService.cs
index 7ff1275b..985a67f5 100644
--- a/BackEnd/Timeline/Services/User/IUserPermissionService.cs
+++ b/BackEnd/Timeline/Services/User/IUserPermissionService.cs
@@ -10,7 +10,7 @@ namespace Timeline.Services.User
/// <param name="userId">The id of the user.</param>
/// <param name="checkUserExistence">Whether check the user's existence.</param>
/// <returns>The permission list.</returns>
- /// <exception cref="UserNotExistException">Thrown when <paramref name="checkUserExistence"/> is true and user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when <paramref name="checkUserExistence"/> is true and user does not exist.</exception>
Task<UserPermissions> GetPermissionsOfUserAsync(long userId, bool checkUserExistence = true);
/// <summary>
@@ -18,7 +18,7 @@ namespace Timeline.Services.User
/// </summary>
/// <param name="userId">The id of the user.</param>
/// <param name="permission">The new permission.</param>
- /// <exception cref="UserNotExistException">Thrown when user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user does not exist.</exception>
/// <exception cref="InvalidOperationOnRootUserException">Thrown when change root user's permission.</exception>
Task AddPermissionToUserAsync(long userId, UserPermission permission);
@@ -28,7 +28,7 @@ namespace Timeline.Services.User
/// <param name="userId">The id of the user.</param>
/// <param name="permission">The permission.</param>
/// <param name="checkUserExistence">Whether check the user's existence.</param>
- /// <exception cref="UserNotExistException">Thrown when <paramref name="checkUserExistence"/> is true and user does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when <paramref name="checkUserExistence"/> is true and user does not exist.</exception>
/// <exception cref="InvalidOperationOnRootUserException">Thrown when change root user's permission.</exception>
Task RemovePermissionFromUserAsync(long userId, UserPermission permission, bool checkUserExistence = true);
}
diff --git a/BackEnd/Timeline/Services/User/IUserService.cs b/BackEnd/Timeline/Services/User/IUserService.cs
index 06155c55..745bd524 100644
--- a/BackEnd/Timeline/Services/User/IUserService.cs
+++ b/BackEnd/Timeline/Services/User/IUserService.cs
@@ -12,7 +12,7 @@ namespace Timeline.Services.User
/// </summary>
/// <param name="id">The id of the user.</param>
/// <returns>The user info.</returns>
- /// <exception cref="UserNotExistException">Thrown when the user with given id does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user with given id does not exist.</exception>
Task<UserEntity> GetUserAsync(long id);
/// <summary>
@@ -38,7 +38,7 @@ namespace Timeline.Services.User
/// <param name="param">The new information.</param>
/// <returns>The new user info.</returns>
/// <exception cref="ArgumentException">Thrown when some fields in <paramref name="param"/> is bad.</exception>
- /// <exception cref="UserNotExistException">Thrown when user with given id does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when user with given id does not exist.</exception>
/// <remarks>
/// Version will increase if password is changed.
/// </remarks>
@@ -52,7 +52,7 @@ namespace Timeline.Services.User
/// <returns>User id.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> or <paramref name="password"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format or <paramref name="password"/> is empty.</exception>
- /// <exception cref="UserNotExistException">Thrown when the user with given username does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown when the user with given username does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown when password is wrong.</exception>
Task<long> VerifyCredential(string username, string password);
@@ -64,7 +64,7 @@ namespace Timeline.Services.User
/// <param name="newPassword">New password.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="oldPassword"/> or <paramref name="newPassword"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown if <paramref name="oldPassword"/> or <paramref name="newPassword"/> is empty.</exception>
- /// <exception cref="UserNotExistException">Thrown if the user with given username does not exist.</exception>
+ /// <exception cref="EntityNotExistException">Thrown if the user with given username does not exist.</exception>
/// <exception cref="BadPasswordException">Thrown if the old password is wrong.</exception>
Task ChangePassword(long id, string oldPassword, string newPassword);
}
diff --git a/BackEnd/Timeline/Services/User/UserAlreadyExistException.cs b/BackEnd/Timeline/Services/User/UserAlreadyExistException.cs
deleted file mode 100644
index e257af74..00000000
--- a/BackEnd/Timeline/Services/User/UserAlreadyExistException.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using System;
-
-namespace Timeline.Services.User
-{
- /// <summary>
- /// The user requested does not exist.
- /// </summary>
- [Serializable]
- public class UserAlreadyExistException : EntityAlreadyExistException
- {
- public UserAlreadyExistException() : this(null, null, null) { }
- public UserAlreadyExistException(object? entity) : this(entity, null, null) { }
- public UserAlreadyExistException(object? entity, Exception? inner) : this(entity, null, inner) { }
- public UserAlreadyExistException(object? entity, string? message, Exception? inner)
- : base(EntityNames.User, entity, message ?? Resource.ExceptionUserAlreadyExist, inner)
- {
-
- }
-
- protected UserAlreadyExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
- }
-}
diff --git a/BackEnd/Timeline/Services/User/UserNotExistException.cs b/BackEnd/Timeline/Services/User/UserNotExistException.cs
deleted file mode 100644
index bc5d8d9e..00000000
--- a/BackEnd/Timeline/Services/User/UserNotExistException.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-
-namespace Timeline.Services.User
-{
- /// <summary>
- /// The user requested does not exist.
- /// </summary>
- [Serializable]
- public class UserNotExistException : EntityNotExistException
- {
- public UserNotExistException() : this(null, null, null, null) { }
- public UserNotExistException(string? username) : this(username, null, null, null) { }
- public UserNotExistException(string? username, Exception? inner) : this(username, null, null, inner) { }
- public UserNotExistException(long id) : this(null, id, null, null) { }
- public UserNotExistException(long id, Exception? inner) : this(null, id, null, inner) { }
- public UserNotExistException(string? username, long? id, string? message, Exception? inner)
- : base(EntityNames.User, message ?? Resource.ExceptionUserNotExist, inner)
- {
- Username = username;
- Id = id;
- }
-
- protected UserNotExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- /// <summary>
- /// The username of the user that does not exist.
- /// </summary>
- public string? Username { get; set; }
-
- /// <summary>
- /// The id of the user that does not exist.
- /// </summary>
- public long? Id { get; set; }
- }
-}
diff --git a/BackEnd/Timeline/Services/User/UserPermissionService.cs b/BackEnd/Timeline/Services/User/UserPermissionService.cs
index f9911c7f..f6f11c61 100644
--- a/BackEnd/Timeline/Services/User/UserPermissionService.cs
+++ b/BackEnd/Timeline/Services/User/UserPermissionService.cs
@@ -8,21 +8,19 @@ namespace Timeline.Services.User
public class UserPermissionService : IUserPermissionService
{
private readonly DatabaseContext _database;
+ private readonly IBasicUserService _basicUserService;
- public UserPermissionService(DatabaseContext database)
+ public UserPermissionService(DatabaseContext database, IBasicUserService basicUserService)
{
_database = database;
+ _basicUserService = basicUserService;
}
private async Task CheckUserExistence(long userId, bool checkUserExistence)
{
if (checkUserExistence)
{
- var existence = await _database.Users.AnyAsync(u => u.Id == userId);
- if (!existence)
- {
- throw new UserNotExistException(userId);
- }
+ await _basicUserService.ThrowIfUserNotExist(userId);
}
}
diff --git a/BackEnd/Timeline/Services/User/UserService.cs b/BackEnd/Timeline/Services/User/UserService.cs
index 443afb90..a47bc860 100644
--- a/BackEnd/Timeline/Services/User/UserService.cs
+++ b/BackEnd/Timeline/Services/User/UserService.cs
@@ -54,9 +54,10 @@ namespace Timeline.Services.User
}
}
- private static void ThrowUsernameConflict(object? user)
+ private static EntityAlreadyExistException CreateUsernameConflictException(string username)
{
- throw new UserAlreadyExistException(user);
+ throw new EntityAlreadyExistException(EntityTypes.User,
+ new Dictionary<string, object> { ["username"] = username });
}
public async Task<UserEntity> GetUserAsync(long id)
@@ -64,7 +65,7 @@ namespace Timeline.Services.User
var user = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync();
if (user is null)
- throw new UserNotExistException(id);
+ throw CreateUserNotExistException(id);
return user;
}
@@ -89,7 +90,7 @@ namespace Timeline.Services.User
var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == param.Username);
if (conflict)
- ThrowUsernameConflict(null);
+ throw CreateUsernameConflictException(param.Username);
var newEntity = new UserEntity
{
@@ -120,8 +121,8 @@ namespace Timeline.Services.User
}
var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync();
- if (entity == null)
- throw new UserNotExistException(id);
+ if (entity is null)
+ throw CreateUserNotExistException(id);
if (param is not null)
{
@@ -133,7 +134,7 @@ namespace Timeline.Services.User
{
var conflict = await _databaseContext.Users.AnyAsync(u => u.Username == username);
if (conflict)
- ThrowUsernameConflict(null);
+ throw CreateUsernameConflictException(username);
entity.Username = username;
entity.UsernameChangeTime = now;
@@ -180,7 +181,7 @@ namespace Timeline.Services.User
if (entity is null)
{
_logger.LogInformation(Resource.LogVerifyCredentialsUsernameBad, username);
- throw new UserNotExistException(username);
+ throw CreateUserNotExistException(username);
}
if (!_passwordService.VerifyPassword(entity.Password, password))
@@ -204,7 +205,7 @@ namespace Timeline.Services.User
var entity = await _databaseContext.Users.Where(u => u.Id == id).SingleOrDefaultAsync();
if (entity is null)
- throw new UserNotExistException(id);
+ throw CreateUserNotExistException(id);
if (!_passwordService.VerifyPassword(entity.Password, oldPassword))
throw new BadPasswordException(oldPassword);