diff options
author | 杨宇千 <crupest@outlook.com> | 2019-08-05 18:58:56 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-08-05 18:58:56 +0800 |
commit | dc1ab11cea249f4ca967f86b115147a63f7c93a5 (patch) | |
tree | b5f26eabcfa547e76dd7e70ffe0763f3fadf0ad5 /Timeline | |
parent | 5f5458518df0475fa36af754cae52eb31eb92fa3 (diff) | |
download | timeline-dc1ab11cea249f4ca967f86b115147a63f7c93a5.tar.gz timeline-dc1ab11cea249f4ca967f86b115147a63f7c93a5.tar.bz2 timeline-dc1ab11cea249f4ca967f86b115147a63f7c93a5.zip |
3 things.
1. Exchange Models and Entities namespace.
2. Fix the bug that input with missing field leads to 500.
3. Write unit tests.
Diffstat (limited to 'Timeline')
20 files changed, 85 insertions, 38 deletions
diff --git a/Timeline/Authenticate/Attribute.cs b/Timeline/Authenticate/Attribute.cs index 50b2681d..645eb236 100644 --- a/Timeline/Authenticate/Attribute.cs +++ b/Timeline/Authenticate/Attribute.cs @@ -1,5 +1,5 @@ using Microsoft.AspNetCore.Authorization; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Authenticate { diff --git a/Timeline/Authenticate/AuthHandler.cs b/Timeline/Authenticate/AuthHandler.cs index 41cb11c6..41d05831 100644 --- a/Timeline/Authenticate/AuthHandler.cs +++ b/Timeline/Authenticate/AuthHandler.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; using System.Threading.Tasks; +using Timeline.Models; using Timeline.Services; namespace Timeline.Authenticate @@ -80,7 +81,7 @@ namespace Timeline.Authenticate var identity = new ClaimsIdentity(AuthConstants.Scheme); identity.AddClaim(new Claim(identity.NameClaimType, userInfo.Username, ClaimValueTypes.String)); - identity.AddClaims(Entities.UserUtility.IsAdminToRoleArray(userInfo.Administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String))); + identity.AddClaims(UserUtility.IsAdminToRoleArray(userInfo.Administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String))); var principal = new ClaimsPrincipal(); principal.AddIdentity(identity); diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 549e227b..57407558 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -5,13 +5,14 @@ using Microsoft.IdentityModel.Tokens; using System; using System.Collections.Generic;
using System.Threading.Tasks; -using Timeline.Entities.Http; +using Timeline.Models.Http; using Timeline.Services; using static Timeline.Helpers.MyLogHelper; namespace Timeline.Controllers { [Route("token")] + [ApiController] public class TokenController : Controller { private static class LoggingEventIds @@ -60,22 +61,9 @@ namespace Timeline.Controllers Pair("Expire Offset (in days)", request.ExpireOffset)));
} - TimeSpan? expireOffset = null; - if (request.ExpireOffset != null) - { - if (request.ExpireOffset.Value <= 0.0) - { - const string message = "Expire time is not bigger than 0."; - var code = ErrorCodes.Create_BadExpireOffset; - LogFailure(message, code); - return BadRequest(new CommonResponse(code, message)); - } - expireOffset = TimeSpan.FromDays(request.ExpireOffset.Value); - } - try { - var expiredTime = expireOffset == null ? null : (DateTime?)(_clock.GetCurrentTime() + expireOffset.Value); + var expiredTime = request.ExpireOffset == null ? null : (DateTime?)(_clock.GetCurrentTime().AddDays(request.ExpireOffset.Value)); var result = await _userService.CreateToken(request.Username, request.Password, expiredTime); _logger.LogInformation(LoggingEventIds.CreateSucceeded, FormatLogMessage("Attemp to login succeeded.",
Pair("Username", request.Username),
diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 2099690c..042a8107 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -4,13 +4,14 @@ using Microsoft.Extensions.Logging; using System; using System.Threading.Tasks; using Timeline.Authenticate; -using Timeline.Entities; -using Timeline.Entities.Http; +using Timeline.Models; +using Timeline.Models.Http; using Timeline.Services; using static Timeline.Helpers.MyLogHelper; namespace Timeline.Controllers { + [ApiController] public class UserController : Controller { private static class ErrorCodes diff --git a/Timeline/Controllers/UserTestController.cs b/Timeline/Controllers/UserTestController.cs index 21686b81..a81f42a8 100644 --- a/Timeline/Controllers/UserTestController.cs +++ b/Timeline/Controllers/UserTestController.cs @@ -5,6 +5,7 @@ using Timeline.Authenticate; namespace Timeline.Controllers { [Route("Test/User")] + [ApiController] public class UserTestController : Controller { [HttpGet("[action]")] diff --git a/Timeline/Models/DatabaseContext.cs b/Timeline/Entities/DatabaseContext.cs index afd5a333..9fe046ac 100644 --- a/Timeline/Models/DatabaseContext.cs +++ b/Timeline/Entities/DatabaseContext.cs @@ -2,7 +2,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -namespace Timeline.Models +namespace Timeline.Entities { public static class UserRoles { diff --git a/Timeline/Helpers/InvalidModelResponseFactory.cs b/Timeline/Helpers/InvalidModelResponseFactory.cs new file mode 100644 index 00000000..e5c87d9e --- /dev/null +++ b/Timeline/Helpers/InvalidModelResponseFactory.cs @@ -0,0 +1,25 @@ +using Microsoft.AspNetCore.Mvc;
+using System.Text;
+using Timeline.Models.Http;
+
+namespace Timeline.Helpers
+{
+ public static class InvalidModelResponseFactory
+ {
+ public static IActionResult Factory(ActionContext context)
+ {
+ var modelState = context.ModelState;
+
+ var messageBuilder = new StringBuilder();
+ foreach (var model in modelState)
+ foreach (var error in model.Value.Errors)
+ {
+ messageBuilder.Append(model.Key);
+ messageBuilder.Append(" : ");
+ messageBuilder.AppendLine(error.ErrorMessage);
+ }
+
+ return new BadRequestObjectResult(CommonResponse.InvalidModel(messageBuilder.ToString()));
+ }
+ }
+}
diff --git a/Timeline/Migrations/20190412102517_InitCreate.Designer.cs b/Timeline/Migrations/20190412102517_InitCreate.Designer.cs index c68183de..1e4a4115 100644 --- a/Timeline/Migrations/20190412102517_InitCreate.Designer.cs +++ b/Timeline/Migrations/20190412102517_InitCreate.Designer.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Migrations { diff --git a/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs b/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs index 319c646a..12a6fb77 100644 --- a/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs +++ b/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Migrations { diff --git a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs index c1d1565f..a2644feb 100644 --- a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs +++ b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Migrations { diff --git a/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs b/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs index 42eeeb40..7402b082 100644 --- a/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs +++ b/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs @@ -3,7 +3,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Migrations { diff --git a/Timeline/Migrations/DatabaseContextModelSnapshot.cs b/Timeline/Migrations/DatabaseContextModelSnapshot.cs index 7d244969..be8b3e9f 100644 --- a/Timeline/Migrations/DatabaseContextModelSnapshot.cs +++ b/Timeline/Migrations/DatabaseContextModelSnapshot.cs @@ -2,7 +2,7 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; +using Timeline.Entities; namespace Timeline.Migrations { diff --git a/Timeline/Entities/Http/Common.cs b/Timeline/Models/Http/Common.cs index 3a45a0ae..74959088 100644 --- a/Timeline/Entities/Http/Common.cs +++ b/Timeline/Models/Http/Common.cs @@ -1,7 +1,21 @@ -namespace Timeline.Entities.Http +namespace Timeline.Models.Http { public class CommonResponse - { + {
+ public static class ErrorCodes
+ {
+ /// <summary>
+ /// Used when the model is invaid.
+ /// For example a required field is null.
+ /// </summary>
+ public const int InvalidModel = -100;
+ } +
+ public static CommonResponse InvalidModel(string message)
+ {
+ return new CommonResponse(ErrorCodes.InvalidModel, message);
+ } + public CommonResponse() { diff --git a/Timeline/Entities/Http/Token.cs b/Timeline/Models/Http/Token.cs index 8a02ed2e..cef679ef 100644 --- a/Timeline/Entities/Http/Token.cs +++ b/Timeline/Models/Http/Token.cs @@ -1,11 +1,16 @@ -namespace Timeline.Entities.Http +using System.ComponentModel.DataAnnotations;
+
+namespace Timeline.Models.Http { public class CreateTokenRequest { + [Required] public string Username { get; set; } + [Required] public string Password { get; set; } - // in day - public double? ExpireOffset { get; set; } + // in days, optional + [Range(1, 365)] + public int? ExpireOffset { get; set; } } public class CreateTokenResponse @@ -16,6 +21,7 @@ public class VerifyTokenRequest { + [Required] public string Token { get; set; } } diff --git a/Timeline/Entities/Http/User.cs b/Timeline/Models/Http/User.cs index b5384778..1de7fae2 100644 --- a/Timeline/Entities/Http/User.cs +++ b/Timeline/Models/Http/User.cs @@ -1,8 +1,12 @@ -namespace Timeline.Entities.Http +using System.ComponentModel.DataAnnotations;
+
+namespace Timeline.Models.Http { public class UserPutRequest { + [Required] public string Password { get; set; } + [Required] public bool Administrator { get; set; } } @@ -14,7 +18,9 @@ public class ChangePasswordRequest { + [Required] public string OldPassword { get; set; } + [Required] public string NewPassword { get; set; } } } diff --git a/Timeline/Entities/PutResult.cs b/Timeline/Models/PutResult.cs index 4ed48572..f11ac138 100644 --- a/Timeline/Entities/PutResult.cs +++ b/Timeline/Models/PutResult.cs @@ -1,4 +1,4 @@ -namespace Timeline.Entities +namespace Timeline.Models { /// <summary> /// Represents the result of a "put" operation. diff --git a/Timeline/Entities/UserInfo.cs b/Timeline/Models/UserInfo.cs index 414a8dfe..b5cb1e7f 100644 --- a/Timeline/Entities/UserInfo.cs +++ b/Timeline/Models/UserInfo.cs @@ -1,4 +1,4 @@ -namespace Timeline.Entities +namespace Timeline.Models { public sealed class UserInfo { diff --git a/Timeline/Entities/UserUtility.cs b/Timeline/Models/UserUtility.cs index 14cdb2d6..711e321a 100644 --- a/Timeline/Entities/UserUtility.cs +++ b/Timeline/Models/UserUtility.cs @@ -1,9 +1,9 @@ using System; using System.Linq; -using Timeline.Models; +using Timeline.Entities; using Timeline.Services; -namespace Timeline.Entities +namespace Timeline.Models { public static class UserUtility { diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 7fe7a2b6..28218612 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -6,8 +6,8 @@ using System.Linq; using System.Threading.Tasks;
using Timeline.Entities;
using Timeline.Models;
-using static Timeline.Entities.UserUtility;
using static Timeline.Helpers.MyLogHelper;
+using static Timeline.Models.UserUtility;
namespace Timeline.Services
{
diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 242e816d..e6a8f96f 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -8,7 +8,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Timeline.Authenticate; using Timeline.Configs; -using Timeline.Models; +using Timeline.Entities; +using Timeline.Helpers;
using Timeline.Services; namespace Timeline @@ -29,7 +30,11 @@ namespace Timeline // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); + services.AddMvc()
+ .ConfigureApiBehaviorOptions(options =>{
+ options.InvalidModelStateResponseFactory = InvalidModelResponseFactory.Factory;
+ })
+ .SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddCors(options => { |