From 88002173a1155883d1fb46683a9a7ad1f521eb56 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 30 Apr 2021 16:52:55 +0800 Subject: refactor: ... --- .../Timeline.Tests/IntegratedTests/TimelineTest.cs | 12 +- .../IntegratedTests/UserAvatarTest.cs | 6 +- .../IntegratedTests/UserPermissionTest.cs | 4 +- BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs | 8 +- .../Services/UserPermissionServiceTest.cs | 9 +- .../ActionResultControllerExtensions.cs | 13 +++ .../Controllers/BookmarkTimelineController.cs | 30 +---- .../Controllers/HighlightTimelineController.cs | 30 +---- BackEnd/Timeline/Controllers/Resource.Designer.cs | 9 ++ BackEnd/Timeline/Controllers/Resource.resx | 3 + BackEnd/Timeline/Controllers/TimelineController.cs | 70 +++--------- .../Timeline/Controllers/TimelinePostController.cs | 3 - BackEnd/Timeline/Controllers/TokenController.cs | 4 +- .../Timeline/Controllers/UserAvatarController.cs | 32 +----- BackEnd/Timeline/Controllers/UserController.cs | 53 ++------- BackEnd/Timeline/ErrorCodes.cs | 24 ++-- .../CatchEntityAlreadyExistExceptionFilter.cs | 28 +++++ .../Filters/CatchEntityNotExistExceptionFilter.cs | 40 +++++++ .../CatchTimelineNotExistExceptionAttribute.cs | 33 ------ ...chTimelinePostDataNotExistExceptionAttribute.cs | 24 ---- .../CatchTimelinePostNotExistExceptionAttribute.cs | 24 ---- BackEnd/Timeline/Filters/Resource.Designer.cs | 81 +++++++++++++ BackEnd/Timeline/Filters/Resource.resx | 126 +++++++++++++++++++++ BackEnd/Timeline/Models/Http/ErrorResponse.cs | 48 +------- .../Services/Api/BookmarkTimelineService.cs | 32 ++---- .../Services/Api/HighlightTimelineService.cs | 21 ++-- .../Services/Api/IBookmarkTimelineService.cs | 18 +-- .../Services/Api/IHighlightTimelineService.cs | 12 +- .../Services/EntityAlreadyExistException.cs | 21 ++-- BackEnd/Timeline/Services/EntityException.cs | 31 +++++ BackEnd/Timeline/Services/EntityNames.cs | 2 + .../Timeline/Services/EntityNotExistException.cs | 16 +-- BackEnd/Timeline/Services/EntityType.cs | 34 ++++++ BackEnd/Timeline/Services/EntityTypes.cs | 11 ++ .../Services/Timeline/BasicTimelineService.cs | 22 +++- .../Timeline/BasicTimelineServiceExtensions.cs | 17 +++ .../Services/Timeline/IBasicTimelineService.cs | 8 +- .../Services/Timeline/ITimelinePostService.cs | 37 +++--- .../Timeline/Services/Timeline/ITimelineService.cs | 22 ++-- .../Timeline/TimelineAlreadyExistException.cs | 24 ---- .../Services/Timeline/TimelineNotExistException.cs | 27 ----- .../Timeline/TimelinePostDataNotExistException.cs | 25 ---- .../Timeline/TimelinePostNotExistException.cs | 36 ------ .../Services/Timeline/TimelinePostService.cs | 72 ++++++------ .../Timeline/Services/Timeline/TimelineService.cs | 33 +++--- .../Timeline/Services/Token/IUserTokenManager.cs | 2 +- .../Timeline/Services/Token/UserTokenManager.cs | 2 +- .../Services/User/Avatar/IUserAvatarService.cs | 8 +- BackEnd/Timeline/Services/User/BasicUserService.cs | 28 ++--- .../Services/User/BasicUserServiceExtensions.cs | 17 +++ .../Timeline/Services/User/IBasicUserService.cs | 4 +- .../Services/User/IUserPermissionService.cs | 6 +- BackEnd/Timeline/Services/User/IUserService.cs | 8 +- .../Services/User/UserAlreadyExistException.cs | 24 ---- .../Services/User/UserNotExistException.cs | 37 ------ .../Services/User/UserPermissionService.cs | 10 +- BackEnd/Timeline/Services/User/UserService.cs | 19 ++-- BackEnd/Timeline/Startup.cs | 8 +- BackEnd/Timeline/Timeline.csproj | 9 ++ 59 files changed, 713 insertions(+), 704 deletions(-) create mode 100644 BackEnd/Timeline/Controllers/ActionResultControllerExtensions.cs create mode 100644 BackEnd/Timeline/Filters/CatchEntityAlreadyExistExceptionFilter.cs create mode 100644 BackEnd/Timeline/Filters/CatchEntityNotExistExceptionFilter.cs delete mode 100644 BackEnd/Timeline/Filters/CatchTimelineNotExistExceptionAttribute.cs delete mode 100644 BackEnd/Timeline/Filters/CatchTimelinePostDataNotExistExceptionAttribute.cs delete mode 100644 BackEnd/Timeline/Filters/CatchTimelinePostNotExistExceptionAttribute.cs create mode 100644 BackEnd/Timeline/Filters/Resource.Designer.cs create mode 100644 BackEnd/Timeline/Filters/Resource.resx create mode 100644 BackEnd/Timeline/Services/EntityException.cs create mode 100644 BackEnd/Timeline/Services/EntityType.cs create mode 100644 BackEnd/Timeline/Services/EntityTypes.cs create mode 100644 BackEnd/Timeline/Services/Timeline/BasicTimelineServiceExtensions.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/TimelineAlreadyExistException.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/TimelineNotExistException.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/TimelinePostDataNotExistException.cs delete mode 100644 BackEnd/Timeline/Services/Timeline/TimelinePostNotExistException.cs create mode 100644 BackEnd/Timeline/Services/User/BasicUserServiceExtensions.cs delete mode 100644 BackEnd/Timeline/Services/User/UserAlreadyExistException.cs delete mode 100644 BackEnd/Timeline/Services/User/UserNotExistException.cs diff --git a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs index e2ce8875..0e7bb735 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/TimelineTest.cs @@ -188,7 +188,7 @@ namespace Timeline.Tests.IntegratedTests body.Should().BeEquivalentTo(await client.GetTimelineAsync("aaa")); } - await client.TestPostAssertErrorAsync("timelines", new HttpTimelineCreateRequest { Name = "aaa" }, errorCode: ErrorCodes.TimelineController.NameConflict); + await client.TestPostAssertErrorAsync("timelines", new HttpTimelineCreateRequest { Name = "aaa" }, errorCode: ErrorCodes.Conflict.Timeline); } } @@ -210,7 +210,7 @@ namespace Timeline.Tests.IntegratedTests await client.TestDeleteAssertInvalidModelAsync("timelines/!!!"); await client.TestDeleteAsync("timelines/t2"); - await client.TestDeleteAssertErrorAsync("timelines/t2"); + await client.TestDeleteAsync("timelines/t2"); } { @@ -218,7 +218,7 @@ namespace Timeline.Tests.IntegratedTests await client.TestDeleteAssertInvalidModelAsync("timelines/!!!"); await client.TestDeleteAsync("timelines/t1"); - await client.TestDeleteAssertErrorAsync("timelines/t1"); + await client.TestDeleteAsync("timelines/t1"); } } @@ -294,13 +294,13 @@ namespace Timeline.Tests.IntegratedTests } await AssertEmptyMembers(); - await client.TestPutAssertErrorAsync($"timelines/{timelineName}/members/usernotexist", errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestPutAssertErrorAsync($"timelines/{timelineName}/members/usernotexist", errorCode: ErrorCodes.NotExist.User); await AssertEmptyMembers(); await client.PutTimelineMemberAsync(timelineName, "user2"); await AssertMembers(new List { await client.GetUserAsync("user2") }); await client.DeleteTimelineMemberAsync(timelineName, "user2", true); await AssertEmptyMembers(); - await client.TestDeleteAssertErrorAsync($"timelines/{timelineName}/members/usernotexist", errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestDeleteAsync($"timelines/{timelineName}/members/usernotexist", false); await AssertEmptyMembers(); } @@ -377,7 +377,7 @@ namespace Timeline.Tests.IntegratedTests using (var client = await CreateClientAsUser()) { await client.TestPatchAssertInvalidModelAsync("timelines/t1", new HttpTimelinePatchRequest { Name = "!!!" }); - await client.TestPatchAssertErrorAsync("timelines/t1", new HttpTimelinePatchRequest { Name = "t2" }, errorCode: ErrorCodes.TimelineController.NameConflict); + await client.TestPatchAssertErrorAsync("timelines/t1", new HttpTimelinePatchRequest { Name = "t2" }, errorCode: ErrorCodes.Conflict.Timeline); await client.TestPatchAsync("timelines/t1", new HttpTimelinePatchRequest { Name = "newt" }); diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs index 708120b1..c2ccff64 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserAvatarTest.cs @@ -30,7 +30,7 @@ namespace Timeline.Tests.IntegratedTests using (var client = await CreateClientAsUser()) { - await client.TestGetAssertNotFoundAsync("users/usernotexist/avatar", errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestGetAssertNotFoundAsync("users/usernotexist/avatar", errorCode: ErrorCodes.NotExist.User); var env = TestApp.Host.Services.GetRequiredService(); var defaultAvatarData = await File.ReadAllBytesAsync(Path.Combine(env.ContentRootPath, "default-avatar.png")); @@ -138,8 +138,8 @@ namespace Timeline.Tests.IntegratedTests { await client.TestPutByteArrayAsync("users/user1/avatar", mockAvatar.Data, mockAvatar.ContentType); await client.TestDeleteAsync("users/user1/avatar"); - await client.TestPutByteArrayAssertErrorAsync("users/usernotexist/avatar", new[] { (byte)0x00 }, "image/png", errorCode: ErrorCodes.UserCommon.NotExist); - await client.TestDeleteAssertErrorAsync("users/usernotexist/avatar", errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestPutByteArrayAssertErrorAsync("users/usernotexist/avatar", new[] { (byte)0x00 }, "image/png", errorCode: ErrorCodes.NotExist.User); + await client.TestDeleteAsync("users/usernotexist/avatar"); } // bad username check diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs index 32e25aaa..83dc51f9 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserPermissionTest.cs @@ -190,8 +190,8 @@ namespace Timeline.Tests.IntegratedTests const string url = "users/user123/permissions/UserManagement"; - await client.TestPutAssertNotFoundAsync(url, errorCode: ErrorCodes.UserCommon.NotExist); - await client.TestDeleteAssertNotFoundAsync(url, errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestPutAssertErrorAsync(url, errorCode: ErrorCodes.NotExist.User); + await client.TestDeleteAsync(url); } } } diff --git a/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs b/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs index c728a280..7286e12e 100644 --- a/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs +++ b/BackEnd/Timeline.Tests/IntegratedTests/UserTest.cs @@ -47,7 +47,7 @@ namespace Timeline.Tests.IntegratedTests public async Task Get_404() { using var client = await CreateDefaultClient(); - await client.TestGetAssertNotFoundAsync("users/usernotexist", errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestGetAssertNotFoundAsync("users/usernotexist", errorCode: ErrorCodes.NotExist.User); } [Fact] @@ -104,7 +104,7 @@ namespace Timeline.Tests.IntegratedTests public async Task Patch_NotExist() { using var client = await CreateClientAsAdministrator(); - await client.TestPatchAssertNotFoundAsync("users/usernotexist", new HttpUserPatchRequest { }, errorCode: ErrorCodes.UserCommon.NotExist); + await client.TestPatchAssertErrorAsync("users/usernotexist", new HttpUserPatchRequest { }, errorCode: ErrorCodes.NotExist.User); } [Fact] @@ -133,7 +133,7 @@ namespace Timeline.Tests.IntegratedTests public async Task Patch_UsernameConflict() { using var client = await CreateClientAsAdministrator(); - await client.TestPatchAssertErrorAsync("users/user1", new HttpUserPatchRequest { Username = "admin" }, errorCode: ErrorCodes.UserController.UsernameConflict); + await client.TestPatchAssertErrorAsync("users/user1", new HttpUserPatchRequest { Username = "admin" }, errorCode: ErrorCodes.Conflict.User); } [Fact] @@ -255,7 +255,7 @@ namespace Timeline.Tests.IntegratedTests { Username = "user1", Password = "bbb", - }, errorCode: ErrorCodes.UserController.UsernameConflict); + }, errorCode: ErrorCodes.Conflict.User); } [Fact] diff --git a/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs b/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs index aa92ff73..7923e9db 100644 --- a/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs +++ b/BackEnd/Timeline.Tests/Services/UserPermissionServiceTest.cs @@ -1,6 +1,7 @@ using FluentAssertions; using System; using System.Threading.Tasks; +using Timeline.Services; using Timeline.Services.User; using Xunit; @@ -17,7 +18,7 @@ namespace Timeline.Tests.Services protected override void OnInitialize() { - _service = new UserPermissionService(Database); + _service = new UserPermissionService(Database, UserService); } [Fact] @@ -37,7 +38,7 @@ namespace Timeline.Tests.Services [Fact] public async Task GetPermissionsOfInexistentUserShouldThrow() { - await _service.Awaiting(s => s.GetPermissionsOfUserAsync(10)).Should().ThrowAsync(); + await _service.Awaiting(s => s.GetPermissionsOfUserAsync(10)).Should().ThrowAsync(); } [Fact] @@ -91,13 +92,13 @@ namespace Timeline.Tests.Services [Fact] public async Task AddPermissionToInexistentUserShouldThrown() { - await _service.Awaiting(s => s.AddPermissionToUserAsync(10, UserPermission.HighlightTimelineManagement)).Should().ThrowAsync(); + await _service.Awaiting(s => s.AddPermissionToUserAsync(10, UserPermission.HighlightTimelineManagement)).Should().ThrowAsync(); } [Fact] public async Task RemovePermissionFromInexistentUserShouldThrown() { - await _service.Awaiting(s => s.RemovePermissionFromUserAsync(10, UserPermission.HighlightTimelineManagement)).Should().ThrowAsync(); + await _service.Awaiting(s => s.RemovePermissionFromUserAsync(10, UserPermission.HighlightTimelineManagement)).Should().ThrowAsync(); } [Fact] diff --git a/BackEnd/Timeline/Controllers/ActionResultControllerExtensions.cs b/BackEnd/Timeline/Controllers/ActionResultControllerExtensions.cs new file mode 100644 index 00000000..76a8b7ae --- /dev/null +++ b/BackEnd/Timeline/Controllers/ActionResultControllerExtensions.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Mvc; +using Timeline.Models.Http; + +namespace Timeline.Controllers +{ + public static class ActionResultControllerExtensions + { + public static BadRequestObjectResult BadRequestWithCodeAndMessage(this ControllerBase controller, int code, string message) + { + return controller.BadRequest(new CommonResponse(code, message)); + } + } +} diff --git a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs index cbc96fc6..94cb0f3e 100644 --- a/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs +++ b/BackEnd/Timeline/Controllers/BookmarkTimelineController.cs @@ -60,16 +60,9 @@ namespace Timeline.Controllers [ProducesResponseType(401)] public async Task> Put([GeneralTimelineName] string timeline) { - try - { - var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); - var create = await _service.AddBookmarkAsync(this.GetUserId(), timelineId); - return CommonPutResponse.Create(create); - } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } + var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); + var create = await _service.AddBookmarkAsync(this.GetUserId(), timelineId); + return CommonPutResponse.Create(create); } /// @@ -83,16 +76,9 @@ namespace Timeline.Controllers [ProducesResponseType(401)] public async Task> Delete([GeneralTimelineName] string timeline) { - try - { - var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); - var delete = await _service.RemoveBookmarkAsync(this.GetUserId(), timelineId); - return CommonDeleteResponse.Create(delete); - } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } + var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); + var delete = await _service.RemoveBookmarkAsync(this.GetUserId(), timelineId); + return CommonDeleteResponse.Create(delete); } /// @@ -112,10 +98,6 @@ namespace Timeline.Controllers await _service.MoveBookmarkAsync(this.GetUserId(), timelineId, request.NewPosition!.Value); return Ok(); } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } catch (InvalidBookmarkException) { return BadRequest(new CommonResponse(ErrorCodes.BookmarkTimelineController.NonBookmark, "You can't move a non-bookmark timeline.")); diff --git a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs index ffaa50c1..e73bc7a9 100644 --- a/BackEnd/Timeline/Controllers/HighlightTimelineController.cs +++ b/BackEnd/Timeline/Controllers/HighlightTimelineController.cs @@ -60,16 +60,9 @@ namespace Timeline.Controllers [ProducesResponseType(403)] public async Task> Put([GeneralTimelineName] string timeline) { - try - { - var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); - var create = await _service.AddHighlightTimelineAsync(timelineId, this.GetUserId()); - return CommonPutResponse.Create(create); - } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } + var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); + var create = await _service.AddHighlightTimelineAsync(timelineId, this.GetUserId()); + return CommonPutResponse.Create(create); } /// @@ -84,16 +77,9 @@ namespace Timeline.Controllers [ProducesResponseType(403)] public async Task> Delete([GeneralTimelineName] string timeline) { - try - { - var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); - var delete = await _service.RemoveHighlightTimelineAsync(timelineId, this.GetUserId()); - return CommonDeleteResponse.Create(delete); - } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } + var timelineId = await _timelineService.GetTimelineIdByNameAsync(timeline); + var delete = await _service.RemoveHighlightTimelineAsync(timelineId, this.GetUserId()); + return CommonDeleteResponse.Create(delete); } /// @@ -113,10 +99,6 @@ namespace Timeline.Controllers await _service.MoveHighlightTimelineAsync(timelineId, body.NewPosition!.Value); return Ok(); } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } catch (InvalidHighlightTimelineException) { return BadRequest(new CommonResponse(ErrorCodes.HighlightTimelineController.NonHighlight, "Can't move a non-highlight timeline.")); diff --git a/BackEnd/Timeline/Controllers/Resource.Designer.cs b/BackEnd/Timeline/Controllers/Resource.Designer.cs index 6279a055..c2dfd3cd 100644 --- a/BackEnd/Timeline/Controllers/Resource.Designer.cs +++ b/BackEnd/Timeline/Controllers/Resource.Designer.cs @@ -68,5 +68,14 @@ namespace Timeline.Controllers { return ResourceManager.GetString("ExceptionNoUserId", resourceCulture); } } + + /// + /// Looks up a localized string similar to A user with given username already exists.. + /// + internal static string MessageUsernameConflict { + get { + return ResourceManager.GetString("MessageUsernameConflict", resourceCulture); + } + } } } diff --git a/BackEnd/Timeline/Controllers/Resource.resx b/BackEnd/Timeline/Controllers/Resource.resx index ec45a5c9..8939dfd8 100644 --- a/BackEnd/Timeline/Controllers/Resource.resx +++ b/BackEnd/Timeline/Controllers/Resource.resx @@ -120,4 +120,7 @@ Can't get user id. + + A user with given username already exists. + \ No newline at end of file diff --git a/BackEnd/Timeline/Controllers/TimelineController.cs b/BackEnd/Timeline/Controllers/TimelineController.cs index 3fd0f2ac..bb770ea0 100644 --- a/BackEnd/Timeline/Controllers/TimelineController.cs +++ b/BackEnd/Timeline/Controllers/TimelineController.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; using Timeline.Entities; -using Timeline.Filters; using Timeline.Models; using Timeline.Models.Http; using Timeline.Models.Validation; @@ -21,7 +20,6 @@ namespace Timeline.Controllers /// [ApiController] [Route("timelines")] - [CatchTimelineNotExistException] [ProducesErrorResponseType(typeof(CommonResponse))] public class TimelineController : Controller { @@ -100,7 +98,7 @@ namespace Timeline.Controllers relationship = new TimelineUserRelationship(relationType, relatedUserId); } - catch (UserNotExistException) + catch (EntityNotExistException) { return BadRequest(ErrorResponse.TimelineController.QueryRelateNotExist()); } @@ -148,17 +146,10 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - try - { - await _service.ChangePropertyAsync(timelineId, _mapper.AutoMapperMap(body)); - var t = await _service.GetTimelineAsync(timelineId); - var result = await Map(t); - return result; - } - catch (EntityAlreadyExistException) - { - return BadRequest(ErrorResponse.TimelineController.NameConflict()); - } + await _service.ChangePropertyAsync(timelineId, _mapper.AutoMapperMap(body)); + var t = await _service.GetTimelineAsync(timelineId); + var result = await Map(t); + return result; } /// @@ -181,16 +172,9 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - try - { - var userId = await _userService.GetUserIdByUsernameAsync(member); - var create = await _service.AddMemberAsync(timelineId, userId); - return Ok(CommonPutResponse.Create(create)); - } - catch (UserNotExistException) - { - return BadRequest(ErrorResponse.UserCommon.NotExist()); - } + var userId = await _userService.GetUserIdByUsernameAsync(member); + var create = await _service.AddMemberAsync(timelineId, userId); + return Ok(CommonPutResponse.Create(create)); } /// @@ -213,16 +197,10 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - try - { - var userId = await _userService.GetUserIdByUsernameAsync(member); - var delete = await _service.RemoveMemberAsync(timelineId, userId); - return Ok(CommonDeleteResponse.Create(delete)); - } - catch (UserNotExistException) - { - return BadRequest(ErrorResponse.UserCommon.NotExist()); - } + + var userId = await _userService.GetUserIdByUsernameAsync(member); + var delete = await _service.RemoveMemberAsync(timelineId, userId); + return Ok(CommonDeleteResponse.Create(delete)); } /// @@ -239,16 +217,9 @@ namespace Timeline.Controllers { var userId = this.GetUserId(); - try - { - var timeline = await _service.CreateTimelineAsync(body.Name, userId); - var result = await Map(timeline); - return result; - } - catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.Timeline) - { - return BadRequest(ErrorResponse.TimelineController.NameConflict()); - } + var timeline = await _service.CreateTimelineAsync(body.Name, userId); + var result = await Map(timeline); + return result; } /// @@ -271,15 +242,8 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - try - { - await _service.DeleteTimelineAsync(timelineId); - return Ok(); - } - catch (TimelineNotExistException) - { - return BadRequest(ErrorResponse.TimelineController.NotExist()); - } + await _service.DeleteTimelineAsync(timelineId); + return Ok(); } } } diff --git a/BackEnd/Timeline/Controllers/TimelinePostController.cs b/BackEnd/Timeline/Controllers/TimelinePostController.cs index 2d3e5423..70f672d1 100644 --- a/BackEnd/Timeline/Controllers/TimelinePostController.cs +++ b/BackEnd/Timeline/Controllers/TimelinePostController.cs @@ -22,9 +22,6 @@ namespace Timeline.Controllers /// [ApiController] [Route("timelines/{timeline}/posts")] - [CatchTimelineNotExistException] - [CatchTimelinePostNotExistException] - [CatchTimelinePostDataNotExistException] [ProducesErrorResponseType(typeof(CommonResponse))] public class TimelinePostController : Controller { diff --git a/BackEnd/Timeline/Controllers/TokenController.cs b/BackEnd/Timeline/Controllers/TokenController.cs index 3d4e9444..915f710d 100644 --- a/BackEnd/Timeline/Controllers/TokenController.cs +++ b/BackEnd/Timeline/Controllers/TokenController.cs @@ -44,7 +44,7 @@ namespace Timeline.Controllers try { DateTime? expireTime = null; - if (request.Expire != null) + if (request.Expire is not null) expireTime = _clock.GetCurrentTime().AddDays(request.Expire.Value); var result = await _userTokenManager.CreateTokenAsync(request.Username, request.Password, expireTime); @@ -55,7 +55,7 @@ namespace Timeline.Controllers User = await _mapper.MapAsync(result.User, Url, User) }; } - catch (UserNotExistException) + catch (EntityNotExistException) { return BadRequest(ErrorResponse.TokenController.Create_BadCredential()); } diff --git a/BackEnd/Timeline/Controllers/UserAvatarController.cs b/BackEnd/Timeline/Controllers/UserAvatarController.cs index b1129329..5d9becaa 100644 --- a/BackEnd/Timeline/Controllers/UserAvatarController.cs +++ b/BackEnd/Timeline/Controllers/UserAvatarController.cs @@ -44,16 +44,8 @@ namespace Timeline.Controllers public async Task Get([FromRoute][Username] string username, [FromHeader(Name = "If-None-Match")] string? ifNoneMatch) { _ = ifNoneMatch; - try - { - long userId = await _userService.GetUserIdByUsernameAsync(username); - return await DataCacheHelper.GenerateActionResult(this, () => _service.GetAvatarDigestAsync(userId), () => _service.GetAvatarAsync(userId)); - } - catch (UserNotExistException) - { - return NotFound(ErrorResponse.UserCommon.NotExist()); - } - + long userId = await _userService.GetUserIdByUsernameAsync(username); + return await DataCacheHelper.GenerateActionResult(this, () => _service.GetAvatarDigestAsync(userId), () => _service.GetAvatarAsync(userId)); } /// @@ -76,15 +68,7 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - long id; - try - { - id = await _userService.GetUserIdByUsernameAsync(username); - } - catch (UserNotExistException) - { - return BadRequest(ErrorResponse.UserCommon.NotExist()); - } + long id = await _userService.GetUserIdByUsernameAsync(username); try { @@ -127,15 +111,7 @@ namespace Timeline.Controllers return StatusCode(StatusCodes.Status403Forbidden, ErrorResponse.Common.Forbid()); } - long id; - try - { - id = await _userService.GetUserIdByUsernameAsync(username); - } - catch (UserNotExistException) - { - return BadRequest(ErrorResponse.UserCommon.NotExist()); - } + long id = await _userService.GetUserIdByUsernameAsync(username); await _service.DeleteAvatarAsync(id); return Ok(); diff --git a/BackEnd/Timeline/Controllers/UserController.cs b/BackEnd/Timeline/Controllers/UserController.cs index c0ae6a09..bdf9c0b7 100644 --- a/BackEnd/Timeline/Controllers/UserController.cs +++ b/BackEnd/Timeline/Controllers/UserController.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Timeline.Auth; using Timeline.Models.Http; using Timeline.Models.Validation; -using Timeline.Services; using Timeline.Services.Mapper; using Timeline.Services.User; @@ -59,16 +58,10 @@ namespace Timeline.Controllers [ProducesResponseType(StatusCodes.Status403Forbidden)] public async Task> Post([FromBody] HttpUserPostRequest body) { - try - { - var user = await _userService.CreateUserAsync( - new CreateUserParams(body.Username, body.Password) { Nickname = body.Nickname }); - return await _mapper.MapAsync(user, Url, User); - } - catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.User) - { - return BadRequest(ErrorResponse.UserController.UsernameConflict()); - } + + var user = await _userService.CreateUserAsync( + new CreateUserParams(body.Username, body.Password) { Nickname = body.Nickname }); + return await _mapper.MapAsync(user, Url, User); } /// @@ -81,16 +74,9 @@ namespace Timeline.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> Get([FromRoute][Username] string username) { - try - { - var id = await _userService.GetUserIdByUsernameAsync(username); - var user = await _userService.GetUserAsync(id); - return await _mapper.MapAsync(user, Url, User); - } - catch (UserNotExistException) - { - return NotFound(ErrorResponse.UserCommon.NotExist()); - } + var id = await _userService.GetUserIdByUsernameAsync(username); + var user = await _userService.GetUserAsync(id); + return await _mapper.MapAsync(user, Url, User); } /// @@ -109,20 +95,9 @@ namespace Timeline.Controllers { if (UserHasUserManagementPermission) { - try - { - var id = await _userService.GetUserIdByUsernameAsync(username); - var user = await _userService.ModifyUserAsync(id, _mapper.AutoMapperMap(body)); - return await _mapper.MapAsync(user, Url, User); - } - catch (UserNotExistException) - { - return NotFound(ErrorResponse.UserCommon.NotExist()); - } - catch (EntityAlreadyExistException e) when (e.EntityName == EntityNames.User) - { - return BadRequest(ErrorResponse.UserController.UsernameConflict()); - } + var id = await _userService.GetUserIdByUsernameAsync(username); + var user = await _userService.ModifyUserAsync(id, _mapper.AutoMapperMap(body)); + return await _mapper.MapAsync(user, Url, User); } else { @@ -204,10 +179,6 @@ namespace Timeline.Controllers await _userPermissionService.AddPermissionToUserAsync(id, permission); return Ok(); } - catch (UserNotExistException) - { - return NotFound(ErrorResponse.UserCommon.NotExist()); - } catch (InvalidOperationOnRootUserException) { return BadRequest(ErrorResponse.UserController.ChangePermission_RootUser()); @@ -228,10 +199,6 @@ namespace Timeline.Controllers await _userPermissionService.RemovePermissionFromUserAsync(id, permission); return Ok(); } - catch (UserNotExistException) - { - return NotFound(ErrorResponse.UserCommon.NotExist()); - } catch (InvalidOperationOnRootUserException) { return BadRequest(ErrorResponse.UserController.ChangePermission_RootUser()); diff --git a/BackEnd/Timeline/ErrorCodes.cs b/BackEnd/Timeline/ErrorCodes.cs index 87d451f2..06952822 100644 --- a/BackEnd/Timeline/ErrorCodes.cs +++ b/BackEnd/Timeline/ErrorCodes.cs @@ -1,4 +1,4 @@ -namespace Timeline.Models.Http +namespace Timeline { /// /// All error code constants. @@ -36,9 +36,22 @@ } } - public static class UserCommon + public static class NotExist { - public const int NotExist = 1_001_0001; + public const int Default = 2_001_00_00; + public const int User = 2_001_00_01; + public const int Timeline = 2_001_00_02; + public const int TimelinePost = 2_001_00_03; + public const int TimelinePostData = 2_001_00_04; + } + + public static class Conflict + { + public const int Default = 2_002_00_00; + public const int User = 2_002_00_01; + public const int Timeline = 2_002_00_02; + public const int TimelinePost = 2_002_00_03; + public const int TimelinePostData = 2_002_00_04; } public static class TokenController @@ -52,7 +65,6 @@ public static class UserController { - public const int UsernameConflict = 1_102_01_01; public const int ChangePassword_BadOldPassword = 1_102_02_01; public const int ChangePermission_RootUser = 1_102_03_01; public const int Delete_RootUser = 1_102_04_01; @@ -67,11 +79,7 @@ public static class TimelineController { - public const int NameConflict = 1_104_01_01; - public const int NotExist = 1_104_02_01; public const int QueryRelateNotExist = 1_104_04_01; - public const int PostNotExist = 1_104_05_01; - public const int PostDataNotExist = 1_104_05_02; } public static class HighlightTimelineController diff --git a/BackEnd/Timeline/Filters/CatchEntityAlreadyExistExceptionFilter.cs b/BackEnd/Timeline/Filters/CatchEntityAlreadyExistExceptionFilter.cs new file mode 100644 index 00000000..67b260d2 --- /dev/null +++ b/BackEnd/Timeline/Filters/CatchEntityAlreadyExistExceptionFilter.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Timeline.Models.Http; +using Timeline.Services; + +namespace Timeline.Filters +{ + public class CatchEntityAlreadyExistExceptionFilter : IExceptionFilter + { + private static string MakeMessage(EntityAlreadyExistException e) + { + return string.Format(Resource.MessageEntityAlreadyExist, e.EntityType.Name, e.GenerateConstraintString()); + } + + private static CommonResponse MakeCommonResponse(EntityAlreadyExistException e) + { + return new CommonResponse(e.EntityType.ConflictErrorCode, MakeMessage(e)); + } + + public void OnException(ExceptionContext context) + { + if (context.Exception is EntityAlreadyExistException e) + { + context.Result = new BadRequestObjectResult(MakeCommonResponse(e)); + } + } + } +} diff --git a/BackEnd/Timeline/Filters/CatchEntityNotExistExceptionFilter.cs b/BackEnd/Timeline/Filters/CatchEntityNotExistExceptionFilter.cs new file mode 100644 index 00000000..225fab4f --- /dev/null +++ b/BackEnd/Timeline/Filters/CatchEntityNotExistExceptionFilter.cs @@ -0,0 +1,40 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Timeline.Models.Http; +using Timeline.Services; + +namespace Timeline.Filters +{ + public class CatchEntityNotExistExceptionFilter : IExceptionFilter + { + private static string MakeMessage(EntityNotExistException e) + { + return string.Format(Resource.MessageEntityNotExist, e.EntityType.Name, e.GenerateConstraintString()); + } + + private static CommonResponse MakeCommonResponse(EntityNotExistException e) + { + return new CommonResponse(e.EntityType.NotExistErrorCode, MakeMessage(e)); + } + + public void OnException(ExceptionContext context) + { + if (context.Exception is EntityNotExistException e) + { + if (HttpMethods.IsGet(context.HttpContext.Request.Method)) + { + context.Result = new NotFoundObjectResult(MakeCommonResponse(e)); + } + else if (HttpMethods.IsDelete(context.HttpContext.Request.Method)) + { + context.Result = new OkObjectResult(CommonDeleteResponse.NotExist()); + } + else + { + context.Result = new BadRequestObjectResult(MakeCommonResponse(e)); + } + } + } + } +} diff --git a/BackEnd/Timeline/Filters/CatchTimelineNotExistExceptionAttribute.cs b/BackEnd/Timeline/Filters/CatchTimelineNotExistExceptionAttribute.cs deleted file mode 100644 index 7a1352a3..00000000 --- a/BackEnd/Timeline/Filters/CatchTimelineNotExistExceptionAttribute.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Timeline.Models.Http; -using Timeline.Services.Timeline; -using Timeline.Services.User; - -namespace Timeline.Filters -{ - public class CatchTimelineNotExistExceptionAttribute : ExceptionFilterAttribute - { - public override void OnException(ExceptionContext context) - { - if (context.Exception is TimelineNotExistException e) - { - if (e.InnerException is UserNotExistException) - { - if (HttpMethods.IsGet(context.HttpContext.Request.Method)) - context.Result = new NotFoundObjectResult(ErrorResponse.UserCommon.NotExist()); - else - context.Result = new BadRequestObjectResult(ErrorResponse.UserCommon.NotExist()); - } - else - { - if (HttpMethods.IsGet(context.HttpContext.Request.Method)) - context.Result = new NotFoundObjectResult(ErrorResponse.TimelineController.NotExist()); - else - context.Result = new BadRequestObjectResult(ErrorResponse.TimelineController.NotExist()); - } - } - } - } -} diff --git a/BackEnd/Timeline/Filters/CatchTimelinePostDataNotExistExceptionAttribute.cs b/BackEnd/Timeline/Filters/CatchTimelinePostDataNotExistExceptionAttribute.cs deleted file mode 100644 index b4046c58..00000000 --- a/BackEnd/Timeline/Filters/CatchTimelinePostDataNotExistExceptionAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Timeline.Models.Http; -using Timeline.Services.Timeline; - -namespace Timeline.Filters -{ - public class CatchTimelinePostDataNotExistExceptionAttribute : ExceptionFilterAttribute - { - public override void OnException(ExceptionContext context) - { - const string message = "Timeline post data does not exist."; - - if (context.Exception is TimelinePostDataNotExistException e) - { - if (HttpMethods.IsGet(context.HttpContext.Request.Method)) - context.Result = new NotFoundObjectResult(new CommonResponse(ErrorCodes.TimelineController.PostNotExist, message)); - else - context.Result = new BadRequestObjectResult(new CommonResponse(ErrorCodes.TimelineController.PostNotExist, message)); - } - } - } -} diff --git a/BackEnd/Timeline/Filters/CatchTimelinePostNotExistExceptionAttribute.cs b/BackEnd/Timeline/Filters/CatchTimelinePostNotExistExceptionAttribute.cs deleted file mode 100644 index a288f890..00000000 --- a/BackEnd/Timeline/Filters/CatchTimelinePostNotExistExceptionAttribute.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using Timeline.Models.Http; -using Timeline.Services.Timeline; - -namespace Timeline.Filters -{ - public class CatchTimelinePostNotExistExceptionAttribute : ExceptionFilterAttribute - { - public override void OnException(ExceptionContext context) - { - const string message = "Timeline post does not exist."; - - if (context.Exception is TimelinePostNotExistException e) - { - if (HttpMethods.IsGet(context.HttpContext.Request.Method)) - context.Result = new NotFoundObjectResult(new CommonResponse(ErrorCodes.TimelineController.PostNotExist, message)); - else - context.Result = new BadRequestObjectResult(new CommonResponse(ErrorCodes.TimelineController.PostNotExist, message)); - } - } - } -} diff --git a/BackEnd/Timeline/Filters/Resource.Designer.cs b/BackEnd/Timeline/Filters/Resource.Designer.cs new file mode 100644 index 00000000..8ae6d288 --- /dev/null +++ b/BackEnd/Timeline/Filters/Resource.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Timeline.Filters { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resource() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Filters.Resource", typeof(Resource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to The entity you want to create already exists. Entity type is {0}. Constraints are {1}.. + /// + internal static string MessageEntityAlreadyExist { + get { + return ResourceManager.GetString("MessageEntityAlreadyExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The entity you operate on does not exist. Entity type is {0}. Constraints are {1}.. + /// + internal static string MessageEntityNotExist { + get { + return ResourceManager.GetString("MessageEntityNotExist", resourceCulture); + } + } + } +} diff --git a/BackEnd/Timeline/Filters/Resource.resx b/BackEnd/Timeline/Filters/Resource.resx new file mode 100644 index 00000000..e9a5fbf9 --- /dev/null +++ b/BackEnd/Timeline/Filters/Resource.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + The entity you want to create already exists. Entity type is {0}. Constraints are {1}. + + + The entity you operate on does not exist. Entity type is {0}. Constraints are {1}. + + \ No newline at end of file diff --git a/BackEnd/Timeline/Models/Http/ErrorResponse.cs b/BackEnd/Timeline/Models/Http/ErrorResponse.cs index 3812471d..7ab520a7 100644 --- a/BackEnd/Timeline/Models/Http/ErrorResponse.cs +++ b/BackEnd/Timeline/Models/Http/ErrorResponse.cs @@ -66,20 +66,6 @@ namespace Timeline.Models.Http } - public static class UserCommon - { - public static CommonResponse NotExist(params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.UserCommon.NotExist, string.Format(UserCommon_NotExist, formatArgs)); - } - - public static CommonResponse CustomMessage_NotExist(string message, params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.UserCommon.NotExist, string.Format(message, formatArgs)); - } - - } - public static class TokenController { public static CommonResponse Create_BadCredential(params object?[] formatArgs) @@ -136,16 +122,6 @@ namespace Timeline.Models.Http public static class UserController { - public static CommonResponse UsernameConflict(params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.UserController.UsernameConflict, string.Format(UserController_UsernameConflict, formatArgs)); - } - - public static CommonResponse CustomMessage_UsernameConflict(string message, params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.UserController.UsernameConflict, string.Format(message, formatArgs)); - } - public static CommonResponse ChangePassword_BadOldPassword(params object?[] formatArgs) { return new CommonResponse(ErrorCodes.UserController.ChangePassword_BadOldPassword, string.Format(UserController_ChangePassword_BadOldPassword, formatArgs)); @@ -214,26 +190,6 @@ namespace Timeline.Models.Http public static class TimelineController { - public static CommonResponse NameConflict(params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.TimelineController.NameConflict, string.Format(TimelineController_NameConflict, formatArgs)); - } - - public static CommonResponse CustomMessage_NameConflict(string message, params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.TimelineController.NameConflict, string.Format(message, formatArgs)); - } - - public static CommonResponse NotExist(params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.TimelineController.NotExist, string.Format(TimelineController_NotExist, formatArgs)); - } - - public static CommonResponse CustomMessage_NotExist(string message, params object?[] formatArgs) - { - return new CommonResponse(ErrorCodes.TimelineController.NotExist, string.Format(message, formatArgs)); - } - public static CommonResponse QueryRelateNotExist(params object?[] formatArgs) { return new CommonResponse(ErrorCodes.TimelineController.QueryRelateNotExist, string.Format(TimelineController_QueryRelateNotExist, formatArgs)); @@ -246,12 +202,12 @@ namespace Timeline.Models.Http public static CommonResponse PostNotExist(params object?[] formatArgs) { - return new CommonResponse(ErrorCodes.TimelineController.PostNotExist, string.Format(TimelineController_PostNotExist, formatArgs)); + return new CommonResponse(ErrorCodes.NotExist.TimelinePost, string.Format(TimelineController_PostNotExist, formatArgs)); } public static CommonResponse CustomMessage_PostNotExist(string message, params object?[] formatArgs) { - return new CommonResponse(ErrorCodes.TimelineController.PostNotExist, string.Format(message, formatArgs)); + return new CommonResponse(ErrorCodes.NotExist.TimelinePost, string.Format(message, formatArgs)); } } diff --git a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs index 4fc20ecb..de70a9db 100644 --- a/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/BookmarkTimelineService.cs @@ -24,11 +24,8 @@ namespace Timeline.Services.Api public async Task 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; @@ -46,8 +43,7 @@ namespace Timeline.Services.Api public async Task> 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(); @@ -56,22 +52,19 @@ namespace Timeline.Services.Api public async Task 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 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); @@ -109,11 +102,8 @@ namespace Timeline.Services.Api public async Task 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 a9d831ab..d4367e57 100644 --- a/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/HighlightTimelineService.cs @@ -25,12 +25,11 @@ namespace Timeline.Services.Api public async Task 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); @@ -51,12 +50,11 @@ namespace Timeline.Services.Api public async Task 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); @@ -79,8 +77,7 @@ namespace Timeline.Services.Api 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); @@ -118,8 +115,8 @@ namespace Timeline.Services.Api public async Task 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 index 18feee54..63b4affa 100644 --- a/BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/IBookmarkTimelineService.cs @@ -15,7 +15,7 @@ namespace Timeline.Services.Api /// /// User id of bookmark owner. /// Id of Bookmark timelines in order. - /// Thrown when user does not exist. + /// Thrown when user does not exist. Task> GetBookmarksAsync(long userId); /// @@ -26,8 +26,8 @@ namespace Timeline.Services.Api /// If true it will throw when user does not exist. /// If true it will throw when timeline does not exist. /// True if timeline is a bookmark. Otherwise false. - /// Throw if user does not exist and is true. - /// Thrown if timeline does not exist and is true. + /// Throw if user does not exist and is true. + /// Thrown if timeline does not exist and is true. Task IsBookmarkAsync(long userId, long timelineId, bool checkUserExistence = true, bool checkTimelineExistence = true); /// @@ -36,8 +36,8 @@ namespace Timeline.Services.Api /// User id of bookmark owner. /// Timeline id. /// True if timeline is added to bookmark. False if it already is. - /// Thrown when user does not exist. - /// Thrown when timeline does not exist. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. Task AddBookmarkAsync(long userId, long timelineId); /// @@ -46,8 +46,8 @@ namespace Timeline.Services.Api /// User id of bookmark owner. /// Timeline id. /// True if deletion is performed. False if bookmark does not exist. - /// Thrown when user does not exist. - /// Thrown when timeline does not exist. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. Task RemoveBookmarkAsync(long userId, long timelineId); /// @@ -56,8 +56,8 @@ namespace Timeline.Services.Api /// User id of bookmark owner. /// Timeline name. /// New position. Starts at 1. - /// Thrown when user does not exist. - /// Thrown when timeline does not exist. + /// Thrown when user does not exist. + /// Thrown when timeline does not exist. /// Thrown when the timeline is not a bookmark. Task MoveBookmarkAsync(long userId, long timelineId, long newPosition); } diff --git a/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs b/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs index 4f14d19b..2e488778 100644 --- a/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs +++ b/BackEnd/Timeline/Services/Api/IHighlightTimelineService.cs @@ -22,7 +22,7 @@ namespace Timeline.Services.Api /// Timeline id. /// If true it will throw if timeline does not exist. /// True if timeline is highlight. Otherwise false. - /// Thrown when timeline does not exist and is true. + /// Thrown when timeline does not exist and is true. Task IsHighlightTimelineAsync(long timelineId, bool checkTimelineExistence = true); /// @@ -31,8 +31,8 @@ namespace Timeline.Services.Api /// The timeline id. /// The user id of operator. /// True if timeline is actually added to highligh. False if it already is. - /// Thrown when timeline with given id does not exist. - /// Thrown when user with given operator id does not exist. + /// Thrown when timeline with given id does not exist. + /// Thrown when user with given operator id does not exist. Task AddHighlightTimelineAsync(long timelineId, long? operatorId); /// @@ -41,8 +41,8 @@ namespace Timeline.Services.Api /// The timeline id. /// The user id of operator. /// True if deletion is actually performed. Otherwise false (timeline was not in the list). - /// Thrown when timeline with given id does not exist. - /// Thrown when user with given operator id does not exist. + /// Thrown when timeline with given id does not exist. + /// Thrown when user with given operator id does not exist. Task RemoveHighlightTimelineAsync(long timelineId, long? operatorId); /// @@ -50,7 +50,7 @@ namespace Timeline.Services.Api /// /// The timeline name. /// The new position. Starts at 1. - /// Thrown when timeline with given id does not exist. + /// Thrown when timeline with given id does not exist. /// Thrown when given timeline is not a highlight timeline. /// /// If is smaller than 1. Then move the timeline to head. 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. /// [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 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 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 Constraints { get; } = new Dictionary(); + + 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. /// [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 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/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 + { + ["name"] = name + }, null, inner); + } + + protected static EntityNotExistException CreateTimelineNotExistException(long id) + { + return new EntityNotExistException(EntityTypes.Timeline, new Dictionary + { + ["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 { ["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 /// Id of the timeline. /// Thrown when is null. /// Throw when is of bad format. - /// + /// /// Thrown when timeline with name does not exist. - /// If it is a personal timeline, then inner exception is . /// - /// - /// 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, will be thrown with as inner exception. - /// Task 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 /// The time that posts have been modified since. /// Whether include deleted posts. /// A list of all posts. - /// Thrown when timeline does not exist. + /// Thrown when timeline does not exist. Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false); /// @@ -28,8 +27,8 @@ namespace Timeline.Services.Timeline /// The id of the post. /// If true, return the entity even if it is deleted. /// The post. - /// Thrown when timeline does not exist. - /// Thrown when post of does not exist or has been deleted. + /// Thrown when timeline does not exist. + /// Thrown when post of does not exist or has been deleted. Task GetPostAsync(long timelineId, long postId, bool includeDeleted = false); /// @@ -39,9 +38,9 @@ namespace Timeline.Services.Timeline /// The post id. /// The index of the data. /// The data digest. - /// Thrown when timeline does not exist. - /// Thrown when post of does not exist or has been deleted. - /// Thrown when data of that index does not exist. + /// Thrown when timeline does not exist. + /// Thrown when post of does not exist or has been deleted. + /// Thrown when data of that index does not exist. Task GetPostDataDigestAsync(long timelineId, long postId, long dataIndex); /// @@ -51,9 +50,9 @@ namespace Timeline.Services.Timeline /// The post id. /// The index of the data. /// The data. - /// Thrown when timeline does not exist. - /// Thrown when post of does not exist or has been deleted. - /// Thrown when data of that index does not exist. + /// Thrown when timeline does not exist. + /// Thrown when post of does not exist or has been deleted. + /// Thrown when data of that index does not exist. Task GetPostDataAsync(long timelineId, long postId, long dataIndex); /// @@ -65,8 +64,8 @@ namespace Timeline.Services.Timeline /// The entity of the created post. /// Thrown when is null. /// Thrown when is of invalid format. - /// Thrown when timeline does not exist. - /// Thrown if user of does not exist. + /// Thrown when timeline does not exist. + /// Thrown if user of does not exist. /// Thrown if data is not a image. Validated by . Task CreatePostAsync(long timelineId, long authorId, TimelinePostCreateRequest request); @@ -79,8 +78,8 @@ namespace Timeline.Services.Timeline /// The entity of the patched post. /// Thrown when is null. /// Thrown when is of invalid format. - /// Thrown when timeline does not exist. - /// Thrown when post does not exist. + /// Thrown when timeline does not exist. + /// Thrown when post does not exist. Task PatchPostAsync(long timelineId, long postId, TimelinePostPatchRequest request); /// @@ -88,8 +87,8 @@ namespace Timeline.Services.Timeline /// /// The id of the timeline to delete post against. /// The id of the post to delete. - /// Thrown when timeline does not exist. - /// Thrown when the post with given id does not exist or is deleted already. + /// Thrown when timeline does not exist. + /// Thrown when the post with given id does not exist or is deleted already. /// /// First use to check the permission. /// @@ -107,10 +106,10 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The id of the post. /// The id of the user to check on. - /// True if you want it to throw . Default false. + /// True if you want it to throw . Default false. /// True if can modify, false if can't modify. - /// Thrown when timeline does not exist. - /// Thrown when the post with given id does not exist or is deleted already and is true. + /// Thrown when timeline does not exist. + /// Thrown when the post with given id does not exist or is deleted already and is true. /// /// Unless 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 is true. diff --git a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs index 9c313b0b..b371e9e0 100644 --- a/BackEnd/Timeline/Services/Timeline/ITimelineService.cs +++ b/BackEnd/Timeline/Services/Timeline/ITimelineService.cs @@ -17,7 +17,7 @@ namespace Timeline.Services.Timeline /// /// Id of timeline. /// The timeline info. - /// Thrown when timeline does not exist. + /// Thrown when timeline does not exist. Task GetTimelineAsync(long id); /// @@ -26,7 +26,7 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The new properties. Null member means not to change. /// Thrown when is null. - /// Thrown when timeline with given id does not exist. + /// Thrown when timeline with given id does not exist. /// Thrown when a timeline with new name already exists. Task ChangePropertyAsync(long id, TimelineChangePropertyParams newProperties); @@ -36,8 +36,8 @@ namespace Timeline.Services.Timeline /// Timeline id. /// User id. /// True if the memeber was added. False if it is already a member. - /// Thrown when timeline does not exist. - /// Thrown when the user does not exist. + /// Thrown when timeline does not exist. + /// Thrown when the user does not exist. Task AddMemberAsync(long timelineId, long userId); /// @@ -46,8 +46,8 @@ namespace Timeline.Services.Timeline /// Timeline id. /// User id. /// True if the memeber was removed. False if it was not a member before. - /// Thrown when timeline does not exist. - /// Thrown when the user does not exist. + /// Thrown when timeline does not exist. + /// Thrown when the user does not exist. Task RemoveMemberAsync(long timelineId, long userId); /// @@ -56,7 +56,7 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The id of the user to check on. /// True if the user can manage the timeline, otherwise false. - /// Thrown when timeline does not exist. + /// Thrown when timeline does not exist. /// /// This method does not check whether visitor is administrator. /// Return false if user with user id does not exist. @@ -69,7 +69,7 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The id of the user to check on. Null means visitor without account. /// True if can read, false if can't read. - /// Thrown when timeline does not exist. + /// Thrown when timeline does not exist. /// /// This method does not check whether visitor is administrator. /// Return false if user with visitor id does not exist. @@ -82,7 +82,7 @@ namespace Timeline.Services.Timeline /// The id of the timeline. /// The id of user to check on. /// True if it is a member, false if not. - /// Thrown when timeline does not exist. + /// Thrown when timeline does not exist. /// /// Timeline owner is also considered as a member. /// Return false when user with user id does not exist. @@ -109,14 +109,14 @@ namespace Timeline.Services.Timeline /// Thrown when is null. /// Thrown when timeline name is invalid. /// Thrown when the timeline already exists. - /// Thrown when the owner user does not exist. + /// Thrown when the owner user does not exist. Task CreateTimelineAsync(string timelineName, long ownerId); /// /// Delete a timeline. /// /// The id of the timeline to delete. - /// Thrown when the timeline does not exist. + /// Thrown when the timeline does not exist. Task DeleteTimelineAsync(long id); } } 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 -{ - /// - /// The user requested does not exist. - /// - [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; } - - /// - /// True if the post is deleted. False if the post does not exist at all. - /// - public bool IsDelete { get; set; } - } -} diff --git a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs index a9bb7bd1..a0961a8d 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelinePostService.cs @@ -38,27 +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 + { + ["timeline-id"] = timelineId, + ["post-id"] = postId, + ["deleted"] = deleted + }); } - private void CheckColor(string color, string paramName) + private static EntityNotExistException CreatePostDataNotExistException(long timelineId, long postId, long dataIndex) { - if (!_colorValidator.Validate(color, out var message)) - throw new ArgumentException(string.Format(Resource.ExceptionColorInvalid, message), paramName); + return new EntityNotExistException(EntityTypes.TimelinePost, new Dictionary + { + ["timeline-id"] = timelineId, + ["post-id"] = postId, + ["data-index"] = dataIndex + }); } public async Task> GetPostsAsync(long timelineId, DateTime? modifiedSince = null, bool includeDeleted = false) { - await CheckTimelineExistence(timelineId); + await _basicTimelineService.ThrowIfTimelineNotExist(timelineId); modifiedSince = modifiedSince?.MyToUtc(); @@ -81,18 +89,18 @@ namespace Timeline.Services.Timeline public async Task 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; @@ -100,40 +108,40 @@ namespace Timeline.Services.Timeline public async Task 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 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."); @@ -194,8 +202,8 @@ namespace Timeline.Services.Timeline 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; @@ -253,15 +261,15 @@ namespace Timeline.Services.Timeline 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; @@ -279,15 +287,15 @@ namespace Timeline.Services.Timeline 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(); @@ -321,7 +329,7 @@ namespace Timeline.Services.Timeline public async Task 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(); @@ -330,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 bde0210a..920fcc74 100644 --- a/BackEnd/Timeline/Services/Timeline/TimelineService.cs +++ b/BackEnd/Timeline/Services/Timeline/TimelineService.cs @@ -34,6 +34,13 @@ namespace Timeline.Services.Timeline _clock = clock; } + private static EntityAlreadyExistException CreateTimelineConflictException(string name) + { + return new EntityAlreadyExistException(EntityTypes.Timeline, new Dictionary + { + ["name"] = name + }); + } private void CheckTimelineName(string name, string paramName) { @@ -48,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; } @@ -73,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; @@ -83,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; @@ -130,10 +137,9 @@ namespace Timeline.Services.Timeline public async Task 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; @@ -153,10 +159,9 @@ namespace Timeline.Services.Timeline public async Task 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; @@ -177,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; } @@ -187,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; @@ -211,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; @@ -266,7 +271,7 @@ namespace Timeline.Services.Timeline var conflict = await _database.Timelines.AnyAsync(t => t.Name == name); if (conflict) - throw new TimelineAlreadyExistException(); + throw CreateTimelineConflictException(name); var entity = CreateNewTimelineEntity(name, owner); @@ -282,7 +287,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); _database.Timelines.Remove(entity); await _database.SaveChangesAsync(); 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 /// The created token and the user info. /// Thrown when or is null. /// Thrown when is of bad format. - /// Thrown when the user with does not exist. + /// Thrown when the user with does not exist. /// Thrown when is wrong. public Task CreateTokenAsync(string username, string password, DateTime? expireAt = null); 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 /// /// User id. /// The avatar digest. - /// Thrown when user does not exist. + /// Thrown when user does not exist. Task GetAvatarDigestAsync(long userId); /// @@ -21,7 +21,7 @@ namespace Timeline.Services.User.Avatar /// /// User id. /// The avatar. - /// Thrown when user does not exist. + /// Thrown when user does not exist. Task GetAvatarAsync(long userId); /// @@ -31,7 +31,7 @@ namespace Timeline.Services.User.Avatar /// The new avatar data. /// The digest of the avatar. /// Thrown if is null. - /// Thrown when user does not exist. + /// Thrown when user does not exist. /// Thrown if avatar is of bad format. Task SetAvatarAsync(long userId, ByteData avatar); @@ -39,7 +39,7 @@ namespace Timeline.Services.User.Avatar /// Remove avatar of a user. /// /// User id. - /// Thrown when user does not exist. + /// Thrown when user does not exist. 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 { ["username"] = username }); + } + + protected static EntityNotExistException CreateUserNotExistException(long id) + { + return new EntityNotExistException(EntityTypes.User, + new Dictionary { ["id"] = id }); + } + public async Task 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 { ["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 /// The id of the user. /// Thrown when is null. /// Thrown when is of bad format. - /// Thrown when the user with given username does not exist. + /// Thrown when the user with given username does not exist. Task GetUserIdByUsernameAsync(string username); /// @@ -30,7 +30,7 @@ namespace Timeline.Services.User /// /// User id. /// The time. - /// Thrown when user does not exist. + /// Thrown when user does not exist. Task 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 /// The id of the user. /// Whether check the user's existence. /// The permission list. - /// Thrown when is true and user does not exist. + /// Thrown when is true and user does not exist. Task GetPermissionsOfUserAsync(long userId, bool checkUserExistence = true); /// @@ -18,7 +18,7 @@ namespace Timeline.Services.User /// /// The id of the user. /// The new permission. - /// Thrown when user does not exist. + /// Thrown when user does not exist. /// Thrown when change root user's permission. Task AddPermissionToUserAsync(long userId, UserPermission permission); @@ -28,7 +28,7 @@ namespace Timeline.Services.User /// The id of the user. /// The permission. /// Whether check the user's existence. - /// Thrown when is true and user does not exist. + /// Thrown when is true and user does not exist. /// Thrown when change root user's permission. 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 /// /// The id of the user. /// The user info. - /// Thrown when the user with given id does not exist. + /// Thrown when the user with given id does not exist. Task GetUserAsync(long id); /// @@ -38,7 +38,7 @@ namespace Timeline.Services.User /// The new information. /// The new user info. /// Thrown when some fields in is bad. - /// Thrown when user with given id does not exist. + /// Thrown when user with given id does not exist. /// /// Version will increase if password is changed. /// @@ -52,7 +52,7 @@ namespace Timeline.Services.User /// User id. /// Thrown when or is null. /// Thrown when is of bad format or is empty. - /// Thrown when the user with given username does not exist. + /// Thrown when the user with given username does not exist. /// Thrown when password is wrong. Task VerifyCredential(string username, string password); @@ -64,7 +64,7 @@ namespace Timeline.Services.User /// New password. /// Thrown if or is null. /// Thrown if or is empty. - /// Thrown if the user with given username does not exist. + /// Thrown if the user with given username does not exist. /// Thrown if the old password is wrong. 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 -{ - /// - /// The user requested does not exist. - /// - [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 -{ - /// - /// The user requested does not exist. - /// - [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) { } - - /// - /// The username of the user that does not exist. - /// - public string? Username { get; set; } - - /// - /// The id of the user that does not exist. - /// - 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 { ["username"] = username }); } public async Task 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); diff --git a/BackEnd/Timeline/Startup.cs b/BackEnd/Timeline/Startup.cs index 994dd7bf..812bf317 100644 --- a/BackEnd/Timeline/Startup.cs +++ b/BackEnd/Timeline/Startup.cs @@ -12,8 +12,10 @@ using System.Text.Json.Serialization; using Timeline.Auth; using Timeline.Configs; using Timeline.Entities; +using Timeline.Filters; using Timeline.Formatters; using Timeline.Helpers; +using Timeline.Models; using Timeline.Models.Converters; using Timeline.Routes; using Timeline.Services; @@ -66,8 +68,10 @@ namespace Timeline { setup.InputFormatters.Add(new StringInputFormatter()); setup.InputFormatters.Add(new ByteDataInputFormatter()); - setup.Filters.Add(new ConsumesAttribute(MediaTypeNames.Application.Json, "text/json")); - setup.Filters.Add(new ProducesAttribute(MediaTypeNames.Application.Json, "text/json")); + setup.Filters.Add(new ConsumesAttribute(MimeTypes.ApplicationJson, MimeTypes.TextJson)); + setup.Filters.Add(new ProducesAttribute(MimeTypes.ApplicationJson, MimeTypes.TextJson)); + setup.Filters.Add(); + setup.Filters.Add(); setup.UseApiRoutePrefix("api"); }) .AddJsonOptions(options => diff --git a/BackEnd/Timeline/Timeline.csproj b/BackEnd/Timeline/Timeline.csproj index ace1aab5..b151d123 100644 --- a/BackEnd/Timeline/Timeline.csproj +++ b/BackEnd/Timeline/Timeline.csproj @@ -58,6 +58,11 @@ True Resource.resx + + True + True + Resource.resx + True True @@ -159,6 +164,10 @@ ResXFileCodeGenerator Resource.Designer.cs + + ResXFileCodeGenerator + Resource.Designer.cs + ResXFileCodeGenerator Entities.Designer.cs -- cgit v1.2.3