aboutsummaryrefslogtreecommitdiff
path: root/Timeline/Services
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-01-30 20:26:52 +0800
committercrupest <crupest@outlook.com>2020-01-30 20:26:52 +0800
commit79ab2b304d93b1029515bd3f954db4e5a73f4168 (patch)
tree538ceea06640f501d2a950cac813c10561036e4d /Timeline/Services
parentdd0097af5c4ccbe25a1faca2286d729c93fd4116 (diff)
downloadtimeline-79ab2b304d93b1029515bd3f954db4e5a73f4168.tar.gz
timeline-79ab2b304d93b1029515bd3f954db4e5a73f4168.tar.bz2
timeline-79ab2b304d93b1029515bd3f954db4e5a73f4168.zip
...
Diffstat (limited to 'Timeline/Services')
-rw-r--r--Timeline/Services/ConflictException.cs (renamed from Timeline/Services/ConfictException.cs)10
-rw-r--r--Timeline/Services/DatabaseExtensions.cs36
-rw-r--r--Timeline/Services/TimelineAlreadyExistException.cs17
-rw-r--r--Timeline/Services/TimelineMemberOperationUserException.cs37
-rw-r--r--Timeline/Services/TimelineNameBadFormatException.cs21
-rw-r--r--Timeline/Services/TimelineService.cs363
-rw-r--r--Timeline/Services/User.cs33
-rw-r--r--Timeline/Services/UserAvatarService.cs48
-rw-r--r--Timeline/Services/UserRoleConvert.cs1
-rw-r--r--Timeline/Services/UserService.cs36
-rw-r--r--Timeline/Services/UserTokenService.cs1
11 files changed, 166 insertions, 437 deletions
diff --git a/Timeline/Services/ConfictException.cs b/Timeline/Services/ConflictException.cs
index dcd77366..6ede183a 100644
--- a/Timeline/Services/ConfictException.cs
+++ b/Timeline/Services/ConflictException.cs
@@ -9,12 +9,12 @@ namespace Timeline.Services
/// For example a username already exists and conflicts with the given username.
/// </remarks>
[Serializable]
- public class ConfictException : Exception
+ public class ConflictException : Exception
{
- public ConfictException() : base(Resources.Services.Exception.ConfictException) { }
- public ConfictException(string message) : base(message) { }
- public ConfictException(string message, Exception inner) : base(message, inner) { }
- protected ConfictException(
+ public ConflictException() : base(Resources.Services.Exception.ConflictException) { }
+ public ConflictException(string message) : base(message) { }
+ public ConflictException(string message, Exception inner) : base(message, inner) { }
+ protected ConflictException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
diff --git a/Timeline/Services/DatabaseExtensions.cs b/Timeline/Services/DatabaseExtensions.cs
deleted file mode 100644
index e77dd01a..00000000
--- a/Timeline/Services/DatabaseExtensions.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using Microsoft.EntityFrameworkCore;
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Timeline.Entities;
-using Timeline.Models.Validation;
-
-namespace Timeline.Services
-{
- internal static class DatabaseExtensions
- {
- private static readonly UsernameValidator usernameValidator = new UsernameValidator();
-
- /// <summary>
- /// Check the existence and get the id of the user.
- /// </summary>
- /// <param name="username">The username of the user.</param>
- /// <returns>The user id.</returns>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception>
- /// <exception cref="UsernameBadFormatException">Thrown if <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown if user does not exist.</exception>
- internal static async Task<long> CheckAndGetUser(DbSet<UserEntity> userDbSet, string? username)
- {
- if (username == null)
- throw new ArgumentNullException(nameof(username));
- var (result, message) = usernameValidator.Validate(username);
- if (!result)
- throw new UsernameBadFormatException(username, message);
-
- var userId = await userDbSet.Where(u => u.Username == username).Select(u => u.Id).SingleOrDefaultAsync();
- if (userId == 0)
- throw new UserNotExistException(username);
- return userId;
- }
- }
-}
diff --git a/Timeline/Services/TimelineAlreadyExistException.cs b/Timeline/Services/TimelineAlreadyExistException.cs
deleted file mode 100644
index c2dea1f9..00000000
--- a/Timeline/Services/TimelineAlreadyExistException.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System;
-
-namespace Timeline.Services
-{
- [Serializable]
- public class TimelineAlreadyExistException : Exception
- {
- public TimelineAlreadyExistException() : base(Resources.Services.Exception.TimelineAlreadyExistException) { }
- public TimelineAlreadyExistException(string name) : base(Resources.Services.Exception.TimelineAlreadyExistException) { Name = name; }
- public TimelineAlreadyExistException(string name, Exception inner) : base(Resources.Services.Exception.TimelineAlreadyExistException, inner) { Name = name; }
- protected TimelineAlreadyExistException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public string? Name { get; set; }
- }
-}
diff --git a/Timeline/Services/TimelineMemberOperationUserException.cs b/Timeline/Services/TimelineMemberOperationUserException.cs
deleted file mode 100644
index 543ee160..00000000
--- a/Timeline/Services/TimelineMemberOperationUserException.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System;
-using System.Globalization;
-
-namespace Timeline.Services
-{
- [Serializable]
- public class TimelineMemberOperationUserException : Exception
- {
- public enum MemberOperation
- {
- Add,
- Remove
- }
-
- public TimelineMemberOperationUserException() : base(Resources.Services.Exception.TimelineMemberOperationException) { }
- public TimelineMemberOperationUserException(string message) : base(message) { }
- public TimelineMemberOperationUserException(string message, Exception inner) : base(message, inner) { }
- protected TimelineMemberOperationUserException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public TimelineMemberOperationUserException(int index, MemberOperation operation, string username, Exception inner)
- : base(MakeMessage(operation, index), inner) { Operation = operation; Index = index; Username = username; }
-
- private static string MakeMessage(MemberOperation operation, int index) => string.Format(CultureInfo.CurrentCulture,
- Resources.Services.Exception.TimelineMemberOperationExceptionDetail, operation, index);
-
- public MemberOperation? Operation { get; set; }
-
- /// <summary>
- /// The index of the member on which the operation failed.
- /// </summary>
- public int? Index { get; set; }
-
- public string? Username { get; set; }
- }
-}
diff --git a/Timeline/Services/TimelineNameBadFormatException.cs b/Timeline/Services/TimelineNameBadFormatException.cs
deleted file mode 100644
index 5120a175..00000000
--- a/Timeline/Services/TimelineNameBadFormatException.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System;
-
-namespace Timeline.Services
-{
- [Serializable]
- public class TimelineNameBadFormatException : Exception
- {
- public TimelineNameBadFormatException()
- : base(Resources.Services.Exception.TimelineNameBadFormatException) { }
- public TimelineNameBadFormatException(string name)
- : base(Resources.Services.Exception.TimelineNameBadFormatException) { Name = name; }
- public TimelineNameBadFormatException(string name, Exception inner)
- : base(Resources.Services.Exception.TimelineNameBadFormatException, inner) { Name = name; }
-
- protected TimelineNameBadFormatException(
- System.Runtime.Serialization.SerializationInfo info,
- System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
-
- public string? Name { get; set; }
- }
-}
diff --git a/Timeline/Services/TimelineService.cs b/Timeline/Services/TimelineService.cs
index f43d2de5..89936aa2 100644
--- a/Timeline/Services/TimelineService.cs
+++ b/Timeline/Services/TimelineService.cs
@@ -1,13 +1,15 @@
-using Microsoft.EntityFrameworkCore;
+using AutoMapper;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
-using Timeline.Models;
using Timeline.Models.Http;
using Timeline.Models.Validation;
+using static Timeline.Resources.Services.TimelineService;
namespace Timeline.Services
{
@@ -28,12 +30,7 @@ namespace Timeline.Services
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
/// <returns>A list of all posts.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
@@ -46,26 +43,20 @@ namespace Timeline.Services
/// Create a new post in timeline.
/// </summary>
/// <param name="name">Username or the timeline name. See remarks of <ssee cref="IBaseTimelineService"/>.</param>
- /// <param name="author">The author's username.</param>
+ /// <param name="authorId">The author's id.</param>
/// <param name="content">The content.</param>
/// <param name="time">The time of the post. If null, then use current time.</param>
/// <returns>The info of the created post.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="author"/> or <paramref name="content"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="content"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
/// For personal timeline, it means the user of that username does not exist
/// and the inner exception should be a <see cref="UserNotExistException"/>.
/// </exception>
- /// <exception cref="UsernameBadFormatException">Thrown if <paramref name="author"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown if <paramref name="author"/> does not exist.</exception>
- Task<TimelinePostCreateResponse> CreatePost(string name, string author, string content, DateTime? time);
+ /// <exception cref="UserNotExistException">Thrown if user with <paramref name="authorId"/> does not exist.</exception>
+ Task<TimelinePostInfo> CreatePost(string name, long authorId, string content, DateTime? time);
/// <summary>
/// Delete a post
@@ -73,12 +64,7 @@ namespace Timeline.Services
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
/// <param name="id">The id of the post to delete.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="username"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
@@ -100,19 +86,14 @@ namespace Timeline.Services
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
/// <param name="newProperties">The new properties. Null member means not to change.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="newProperties"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
/// For personal timeline, it means the user of that username does not exist
/// and the inner exception should be a <see cref="UserNotExistException"/>.
/// </exception>
- Task ChangeProperty(string name, TimelinePropertyChangeRequest newProperties);
+ Task ChangeProperty(string name, TimelinePatchRequest newProperties);
/// <summary>
/// Remove members to a timeline.
@@ -121,24 +102,16 @@ namespace Timeline.Services
/// <param name="add">A list of usernames of members to add. May be null.</param>
/// <param name="remove">A list of usernames of members to remove. May be null.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
+ /// <exception cref="ArgumentException">Thrown when names in <paramref name="add"/> or <paramref name="remove"/> is not a valid username.</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
/// For personal timeline, it means the user of that username does not exist
/// and the inner exception should be a <see cref="UserNotExistException"/>.
/// </exception>
- /// <exception cref="TimelineMemberOperationUserException">
- /// Thrown when an exception occurs on the user list.
- /// The inner exception is <see cref="UsernameBadFormatException"/>
- /// when one of the username is invalid.
- /// The inner exception is <see cref="UserNotExistException"/>
- /// when one of the user to change does not exist.
+ /// <exception cref="UserNotExistException">
+ /// Thrown when one of the user to change does not exist.
/// </exception>
/// <remarks>
/// Operating on a username that is of bad format or does not exist always throws.
@@ -153,42 +126,30 @@ namespace Timeline.Services
/// Verify whether a visitor has the permission to read a timeline.
/// </summary>
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
- /// <param name="username">The user to check on. Null means visitor without account.</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="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
/// For personal timeline, it means the user of that username does not exist
/// and the inner exception should be a <see cref="UserNotExistException"/>.
/// </exception>
- /// <exception cref="UsernameBadFormatException">
- /// Thrown when <paramref name="username"/> is of bad format.
- /// </exception>
- /// <exception cref="UserNotExistException">
- /// Thrown when <paramref name="username"/> does not exist.
- /// </exception>
- Task<bool> HasReadPermission(string name, string? username);
+ /// <remarks>
+ /// This method does not check whether visitor is administrator.
+ /// Return false if user with visitor id does not exist.
+ /// </remarks>
+ Task<bool> HasReadPermission(string name, long? visitorId);
/// <summary>
/// Verify whether a user has the permission to modify a post.
/// </summary>
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
- /// <param name="username">The user to check on.</param>
+ /// <param name="modifierId">The id of the user to check on.</param>
/// <returns>True if can modify, false if can't modify.</returns>
- /// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="username"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
@@ -198,47 +159,32 @@ namespace Timeline.Services
/// <exception cref="TimelinePostNotExistException">
/// Thrown when the post with given id does not exist or is deleted already.
/// </exception>
- /// <exception cref="UsernameBadFormatException">
- /// Thrown when <paramref name="username"/> is of bad format.
- /// </exception>
- /// <exception cref="UserNotExistException">
- /// Thrown when <paramref name="username"/> does not exist.
- /// </exception>
/// <remarks>
/// This method does not check whether the user is administrator.
/// It only checks whether he is the author of the post or the owner of the timeline.
+ /// Return false when user with modifier id does not exist.
/// </remarks>
- Task<bool> HasPostModifyPermission(string name, long id, string username);
+ Task<bool> HasPostModifyPermission(string name, long id, long modifierId);
/// <summary>
/// Verify whether a user is member of a timeline.
/// </summary>
/// <param name="name">Username or the timeline name. See remarks of <see cref="IBaseTimelineService"/>.</param>
- /// <param name="username">The user to check on.</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="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="username"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
/// For personal timeline, it means the user of that username does not exist
/// and the inner exception should be a <see cref="UserNotExistException"/>.
/// </exception>
- /// <exception cref="UsernameBadFormatException">
- /// Thrown when <paramref name="username"/> is not a valid username.
- /// </exception>
- /// <exception cref="UserNotExistException">
- /// Thrown when user <paramref name="username"/> does not exist.
- /// </exception>
/// <remarks>
/// Timeline owner is also considered as a member.
+ /// Return false when user with user id does not exist.
/// </remarks>
- Task<bool> IsMemberOf(string name, string username);
+ Task<bool> IsMemberOf(string name, long userId);
}
/// <summary>
@@ -252,7 +198,7 @@ namespace Timeline.Services
/// <param name="name">The name of the timeline.</param>
/// <returns>The timeline info.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
+ /// <exception cref="ArgumentException">
/// Thrown when timeline name is invalid. Currently it means it is an empty string.
/// </exception>
/// <exception cref="TimelineNotExistException">
@@ -264,20 +210,12 @@ namespace Timeline.Services
/// Create a timeline.
/// </summary>
/// <param name="name">The name of the timeline.</param>
- /// <param name="owner">The owner of the timeline.</param>
+ /// <param name="owner">The id of owner of the timeline.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> or <paramref name="owner"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is invalid. Currently it means it is an empty string.
- /// </exception>
- /// <exception cref="TimelineAlreadyExistException">
- /// Thrown when the timeline already exists.
- /// </exception>
- /// <exception cref="UsernameBadFormatException">
- /// Thrown when the username of the owner is not valid.
- /// </exception>
- /// <exception cref="UserNotExistException">
- /// Thrown when the owner user does not exist.</exception>
- Task CreateTimeline(string name, string owner);
+ /// <exception cref="ArgumentException">Thrown when timeline name is invalid. Currently it means it is an empty string.</exception>
+ /// <exception cref="ConflictException">Thrown when the timeline already exists.</exception>
+ /// <exception cref="UserNotExistException">Thrown when the owner user does not exist.</exception>
+ Task CreateTimeline(string name, long owner);
}
public interface IPersonalTimelineService : IBaseTimelineService
@@ -290,8 +228,8 @@ namespace Timeline.Services
/// <exception cref="ArgumentNullException">
/// Thrown when <paramref name="username"/> is null.
/// </exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when <paramref name="username"/> is of bad format. Inner exception MUST be <see cref="UsernameBadFormatException"/>.
+ /// <exception cref="ArgumentException">
+ /// Thrown when <paramref name="username"/> is of bad format.
/// </exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when the user does not exist. Inner exception MUST be <see cref="UserNotExistException"/>.
@@ -301,10 +239,12 @@ namespace Timeline.Services
public abstract class BaseTimelineService : IBaseTimelineService
{
- protected BaseTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IClock clock)
+ protected BaseTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IUserService userService, IMapper mapper, IClock clock)
{
Clock = clock;
Database = database;
+ UserService = userService;
+ Mapper = mapper;
}
protected IClock Clock { get; }
@@ -313,6 +253,10 @@ namespace Timeline.Services
protected DatabaseContext Database { get; }
+ protected IUserService UserService { get; }
+
+ protected IMapper Mapper { get; }
+
/// <summary>
/// Find the timeline id by the name.
/// For details, see remarks.
@@ -320,12 +264,7 @@ namespace Timeline.Services
/// <param name="name">The username or the timeline name. See remarks.</param>
/// <returns>The id of the timeline entity.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="name"/> is null.</exception>
- /// <exception cref="TimelineNameBadFormatException">
- /// Thrown when timeline name is of bad format.
- /// For normal timeline, it means name is an empty string.
- /// For personal timeline, it means the username is of bad format,
- /// the inner exception should be a <see cref="UsernameBadFormatException"/>.
- /// </exception>
+ /// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is illegal. It is not a valid timeline name (for normal timeline service) or a valid username (for personal timeline service).</exception>
/// <exception cref="TimelineNotExistException">
/// Thrown when timeline does not exist.
/// For normal timeline, it means the name does not exist.
@@ -347,66 +286,60 @@ namespace Timeline.Services
if (name == null)
throw new ArgumentNullException(nameof(name));
+
var timelineId = await FindTimelineId(name);
var postEntities = await Database.TimelinePosts.OrderBy(p => p.Time).Where(p => p.TimelineId == timelineId && p.Content != null).ToListAsync();
+
var posts = new List<TimelinePostInfo>();
foreach (var entity in postEntities)
{
- posts.Add(new TimelinePostInfo
+ if (entity.Content != null) // otherwise it is deleted
{
- Id = entity.Id,
- Content = entity.Content,
- Author = (await Database.Users.Where(u => u.Id == entity.AuthorId).Select(u => new { u.Username }).SingleAsync()).Name,
- Time = entity.Time
- });
+ var author = Mapper.Map<UserInfo>(UserService.GetUserById(entity.AuthorId));
+ posts.Add(new TimelinePostInfo
+ {
+ Id = entity.Id,
+ Content = entity.Content,
+ Author = author,
+ Time = entity.Time,
+ LastUpdated = entity.LastUpdated
+ });
+ }
}
return posts;
}
- public async Task<TimelinePostCreateResponse> CreatePost(string name, string author, string content, DateTime? time)
+ public async Task<TimelinePostInfo> CreatePost(string name, long authorId, string content, DateTime? time)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
- if (author == null)
- throw new ArgumentNullException(nameof(author));
if (content == null)
throw new ArgumentNullException(nameof(content));
- {
- var (result, message) = UsernameValidator.Validate(author);
- if (!result)
- {
- throw new UsernameBadFormatException(author, message);
- }
- }
-
var timelineId = await FindTimelineId(name);
-
- var authorEntity = Database.Users.Where(u => u.Username == author).Select(u => new { u.Id }).SingleOrDefault();
- if (authorEntity == null)
- {
- throw new UserNotExistException(author);
- }
- var authorId = authorEntity.Id;
+ var author = Mapper.Map<UserInfo>(await UserService.GetUserById(authorId));
var currentTime = Clock.GetCurrentTime();
+ var finalTime = time ?? currentTime;
var postEntity = new TimelinePostEntity
{
Content = content,
AuthorId = authorId,
TimelineId = timelineId,
- Time = time ?? currentTime,
+ Time = finalTime,
LastUpdated = currentTime
};
-
Database.TimelinePosts.Add(postEntity);
await Database.SaveChangesAsync();
- return new TimelinePostCreateResponse
+ return new TimelinePostInfo
{
Id = postEntity.Id,
- Time = postEntity.Time
+ Content = content,
+ Author = author,
+ Time = finalTime,
+ LastUpdated = currentTime
};
}
@@ -426,7 +359,7 @@ namespace Timeline.Services
await Database.SaveChangesAsync();
}
- public async Task ChangeProperty(string name, TimelinePropertyChangeRequest newProperties)
+ public async Task ChangeProperty(string name, TimelinePatchRequest newProperties)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
@@ -455,27 +388,23 @@ namespace Timeline.Services
if (name == null)
throw new ArgumentNullException(nameof(name));
- // remove duplication and check the format of each username.
- // Return a username->index map.
- Dictionary<string, int>? RemoveDuplicateAndCheckFormat(IList<string>? list, TimelineMemberOperationUserException.MemberOperation operation)
+ List<string>? RemoveDuplicateAndCheckFormat(IList<string>? list, string paramName)
{
if (list != null)
{
- Dictionary<string, int> result = new Dictionary<string, int>();
+ List<string> result = new List<string>();
var count = list.Count;
for (var index = 0; index < count; index++)
{
var username = list[index];
- if (result.ContainsKey(username))
+ if (result.Contains(username))
{
continue;
}
var (validationResult, message) = UsernameValidator.Validate(username);
if (!validationResult)
- throw new TimelineMemberOperationUserException(
- index, operation, username,
- new UsernameBadFormatException(username, message));
- result.Add(username, index);
+ throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ExceptionChangeMemberUsernameBadFormat, index), nameof(paramName));
+ result.Add(username);
}
return result;
}
@@ -484,13 +413,13 @@ namespace Timeline.Services
return null;
}
}
- var simplifiedAdd = RemoveDuplicateAndCheckFormat(add, TimelineMemberOperationUserException.MemberOperation.Add);
- var simplifiedRemove = RemoveDuplicateAndCheckFormat(remove, TimelineMemberOperationUserException.MemberOperation.Remove);
+ var simplifiedAdd = RemoveDuplicateAndCheckFormat(add, nameof(add));
+ var simplifiedRemove = RemoveDuplicateAndCheckFormat(remove, nameof(remove));
// remove those both in add and remove
if (simplifiedAdd != null && simplifiedRemove != null)
{
- var usersToClean = simplifiedRemove.Keys.Where(u => simplifiedAdd.ContainsKey(u));
+ var usersToClean = simplifiedRemove.Where(u => simplifiedAdd.Contains(u)).ToList();
foreach (var u in usersToClean)
{
simplifiedAdd.Remove(u);
@@ -500,26 +429,20 @@ namespace Timeline.Services
var timelineId = await FindTimelineId(name);
- async Task<List<long>?> CheckExistenceAndGetId(Dictionary<string, int>? map, TimelineMemberOperationUserException.MemberOperation operation)
+ async Task<List<long>?> CheckExistenceAndGetId(List<string>? list)
{
- if (map == null)
+ if (list == null)
return null;
List<long> result = new List<long>();
- foreach (var (username, index) in map)
+ foreach (var username in list)
{
- var user = await Database.Users.Where(u => u.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
- if (user == null)
- {
- throw new TimelineMemberOperationUserException(index, operation, username,
- new UserNotExistException(username));
- }
- result.Add(user.Id);
+ result.Add(await UserService.GetUserIdByUsername(username));
}
return result;
}
- var userIdsAdd = await CheckExistenceAndGetId(simplifiedAdd, TimelineMemberOperationUserException.MemberOperation.Add);
- var userIdsRemove = await CheckExistenceAndGetId(simplifiedRemove, TimelineMemberOperationUserException.MemberOperation.Remove);
+ var userIdsAdd = await CheckExistenceAndGetId(simplifiedAdd);
+ var userIdsRemove = await CheckExistenceAndGetId(simplifiedRemove);
if (userIdsAdd != null)
{
@@ -536,30 +459,11 @@ namespace Timeline.Services
await Database.SaveChangesAsync();
}
- public async Task<bool> HasReadPermission(string name, string? username)
+ public async Task<bool> HasReadPermission(string name, long? visitorId)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
- long? userId = null;
- if (username != null)
- {
- var (result, message) = UsernameValidator.Validate(username);
- if (!result)
- {
- throw new UsernameBadFormatException(username);
- }
-
- var user = await Database.Users.Where(u => u.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
-
- if (user == null)
- {
- throw new UserNotExistException(username);
- }
-
- userId = user.Id;
- }
-
var timelineId = await FindTimelineId(name);
var timelineEntity = await Database.Timelines.Where(t => t.Id == timelineId).Select(t => new { t.Visibility }).SingleAsync();
@@ -567,43 +471,24 @@ namespace Timeline.Services
if (timelineEntity.Visibility == TimelineVisibility.Public)
return true;
- if (timelineEntity.Visibility == TimelineVisibility.Register && username != null)
+ if (timelineEntity.Visibility == TimelineVisibility.Register && visitorId != null)
return true;
- if (userId == null)
+ if (visitorId == null)
{
return false;
}
else
{
- var memberEntity = await Database.TimelineMembers.Where(m => m.UserId == userId && m.TimelineId == timelineId).SingleOrDefaultAsync();
+ var memberEntity = await Database.TimelineMembers.Where(m => m.UserId == visitorId && m.TimelineId == timelineId).SingleOrDefaultAsync();
return memberEntity != null;
}
}
- public async Task<bool> HasPostModifyPermission(string name, long id, string username)
+ public async Task<bool> HasPostModifyPermission(string name, long id, long modifierId)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
- if (username == null)
- throw new ArgumentNullException(nameof(username));
-
- {
- var (result, message) = UsernameValidator.Validate(username);
- if (!result)
- {
- throw new UsernameBadFormatException(username);
- }
- }
-
- var user = await Database.Users.Where(u => u.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
-
- if (user == null)
- {
- throw new UserNotExistException(username);
- }
-
- var userId = user.Id;
var timelineId = await FindTimelineId(name);
@@ -614,32 +499,13 @@ namespace Timeline.Services
if (postEntity == null)
throw new TimelinePostNotExistException(id);
- return timelineEntity.OwnerId == userId || postEntity.AuthorId == userId;
+ return timelineEntity.OwnerId == modifierId || postEntity.AuthorId == modifierId;
}
- public async Task<bool> IsMemberOf(string name, string username)
+ public async Task<bool> IsMemberOf(string name, long userId)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
- if (username == null)
- throw new ArgumentNullException(nameof(username));
-
- {
- var (result, message) = UsernameValidator.Validate(username);
- if (!result)
- {
- throw new UsernameBadFormatException(username);
- }
- }
-
- var user = await Database.Users.Where(u => u.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
-
- if (user == null)
- {
- throw new UserNotExistException(username);
- }
-
- var userId = user.Id;
var timelineId = await FindTimelineId(name);
@@ -648,38 +514,33 @@ namespace Timeline.Services
if (userId == timelineEntity.OwnerId)
return true;
- var timelineMemberEntity = await Database.TimelineMembers.Where(m => m.TimelineId == timelineId && m.UserId == userId).SingleOrDefaultAsync();
-
- return timelineMemberEntity != null;
+ return await Database.TimelineMembers.AnyAsync(m => m.TimelineId == timelineId && m.UserId == userId);
}
}
public class PersonalTimelineService : BaseTimelineService, IPersonalTimelineService
{
- public PersonalTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IClock clock)
- : base(loggerFactory, database, clock)
+ public PersonalTimelineService(ILoggerFactory loggerFactory, DatabaseContext database, IUserService userService, IMapper mapper, IClock clock)
+ : base(loggerFactory, database, userService, mapper, clock)
{
}
protected override async Task<long> FindTimelineId(string name)
{
+ long userId;
+ try
{
- var (result, message) = UsernameValidator.Validate(name);
- if (!result)
- {
- throw new TimelineNameBadFormatException(name, new UsernameBadFormatException(name, message));
- }
+ userId = await UserService.GetUserIdByUsername(name);
}
-
- var userEntity = await Database.Users.Where(u => u.Username == name).Select(u => new { u.Id }).SingleOrDefaultAsync();
-
- if (userEntity == null)
+ catch (ArgumentException e)
{
- throw new TimelineNotExistException(name, new UserNotExistException(name));
+ throw new ArgumentException(ExceptionFindTimelineUsernameBadFormat, nameof(name), e);
+ }
+ catch (UserNotExistException e)
+ {
+ throw new TimelineNotExistException(name, e);
}
-
- var userId = userEntity.Id;
var timelineEntity = await Database.Timelines.Where(t => t.OwnerId == userId && t.Name == null).Select(t => new { t.Id }).SingleOrDefaultAsync();
@@ -715,16 +576,20 @@ namespace Timeline.Services
var timelineMemberEntities = await Database.TimelineMembers.Where(m => m.TimelineId == timelineId).Select(m => new { m.UserId }).ToListAsync();
- var memberUsernameTasks = timelineMemberEntities.Select(m => Database.Users.Where(u => u.Id == m.UserId).Select(u => u.Username).SingleAsync()).ToArray();
+ var owner = Mapper.Map<UserInfo>(await UserService.GetUserById(timelineEntity.OwnerId));
- var memberUsernames = await Task.WhenAll(memberUsernameTasks);
+ var members = new List<UserInfo>();
+ foreach (var memberEntity in timelineMemberEntities)
+ {
+ members.Add(Mapper.Map<UserInfo>(await UserService.GetUserById(memberEntity.UserId)));
+ }
return new BaseTimelineInfo
{
Description = timelineEntity.Description ?? "",
- Owner = username,
+ Owner = owner,
Visibility = timelineEntity.Visibility,
- Members = memberUsernames.ToList()
+ Members = members
};
}
diff --git a/Timeline/Services/User.cs b/Timeline/Services/User.cs
index f63a374e..09a472e5 100644
--- a/Timeline/Services/User.cs
+++ b/Timeline/Services/User.cs
@@ -1,14 +1,9 @@
-using Microsoft.AspNetCore.Mvc;
-using System;
-using Timeline.Controllers;
-
-namespace Timeline.Services
+namespace Timeline.Services
{
public class User
{
public string? Username { get; set; }
public string? Nickname { get; set; }
- public string? AvatarUrl { get; set; }
#region adminsecret
public bool? Administrator { get; set; }
@@ -20,30 +15,4 @@ namespace Timeline.Services
public long? Version { get; set; }
#endregion secret
}
-
- public static class UserExtensions
- {
- public static User EraseSecretAndFinalFill(this User user, IUrlHelper urlHelper, bool adminstrator)
- {
- if (user == null)
- throw new ArgumentNullException(nameof(user));
-
- var result = new User
- {
- Username = user.Username,
- Nickname = user.Nickname,
- AvatarUrl = urlHelper.ActionLink(action: nameof(UserAvatarController.Get), controller: nameof(UserAvatarController), values: new
- {
- user.Username
- })
- };
-
- if (adminstrator)
- {
- result.Administrator = user.Administrator;
- }
-
- return result;
- }
- }
}
diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs
index ac7dd857..39b408e6 100644
--- a/Timeline/Services/UserAvatarService.cs
+++ b/Timeline/Services/UserAvatarService.cs
@@ -11,7 +11,6 @@ using System.Linq;
using System.Threading.Tasks;
using Timeline.Entities;
using Timeline.Helpers;
-using Timeline.Models.Validation;
namespace Timeline.Services
{
@@ -61,36 +60,27 @@ namespace Timeline.Services
public interface IUserAvatarService
{
/// <summary>
- /// Get the etag of a user's avatar.
+ /// Get the etag of a user's avatar. Warning: This method does not check the user existence.
/// </summary>
- /// <param name="username">The username of the user to get avatar etag of.</param>
+ /// <param name="id">The id of the user to get avatar etag of.</param>
/// <returns>The etag.</returns>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception>
- /// <exception cref="UsernameBadFormatException">Thrown if the <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown if the user does not exist.</exception>
- Task<string> GetAvatarETag(string username);
+ Task<string> GetAvatarETag(long id);
/// <summary>
- /// Get avatar of a user. If the user has no avatar set, a default one is returned.
+ /// Get avatar of a user. If the user has no avatar set, a default one is returned. Warning: This method does not check the user existence.
/// </summary>
- /// <param name="username">The username of the user to get avatar of.</param>
+ /// <param name="id">The id of the user to get avatar of.</param>
/// <returns>The avatar info.</returns>
- /// <exception cref="ArgumentNullException">Thrown if <paramref name="username"/> is null.</exception>
- /// <exception cref="UsernameBadFormatException">Thrown if the <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown if the user does not exist.</exception>
- Task<AvatarInfo> GetAvatar(string username);
+ Task<AvatarInfo> GetAvatar(long id);
/// <summary>
- /// Set avatar for a user.
+ /// Set avatar for a user. Warning: This method does not check the user existence.
/// </summary>
- /// <param name="username">The username of the user to set avatar for.</param>
+ /// <param name="id">The id of the user to set avatar for.</param>
/// <param name="avatar">The avatar. Can be null to delete the saved avatar.</param>
- /// <exception cref="ArgumentNullException">Throw if <paramref name="username"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown if any field in <paramref name="avatar"/> is null when <paramref name="avatar"/> is not null.</exception>
- /// <exception cref="UsernameBadFormatException">Thrown if the <paramref name="username"/> is of bad format.</exception>
- /// <exception cref="UserNotExistException">Thrown if the user does not exist.</exception>
/// <exception cref="AvatarFormatException">Thrown if avatar is of bad format.</exception>
- Task SetAvatar(string username, Avatar? avatar);
+ Task SetAvatar(long id, Avatar? avatar);
}
// TODO! : Make this configurable.
@@ -104,7 +94,6 @@ namespace Timeline.Services
private DateTime _cacheLastModified;
private string _cacheETag = default!;
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "DI.")]
public DefaultUserAvatarProvider(IWebHostEnvironment environment, IETagGenerator eTagGenerator)
{
_avatarPath = Path.Combine(environment.ContentRootPath, "default-avatar.png");
@@ -195,22 +184,18 @@ namespace Timeline.Services
_clock = clock;
}
- public async Task<string> GetAvatarETag(string username)
+ public async Task<string> GetAvatarETag(long id)
{
- var userId = await DatabaseExtensions.CheckAndGetUser(_database.Users, username);
-
- var eTag = (await _database.UserAvatars.Where(a => a.UserId == userId).Select(a => new { a.ETag }).SingleOrDefaultAsync())?.ETag;
+ var eTag = (await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.ETag }).SingleOrDefaultAsync())?.ETag;
if (eTag == null)
return await _defaultUserAvatarProvider.GetDefaultAvatarETag();
else
return eTag;
}
- public async Task<AvatarInfo> GetAvatar(string username)
+ public async Task<AvatarInfo> GetAvatar(long id)
{
- var userId = await DatabaseExtensions.CheckAndGetUser(_database.Users, username);
-
- var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == userId).Select(a => new { a.Type, a.Data, a.LastModified }).SingleOrDefaultAsync();
+ var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == id).Select(a => new { a.Type, a.Data, a.LastModified }).SingleOrDefaultAsync();
if (avatarEntity != null)
{
@@ -240,7 +225,7 @@ namespace Timeline.Services
return defaultAvatar;
}
- public async Task SetAvatar(string username, Avatar? avatar)
+ public async Task SetAvatar(long id, Avatar? avatar)
{
if (avatar != null)
{
@@ -250,8 +235,7 @@ namespace Timeline.Services
throw new ArgumentException(Resources.Services.UserAvatarService.ExceptionAvatarTypeNullOrEmpty, nameof(avatar));
}
- var userId = await DatabaseExtensions.CheckAndGetUser(_database.Users, username);
- var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == userId).SingleOrDefaultAsync();
+ var avatarEntity = await _database.UserAvatars.Where(a => a.UserId == id).SingleOrDefaultAsync();
if (avatar == null)
{
@@ -281,7 +265,7 @@ namespace Timeline.Services
avatarEntity.Data = avatar.Data;
avatarEntity.ETag = await _eTagGenerator.Generate(avatar.Data);
avatarEntity.LastModified = _clock.GetCurrentTime();
- avatarEntity.UserId = userId;
+ avatarEntity.UserId = id;
if (create)
{
_database.UserAvatars.Add(avatarEntity);
diff --git a/Timeline/Services/UserRoleConvert.cs b/Timeline/Services/UserRoleConvert.cs
index 4fa4a7b8..f27ee1bb 100644
--- a/Timeline/Services/UserRoleConvert.cs
+++ b/Timeline/Services/UserRoleConvert.cs
@@ -5,7 +5,6 @@ using Timeline.Entities;
namespace Timeline.Services
{
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "No need.")]
public static class UserRoleConvert
{
public const string UserRole = UserRoles.User;
diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs
index ff2306c5..1197bb73 100644
--- a/Timeline/Services/UserService.cs
+++ b/Timeline/Services/UserService.cs
@@ -44,6 +44,16 @@ namespace Timeline.Services
Task<User> GetUserByUsername(string username);
/// <summary>
+ /// Get the user id of given username.
+ /// </summary>
+ /// <param name="username">Username of the user.</param>
+ /// <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>
+ Task<long> GetUserIdByUsername(string username);
+
+ /// <summary>
/// List all users.
/// </summary>
/// <returns>The user info of users.</returns>
@@ -57,7 +67,7 @@ namespace Timeline.Services
/// <returns>The id of the new user.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="info"/>is null.</exception>
/// <exception cref="ArgumentException">Thrown when some fields in <paramref name="info"/> is bad.</exception>
- /// <exception cref="ConfictException">Thrown when a user with given username already exists.</exception>
+ /// <exception cref="ConflictException">Thrown when a user with given username already exists.</exception>
/// <remarks>
/// <see cref="User.Username"/> must not be null and must be a valid username.
/// <see cref="User.Password"/> must not be null or empty.
@@ -78,13 +88,12 @@ namespace Timeline.Services
/// Only <see cref="User.Username"/>, <see cref="User.Administrator"/>, <see cref="User.Password"/> and <see cref="User.Nickname"/> will be used.
/// If null, then not change.
/// Other fields are ignored.
- /// After modified, even if nothing is changed, version will increase.
+ /// Version will increase if password is changed.
///
/// <see cref="User.Username"/> must be a valid username if set.
/// <see cref="User.Password"/> can't be empty if set.
/// <see cref="User.Nickname"/> must be a valid nickname if set.
///
- /// Note: Whether <see cref="User.Version"/> is set or not, version will increase and not set to the specified value if there is one.
/// </remarks>
/// <seealso cref="ModifyUser(string, User)"/>
Task ModifyUser(long id, User? info);
@@ -97,6 +106,7 @@ namespace Timeline.Services
/// <exception cref="ArgumentNullException">Thrown when <paramref name="username"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="username"/> is of bad format or some fields in <paramref name="info"/> is bad.</exception>
/// <exception cref="UserNotExistException">Thrown when user with given id does not exist.</exception>
+ /// <exception cref="ConflictException">Thrown when user with the newusername already exist.</exception>
/// <remarks>
/// Only <see cref="User.Administrator"/>, <see cref="User.Password"/> and <see cref="User.Nickname"/> will be used.
/// If null, then not change.
@@ -184,7 +194,7 @@ namespace Timeline.Services
private static void ThrowUsernameConflict()
{
- throw new ConfictException(ExceptionUsernameConflict);
+ throw new ConflictException(ExceptionUsernameConflict);
}
private static User CreateUserFromEntity(UserEntity entity)
@@ -245,6 +255,21 @@ namespace Timeline.Services
return CreateUserFromEntity(entity);
}
+ public async Task<long> GetUserIdByUsername(string username)
+ {
+ if (username == null)
+ throw new ArgumentNullException(nameof(username));
+
+ CheckUsernameFormat(username, nameof(username));
+
+ var entity = await _databaseContext.Users.Where(user => user.Username == username).Select(u => new { u.Id }).SingleOrDefaultAsync();
+
+ if (entity == null)
+ throw new UserNotExistException(username);
+
+ return entity.Id;
+ }
+
public async Task<User[]> GetUsers()
{
var entities = await _databaseContext.Users.ToArrayAsync();
@@ -325,6 +350,7 @@ namespace Timeline.Services
if (password != null)
{
entity.Password = _passwordService.HashPassword(password);
+ entity.Version += 1;
}
var administrator = info.Administrator;
@@ -339,8 +365,6 @@ namespace Timeline.Services
entity.Nickname = nickname;
}
}
-
- entity.Version += 1;
}
diff --git a/Timeline/Services/UserTokenService.cs b/Timeline/Services/UserTokenService.cs
index c246fdff..cf7286f4 100644
--- a/Timeline/Services/UserTokenService.cs
+++ b/Timeline/Services/UserTokenService.cs
@@ -49,7 +49,6 @@ namespace Timeline.Services
private readonly JwtSecurityTokenHandler _tokenHandler = new JwtSecurityTokenHandler();
private SymmetricSecurityKey _tokenSecurityKey;
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "<Pending>")]
public JwtUserTokenService(IOptionsMonitor<JwtConfig> jwtConfig, IClock clock)
{
_jwtConfig = jwtConfig;