From 29bd71cd93b03248254f341aff9252374abc74ec Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 7 Aug 2019 17:38:56 +0800 Subject: Add script to convert encoding and eof. And of course run it. --- .vscode/launch.json | 17 +- Timeline.Tests/AuthorizationUnitTest.cs | 136 +++++----- .../Authentication/AuthenticationExtensions.cs | 56 ++--- Timeline.Tests/Helpers/MyWebApplicationFactory.cs | 46 ++-- Timeline.Tests/Helpers/ResponseExtensions.cs | 28 +-- Timeline.Tests/Helpers/TestClock.cs | 2 +- Timeline.Tests/Helpers/TestUsers.cs | 84 +++---- Timeline.Tests/Helpers/UserInfoComparers.cs | 94 +++---- Timeline.Tests/Timeline.Tests.csproj | 2 +- Timeline.Tests/TokenUnitTest.cs | 2 +- Timeline.Tests/UserUnitTest.cs | 72 +++--- Timeline.sln | 61 +++-- Timeline/Authenticate/Attribute.cs | 42 ++-- Timeline/Authenticate/AuthHandler.cs | 202 +++++++-------- Timeline/Configs/DatabaseConfig.cs | 14 +- Timeline/Configs/JwtConfig.cs | 30 +-- Timeline/Controllers/TokenController.cs | 276 ++++++++++----------- Timeline/Controllers/UserController.cs | 250 +++++++++---------- Timeline/Controllers/UserTestController.cs | 62 ++--- Timeline/Entities/Http/Common.cs | 74 +++--- Timeline/Entities/Http/Token.cs | 52 ++-- Timeline/Entities/Http/User.cs | 40 +-- Timeline/Entities/PutResult.cs | 34 +-- Timeline/Entities/UserInfo.cs | 46 ++-- Timeline/Entities/UserUtility.cs | 120 ++++----- Timeline/Helpers/Log.cs | 2 +- .../20190412102517_InitCreate.Designer.cs | 86 +++---- Timeline/Migrations/20190412102517_InitCreate.cs | 64 ++--- .../20190412144150_AddAdminUser.Designer.cs | 86 +++---- Timeline/Migrations/20190412144150_AddAdminUser.cs | 38 +-- ...0412153003_MakeColumnsInUserNotNull.Designer.cs | 92 +++---- .../20190412153003_MakeColumnsInUserNotNull.cs | 104 ++++---- .../20190719115321_Add-User-Version.Designer.cs | 98 ++++---- .../Migrations/20190719115321_Add-User-Version.cs | 46 ++-- .../Migrations/DatabaseContextModelSnapshot.cs | 94 +++---- Timeline/Models/DatabaseContext.cs | 84 +++---- Timeline/Program.cs | 50 ++-- Timeline/Services/Clock.cs | 64 ++--- Timeline/Services/JwtService.cs | 2 +- Timeline/Services/PasswordService.cs | 2 +- Timeline/Startup.cs | 180 +++++++------- Timeline/Timeline.csproj | 32 +-- Timeline/appsettings.Development.json | 24 +- Timeline/appsettings.json | 22 +- nuget.config | 16 +- tools/convert-eol.py | 35 +++ 46 files changed, 1552 insertions(+), 1511 deletions(-) create mode 100644 tools/convert-eol.py diff --git a/.vscode/launch.json b/.vscode/launch.json index bb765851..74744083 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,9 +1,16 @@ { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": "Python: Current File", + "type": "python", + "request": "launch", + "program": "${file}", + "console": "integratedTerminal" + }, { "name": ".NET Core Launch (web)", "type": "coreclr", diff --git a/Timeline.Tests/AuthorizationUnitTest.cs b/Timeline.Tests/AuthorizationUnitTest.cs index a25a8f9b..8df23c45 100644 --- a/Timeline.Tests/AuthorizationUnitTest.cs +++ b/Timeline.Tests/AuthorizationUnitTest.cs @@ -1,68 +1,68 @@ -using Microsoft.AspNetCore.Mvc.Testing; -using System.Net; -using System.Threading.Tasks; -using Timeline.Tests.Helpers; -using Timeline.Tests.Helpers.Authentication; -using Xunit; -using Xunit.Abstractions; - -namespace Timeline.Tests -{ - public class AuthorizationUnitTest : IClassFixture> - { - private const string AuthorizeUrl = "Test/User/Authorize"; - private const string UserUrl = "Test/User/User"; - private const string AdminUrl = "Test/User/Admin"; - - private readonly WebApplicationFactory _factory; - - public AuthorizationUnitTest(MyWebApplicationFactory factory, ITestOutputHelper outputHelper) - { - _factory = factory.WithTestLogging(outputHelper); - } - - [Fact] - public async Task UnauthenticationTest() - { - using (var client = _factory.CreateDefaultClient()) - { - var response = await client.GetAsync(AuthorizeUrl); - Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); - } - } - - [Fact] - public async Task AuthenticationTest() - { - using (var client = await _factory.CreateClientWithUser("user", "user")) - { - var response = await client.GetAsync(AuthorizeUrl); - Assert.Equal(HttpStatusCode.OK, response.StatusCode); - } - } - - [Fact] - public async Task UserAuthorizationTest() - { - using (var client = await _factory.CreateClientWithUser("user", "user")) - { - var response1 = await client.GetAsync(UserUrl); - Assert.Equal(HttpStatusCode.OK, response1.StatusCode); - var response2 = await client.GetAsync(AdminUrl); - Assert.Equal(HttpStatusCode.Forbidden, response2.StatusCode); - } - } - - [Fact] - public async Task AdminAuthorizationTest() - { - using (var client = await _factory.CreateClientWithUser("admin", "admin")) - { - var response1 = await client.GetAsync(UserUrl); - Assert.Equal(HttpStatusCode.OK, response1.StatusCode); - var response2 = await client.GetAsync(AdminUrl); - Assert.Equal(HttpStatusCode.OK, response2.StatusCode); - } - } - } -} +using Microsoft.AspNetCore.Mvc.Testing; +using System.Net; +using System.Threading.Tasks; +using Timeline.Tests.Helpers; +using Timeline.Tests.Helpers.Authentication; +using Xunit; +using Xunit.Abstractions; + +namespace Timeline.Tests +{ + public class AuthorizationUnitTest : IClassFixture> + { + private const string AuthorizeUrl = "Test/User/Authorize"; + private const string UserUrl = "Test/User/User"; + private const string AdminUrl = "Test/User/Admin"; + + private readonly WebApplicationFactory _factory; + + public AuthorizationUnitTest(MyWebApplicationFactory factory, ITestOutputHelper outputHelper) + { + _factory = factory.WithTestLogging(outputHelper); + } + + [Fact] + public async Task UnauthenticationTest() + { + using (var client = _factory.CreateDefaultClient()) + { + var response = await client.GetAsync(AuthorizeUrl); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + } + } + + [Fact] + public async Task AuthenticationTest() + { + using (var client = await _factory.CreateClientWithUser("user", "user")) + { + var response = await client.GetAsync(AuthorizeUrl); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + } + + [Fact] + public async Task UserAuthorizationTest() + { + using (var client = await _factory.CreateClientWithUser("user", "user")) + { + var response1 = await client.GetAsync(UserUrl); + Assert.Equal(HttpStatusCode.OK, response1.StatusCode); + var response2 = await client.GetAsync(AdminUrl); + Assert.Equal(HttpStatusCode.Forbidden, response2.StatusCode); + } + } + + [Fact] + public async Task AdminAuthorizationTest() + { + using (var client = await _factory.CreateClientWithUser("admin", "admin")) + { + var response1 = await client.GetAsync(UserUrl); + Assert.Equal(HttpStatusCode.OK, response1.StatusCode); + var response2 = await client.GetAsync(AdminUrl); + Assert.Equal(HttpStatusCode.OK, response2.StatusCode); + } + } + } +} diff --git a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs index 27362ac3..c8bec266 100644 --- a/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs +++ b/Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs @@ -1,28 +1,28 @@ -using Microsoft.AspNetCore.Mvc.Testing; -using Newtonsoft.Json; -using System.Net.Http; -using System.Threading.Tasks; -using Timeline.Entities.Http; - -namespace Timeline.Tests.Helpers.Authentication -{ - public static class AuthenticationExtensions - { - private const string CreateTokenUrl = "/token/create"; - - public static async Task CreateUserTokenAsync(this HttpClient client, string username, string password, double? expireOffset = null) - { - var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, ExpireOffset = expireOffset }); - var result = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - return result; - } - - public static async Task CreateClientWithUser(this WebApplicationFactory factory, string username, string password) where T : class - { - var client = factory.CreateDefaultClient(); - var token = (await client.CreateUserTokenAsync(username, password)).Token; - client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); - return client; - } - } -} +using Microsoft.AspNetCore.Mvc.Testing; +using Newtonsoft.Json; +using System.Net.Http; +using System.Threading.Tasks; +using Timeline.Entities.Http; + +namespace Timeline.Tests.Helpers.Authentication +{ + public static class AuthenticationExtensions + { + private const string CreateTokenUrl = "/token/create"; + + public static async Task CreateUserTokenAsync(this HttpClient client, string username, string password, double? expireOffset = null) + { + var response = await client.PostAsJsonAsync(CreateTokenUrl, new CreateTokenRequest { Username = username, Password = password, ExpireOffset = expireOffset }); + var result = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + return result; + } + + public static async Task CreateClientWithUser(this WebApplicationFactory factory, string username, string password) where T : class + { + var client = factory.CreateDefaultClient(); + var token = (await client.CreateUserTokenAsync(username, password)).Token; + client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token); + return client; + } + } +} diff --git a/Timeline.Tests/Helpers/MyWebApplicationFactory.cs b/Timeline.Tests/Helpers/MyWebApplicationFactory.cs index 903cd670..d9503526 100644 --- a/Timeline.Tests/Helpers/MyWebApplicationFactory.cs +++ b/Timeline.Tests/Helpers/MyWebApplicationFactory.cs @@ -1,16 +1,16 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Timeline.Models; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Timeline.Models; using Timeline.Services; -using Xunit.Abstractions; - -namespace Timeline.Tests.Helpers -{ +using Xunit.Abstractions; + +namespace Timeline.Tests.Helpers +{ public class MyWebApplicationFactory : WebApplicationFactory where TStartup : class { // We should keep the connection, so the database is persisted but not recreate every time. @@ -65,19 +65,19 @@ namespace Timeline.Tests.Helpers base.Dispose(disposing); } - } - - public static class WebApplicationFactoryExtensions - { - public static WebApplicationFactory WithTestLogging(this WebApplicationFactory factory, ITestOutputHelper outputHelper) where TEntry : class - { - return factory.WithWebHostBuilder(builder => - { + } + + public static class WebApplicationFactoryExtensions + { + public static WebApplicationFactory WithTestLogging(this WebApplicationFactory factory, ITestOutputHelper outputHelper) where TEntry : class + { + return factory.WithWebHostBuilder(builder => + { builder.ConfigureLogging(logging => { logging.AddXunit(outputHelper); - }); - }); - } - } -} + }); + }); + } + } +} diff --git a/Timeline.Tests/Helpers/ResponseExtensions.cs b/Timeline.Tests/Helpers/ResponseExtensions.cs index 86ac1c88..155836fb 100644 --- a/Timeline.Tests/Helpers/ResponseExtensions.cs +++ b/Timeline.Tests/Helpers/ResponseExtensions.cs @@ -1,14 +1,14 @@ -using Newtonsoft.Json; -using System.Net.Http; -using System.Threading.Tasks; - -namespace Timeline.Tests.Helpers -{ - public static class ResponseExtensions - { - public static async Task ReadBodyAsJson(this HttpResponseMessage response) - { - return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); - } - } -} +using Newtonsoft.Json; +using System.Net.Http; +using System.Threading.Tasks; + +namespace Timeline.Tests.Helpers +{ + public static class ResponseExtensions + { + public static async Task ReadBodyAsJson(this HttpResponseMessage response) + { + return JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); + } + } +} diff --git a/Timeline.Tests/Helpers/TestClock.cs b/Timeline.Tests/Helpers/TestClock.cs index 91523f2b..ea90305f 100644 --- a/Timeline.Tests/Helpers/TestClock.cs +++ b/Timeline.Tests/Helpers/TestClock.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using System; using Timeline.Services; diff --git a/Timeline.Tests/Helpers/TestUsers.cs b/Timeline.Tests/Helpers/TestUsers.cs index 41dd83a9..71de8237 100644 --- a/Timeline.Tests/Helpers/TestUsers.cs +++ b/Timeline.Tests/Helpers/TestUsers.cs @@ -1,42 +1,42 @@ -using System.Collections.Generic; -using System.Linq; -using Timeline.Entities; -using Timeline.Models; -using Timeline.Services; - -namespace Timeline.Tests.Helpers -{ - public static class TestMockUsers - { - static TestMockUsers() - { - var mockUsers = new List(); - var passwordService = new PasswordService(); - - mockUsers.Add(new User - { - Name = "user", - EncryptedPassword = passwordService.HashPassword("user"), - RoleString = UserUtility.IsAdminToRoleString(false), - Version = 0, - }); - mockUsers.Add(new User - { - Name = "admin", - EncryptedPassword = passwordService.HashPassword("admin"), - RoleString = UserUtility.IsAdminToRoleString(true), - Version = 0, - }); - - MockUsers = mockUsers; - - var mockUserInfos = mockUsers.Select(u => UserUtility.CreateUserInfo(u)).ToList(); - mockUserInfos.Sort(UserInfoComparers.Comparer); - MockUserInfos = mockUserInfos; - } - - public static List MockUsers { get; } - - public static IReadOnlyList MockUserInfos { get; } - } -} +using System.Collections.Generic; +using System.Linq; +using Timeline.Entities; +using Timeline.Models; +using Timeline.Services; + +namespace Timeline.Tests.Helpers +{ + public static class TestMockUsers + { + static TestMockUsers() + { + var mockUsers = new List(); + var passwordService = new PasswordService(); + + mockUsers.Add(new User + { + Name = "user", + EncryptedPassword = passwordService.HashPassword("user"), + RoleString = UserUtility.IsAdminToRoleString(false), + Version = 0, + }); + mockUsers.Add(new User + { + Name = "admin", + EncryptedPassword = passwordService.HashPassword("admin"), + RoleString = UserUtility.IsAdminToRoleString(true), + Version = 0, + }); + + MockUsers = mockUsers; + + var mockUserInfos = mockUsers.Select(u => UserUtility.CreateUserInfo(u)).ToList(); + mockUserInfos.Sort(UserInfoComparers.Comparer); + MockUserInfos = mockUserInfos; + } + + public static List MockUsers { get; } + + public static IReadOnlyList MockUserInfos { get; } + } +} diff --git a/Timeline.Tests/Helpers/UserInfoComparers.cs b/Timeline.Tests/Helpers/UserInfoComparers.cs index fcf37e5c..c7c584b7 100644 --- a/Timeline.Tests/Helpers/UserInfoComparers.cs +++ b/Timeline.Tests/Helpers/UserInfoComparers.cs @@ -1,47 +1,47 @@ -using System.Collections.Generic; -using Timeline.Entities; - -namespace Timeline.Tests.Helpers -{ - public static class UserInfoComparers - { - public static IEqualityComparer EqualityComparer { get; } = new EqualityComparerImpl(); - public static IComparer Comparer { get; } = Comparer.Create(Compare); - - - private class EqualityComparerImpl : IEqualityComparer - { - bool IEqualityComparer.Equals(UserInfo x, UserInfo y) - { - return Compare(x, y) == 0; - } - - int IEqualityComparer.GetHashCode(UserInfo obj) - { - return obj.Username.GetHashCode() ^ obj.Administrator.GetHashCode(); - } - } - - public static int Compare(UserInfo left, UserInfo right) - { - if (left == null) - { - if (right == null) - return 0; - return -1; - } - - if (right == null) - return 1; - - var uc = string.Compare(left.Username, right.Username); - if (uc != 0) - return uc; - - if (left.Administrator == right.Administrator) - return 0; - - return left.Administrator ? -1 : 1; - } - } -} +using System.Collections.Generic; +using Timeline.Entities; + +namespace Timeline.Tests.Helpers +{ + public static class UserInfoComparers + { + public static IEqualityComparer EqualityComparer { get; } = new EqualityComparerImpl(); + public static IComparer Comparer { get; } = Comparer.Create(Compare); + + + private class EqualityComparerImpl : IEqualityComparer + { + bool IEqualityComparer.Equals(UserInfo x, UserInfo y) + { + return Compare(x, y) == 0; + } + + int IEqualityComparer.GetHashCode(UserInfo obj) + { + return obj.Username.GetHashCode() ^ obj.Administrator.GetHashCode(); + } + } + + public static int Compare(UserInfo left, UserInfo right) + { + if (left == null) + { + if (right == null) + return 0; + return -1; + } + + if (right == null) + return 1; + + var uc = string.Compare(left.Username, right.Username); + if (uc != 0) + return uc; + + if (left.Administrator == right.Administrator) + return 0; + + return left.Administrator ? -1 : 1; + } + } +} diff --git a/Timeline.Tests/Timeline.Tests.csproj b/Timeline.Tests/Timeline.Tests.csproj index 854c63ac..8cc304f4 100644 --- a/Timeline.Tests/Timeline.Tests.csproj +++ b/Timeline.Tests/Timeline.Tests.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.2 diff --git a/Timeline.Tests/TokenUnitTest.cs b/Timeline.Tests/TokenUnitTest.cs index 7b83cd13..f942767d 100644 --- a/Timeline.Tests/TokenUnitTest.cs +++ b/Timeline.Tests/TokenUnitTest.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Mvc.Testing; +using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using System; diff --git a/Timeline.Tests/UserUnitTest.cs b/Timeline.Tests/UserUnitTest.cs index b3377f7b..de429c7f 100644 --- a/Timeline.Tests/UserUnitTest.cs +++ b/Timeline.Tests/UserUnitTest.cs @@ -1,36 +1,36 @@ -using Microsoft.AspNetCore.Mvc.Testing; -using Newtonsoft.Json; -using System.Linq; -using System.Net; -using System.Threading.Tasks; -using Timeline.Entities; -using Timeline.Tests.Helpers; -using Timeline.Tests.Helpers.Authentication; -using Xunit; -using Xunit.Abstractions; - -namespace Timeline.Tests -{ - public class UserUnitTest : IClassFixture> - { - private readonly WebApplicationFactory _factory; - - public UserUnitTest(MyWebApplicationFactory factory, ITestOutputHelper outputHelper) - { - _factory = factory.WithTestLogging(outputHelper); - } - - [Fact] - public async Task UserTest() - { - using (var client = await _factory.CreateClientWithUser("admin", "admin")) - { - var res1 = await client.GetAsync("users"); - Assert.Equal(HttpStatusCode.OK, res1.StatusCode); - var users = JsonConvert.DeserializeObject(await res1.Content.ReadAsStringAsync()).ToList(); - users.Sort(UserInfoComparers.Comparer); - Assert.Equal(TestMockUsers.MockUserInfos, users, UserInfoComparers.EqualityComparer); - } - } - } -} +using Microsoft.AspNetCore.Mvc.Testing; +using Newtonsoft.Json; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Timeline.Entities; +using Timeline.Tests.Helpers; +using Timeline.Tests.Helpers.Authentication; +using Xunit; +using Xunit.Abstractions; + +namespace Timeline.Tests +{ + public class UserUnitTest : IClassFixture> + { + private readonly WebApplicationFactory _factory; + + public UserUnitTest(MyWebApplicationFactory factory, ITestOutputHelper outputHelper) + { + _factory = factory.WithTestLogging(outputHelper); + } + + [Fact] + public async Task UserTest() + { + using (var client = await _factory.CreateClientWithUser("admin", "admin")) + { + var res1 = await client.GetAsync("users"); + Assert.Equal(HttpStatusCode.OK, res1.StatusCode); + var users = JsonConvert.DeserializeObject(await res1.Content.ReadAsStringAsync()).ToList(); + users.Sort(UserInfoComparers.Comparer); + Assert.Equal(TestMockUsers.MockUserInfos, users, UserInfoComparers.EqualityComparer); + } + } + } +} diff --git a/Timeline.sln b/Timeline.sln index 9d041499..055989e9 100644 --- a/Timeline.sln +++ b/Timeline.sln @@ -1,31 +1,30 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.271 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Timeline", "Timeline\Timeline.csproj", "{A34D323C-5233-4754-B14F-4819CE9C27CA}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Timeline.Tests", "Timeline.Tests\Timeline.Tests.csproj", "{3D76D578-37BC-43C2-97BF-9C6DD3825F10}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A34D323C-5233-4754-B14F-4819CE9C27CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A34D323C-5233-4754-B14F-4819CE9C27CA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A34D323C-5233-4754-B14F-4819CE9C27CA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A34D323C-5233-4754-B14F-4819CE9C27CA}.Release|Any CPU.Build.0 = Release|Any CPU - {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {9A7526E5-E68F-465C-9E0F-88BF6E040F14} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.271 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Timeline", "Timeline\Timeline.csproj", "{A34D323C-5233-4754-B14F-4819CE9C27CA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Timeline.Tests", "Timeline.Tests\Timeline.Tests.csproj", "{3D76D578-37BC-43C2-97BF-9C6DD3825F10}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A34D323C-5233-4754-B14F-4819CE9C27CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A34D323C-5233-4754-B14F-4819CE9C27CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A34D323C-5233-4754-B14F-4819CE9C27CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A34D323C-5233-4754-B14F-4819CE9C27CA}.Release|Any CPU.Build.0 = Release|Any CPU + {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D76D578-37BC-43C2-97BF-9C6DD3825F10}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {9A7526E5-E68F-465C-9E0F-88BF6E040F14} + EndGlobalSection +EndGlobal diff --git a/Timeline/Authenticate/Attribute.cs b/Timeline/Authenticate/Attribute.cs index 50b2681d..1875a21b 100644 --- a/Timeline/Authenticate/Attribute.cs +++ b/Timeline/Authenticate/Attribute.cs @@ -1,21 +1,21 @@ -using Microsoft.AspNetCore.Authorization; -using Timeline.Models; - -namespace Timeline.Authenticate -{ - public class AdminAuthorizeAttribute : AuthorizeAttribute - { - public AdminAuthorizeAttribute() - { - Roles = UserRoles.Admin; - } - } - - public class UserAuthorizeAttribute : AuthorizeAttribute - { - public UserAuthorizeAttribute() - { - Roles = UserRoles.User; - } - } -} +using Microsoft.AspNetCore.Authorization; +using Timeline.Models; + +namespace Timeline.Authenticate +{ + public class AdminAuthorizeAttribute : AuthorizeAttribute + { + public AdminAuthorizeAttribute() + { + Roles = UserRoles.Admin; + } + } + + public class UserAuthorizeAttribute : AuthorizeAttribute + { + public UserAuthorizeAttribute() + { + Roles = UserRoles.User; + } + } +} diff --git a/Timeline/Authenticate/AuthHandler.cs b/Timeline/Authenticate/AuthHandler.cs index 41cb11c6..5b26716d 100644 --- a/Timeline/Authenticate/AuthHandler.cs +++ b/Timeline/Authenticate/AuthHandler.cs @@ -1,101 +1,101 @@ -using Microsoft.AspNetCore.Authentication; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Headers; -using System; -using System.Linq; -using System.Security.Claims; -using System.Text.Encodings.Web; -using System.Threading.Tasks; -using Timeline.Services; - -namespace Timeline.Authenticate -{ - static class AuthConstants - { - public const string Scheme = "Bearer"; - public const string DisplayName = "My Jwt Auth Scheme"; - } - - class AuthOptions : AuthenticationSchemeOptions - { - /// - /// The query param key to search for token. If null then query params are not searched for token. Default to "token". - /// - public string TokenQueryParamKey { get; set; } = "token"; - } - - class AuthHandler : AuthenticationHandler - { - private readonly ILogger _logger; - private readonly IUserService _userService; - - public AuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService) - : base(options, logger, encoder, clock) - { - _logger = logger.CreateLogger(); - _userService = userService; - } - - // return null if no token is found - private string ExtractToken() - { - // check the authorization header - string header = Request.Headers[HeaderNames.Authorization]; - if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) - { - var token = header.Substring("Bearer ".Length).Trim(); - _logger.LogInformation("Token is found in authorization header. Token is {} .", token); - return token; - } - - // check the query params - var paramQueryKey = Options.TokenQueryParamKey; - if (!string.IsNullOrEmpty(paramQueryKey)) - { - string token = Request.Query[paramQueryKey]; - if (!string.IsNullOrEmpty(token)) - { - _logger.LogInformation("Token is found in query param with key \"{}\". Token is {} .", paramQueryKey, token); - return token; - } - } - - // not found anywhere then return null - return null; - } - - protected override async Task HandleAuthenticateAsync() - { - var token = ExtractToken(); - if (string.IsNullOrEmpty(token)) - { - _logger.LogInformation("No jwt token is found."); - return AuthenticateResult.NoResult(); - } - - try - { - var userInfo = await _userService.VerifyToken(token); - - 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))); - - var principal = new ClaimsPrincipal(); - principal.AddIdentity(identity); - - return AuthenticateResult.Success(new AuthenticationTicket(principal, AuthConstants.Scheme)); - } - catch (ArgumentException) - { - throw; // this exception usually means server error. - } - catch (Exception e) - { - _logger.LogInformation(e, "A jwt token validation failed."); - return AuthenticateResult.Fail(e); - } - } - } -} +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; +using System; +using System.Linq; +using System.Security.Claims; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using Timeline.Services; + +namespace Timeline.Authenticate +{ + static class AuthConstants + { + public const string Scheme = "Bearer"; + public const string DisplayName = "My Jwt Auth Scheme"; + } + + class AuthOptions : AuthenticationSchemeOptions + { + /// + /// The query param key to search for token. If null then query params are not searched for token. Default to "token". + /// + public string TokenQueryParamKey { get; set; } = "token"; + } + + class AuthHandler : AuthenticationHandler + { + private readonly ILogger _logger; + private readonly IUserService _userService; + + public AuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService) + : base(options, logger, encoder, clock) + { + _logger = logger.CreateLogger(); + _userService = userService; + } + + // return null if no token is found + private string ExtractToken() + { + // check the authorization header + string header = Request.Headers[HeaderNames.Authorization]; + if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) + { + var token = header.Substring("Bearer ".Length).Trim(); + _logger.LogInformation("Token is found in authorization header. Token is {} .", token); + return token; + } + + // check the query params + var paramQueryKey = Options.TokenQueryParamKey; + if (!string.IsNullOrEmpty(paramQueryKey)) + { + string token = Request.Query[paramQueryKey]; + if (!string.IsNullOrEmpty(token)) + { + _logger.LogInformation("Token is found in query param with key \"{}\". Token is {} .", paramQueryKey, token); + return token; + } + } + + // not found anywhere then return null + return null; + } + + protected override async Task HandleAuthenticateAsync() + { + var token = ExtractToken(); + if (string.IsNullOrEmpty(token)) + { + _logger.LogInformation("No jwt token is found."); + return AuthenticateResult.NoResult(); + } + + try + { + var userInfo = await _userService.VerifyToken(token); + + 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))); + + var principal = new ClaimsPrincipal(); + principal.AddIdentity(identity); + + return AuthenticateResult.Success(new AuthenticationTicket(principal, AuthConstants.Scheme)); + } + catch (ArgumentException) + { + throw; // this exception usually means server error. + } + catch (Exception e) + { + _logger.LogInformation(e, "A jwt token validation failed."); + return AuthenticateResult.Fail(e); + } + } + } +} diff --git a/Timeline/Configs/DatabaseConfig.cs b/Timeline/Configs/DatabaseConfig.cs index 05dc630e..e24ecdfb 100644 --- a/Timeline/Configs/DatabaseConfig.cs +++ b/Timeline/Configs/DatabaseConfig.cs @@ -1,7 +1,7 @@ -namespace Timeline.Configs -{ - public class DatabaseConfig - { - public string ConnectionString { get; set; } - } -} +namespace Timeline.Configs +{ + public class DatabaseConfig + { + public string ConnectionString { get; set; } + } +} diff --git a/Timeline/Configs/JwtConfig.cs b/Timeline/Configs/JwtConfig.cs index 4d5ef97f..8c61d7bc 100644 --- a/Timeline/Configs/JwtConfig.cs +++ b/Timeline/Configs/JwtConfig.cs @@ -1,15 +1,15 @@ -namespace Timeline.Configs -{ - public class JwtConfig - { - public string Issuer { get; set; } - public string Audience { get; set; } - public string SigningKey { get; set; } - - /// - /// Set the default value of expire offset of jwt token. - /// Unit is second. Default is 3600 * 24 seconds, aka 1 day. - /// - public long DefaultExpireOffset { get; set; } = 3600 * 24; - } -} +namespace Timeline.Configs +{ + public class JwtConfig + { + public string Issuer { get; set; } + public string Audience { get; set; } + public string SigningKey { get; set; } + + /// + /// Set the default value of expire offset of jwt token. + /// Unit is second. Default is 3600 * 24 seconds, aka 1 day. + /// + public long DefaultExpireOffset { get; set; } = 3600 * 24; + } +} diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 549e227b..ff397518 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -1,55 +1,55 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; -using System; +using System; using System.Collections.Generic; -using System.Threading.Tasks; -using Timeline.Entities.Http; -using Timeline.Services; -using static Timeline.Helpers.MyLogHelper; - -namespace Timeline.Controllers -{ - [Route("token")] - public class TokenController : Controller - { - private static class LoggingEventIds - { - public const int CreateSucceeded = 1000; - public const int CreateFailed = 1001; - - public const int VerifySucceeded = 2000; - public const int VerifyFailed = 2001; - } - - public static class ErrorCodes - { - public const int Create_UserNotExist = -1001; - public const int Create_BadPassword = -1002; - public const int Create_BadExpireOffset = -1003; - - public const int Verify_BadToken = -2001; - public const int Verify_UserNotExist = -2002; - public const int Verify_BadVersion = -2003; - public const int Verify_Expired = -2004; - } - - private readonly IUserService _userService; - private readonly ILogger _logger; - private readonly IClock _clock; - - public TokenController(IUserService userService, ILogger logger, IClock clock) - { - _userService = userService; - _logger = logger; - _clock = clock; - } - - [HttpPost("create")] - [AllowAnonymous] - public async Task Create([FromBody] CreateTokenRequest request) - { +using System.Threading.Tasks; +using Timeline.Entities.Http; +using Timeline.Services; +using static Timeline.Helpers.MyLogHelper; + +namespace Timeline.Controllers +{ + [Route("token")] + public class TokenController : Controller + { + private static class LoggingEventIds + { + public const int CreateSucceeded = 1000; + public const int CreateFailed = 1001; + + public const int VerifySucceeded = 2000; + public const int VerifyFailed = 2001; + } + + public static class ErrorCodes + { + public const int Create_UserNotExist = -1001; + public const int Create_BadPassword = -1002; + public const int Create_BadExpireOffset = -1003; + + public const int Verify_BadToken = -2001; + public const int Verify_UserNotExist = -2002; + public const int Verify_BadVersion = -2003; + public const int Verify_Expired = -2004; + } + + private readonly IUserService _userService; + private readonly ILogger _logger; + private readonly IClock _clock; + + public TokenController(IUserService userService, ILogger logger, IClock clock) + { + _userService = userService; + _logger = logger; + _clock = clock; + } + + [HttpPost("create")] + [AllowAnonymous] + public async Task Create([FromBody] CreateTokenRequest request) + { void LogFailure(string reason, int code, Exception e = null) { _logger.LogInformation(LoggingEventIds.CreateFailed, e, FormatLogMessage("Attemp to login failed.", @@ -58,51 +58,51 @@ namespace Timeline.Controllers Pair("Username", request.Username), Pair("Password", request.Password), 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 result = await _userService.CreateToken(request.Username, request.Password, expiredTime); + } + + 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 result = await _userService.CreateToken(request.Username, request.Password, expiredTime); _logger.LogInformation(LoggingEventIds.CreateSucceeded, FormatLogMessage("Attemp to login succeeded.", Pair("Username", request.Username), - Pair("Expire Time", expiredTime == null ? "default" : expiredTime.Value.ToString()))); - return Ok(new CreateTokenResponse - { - Token = result.Token, - User = result.User - }); - } - catch (UserNotExistException e) - { - var code = ErrorCodes.Create_UserNotExist; - LogFailure("User does not exist.", code, e); - return BadRequest(new CommonResponse(code, "Bad username or password.")); - } - catch (BadPasswordException e) - { - var code = ErrorCodes.Create_BadPassword; - LogFailure("Password is wrong.", code, e); - return BadRequest(new CommonResponse(code, "Bad username or password.")); - } - } - - [HttpPost("verify")] - [AllowAnonymous] - public async Task Verify([FromBody] VerifyTokenRequest request) + Pair("Expire Time", expiredTime == null ? "default" : expiredTime.Value.ToString()))); + return Ok(new CreateTokenResponse + { + Token = result.Token, + User = result.User + }); + } + catch (UserNotExistException e) + { + var code = ErrorCodes.Create_UserNotExist; + LogFailure("User does not exist.", code, e); + return BadRequest(new CommonResponse(code, "Bad username or password.")); + } + catch (BadPasswordException e) + { + var code = ErrorCodes.Create_BadPassword; + LogFailure("Password is wrong.", code, e); + return BadRequest(new CommonResponse(code, "Bad username or password.")); + } + } + + [HttpPost("verify")] + [AllowAnonymous] + public async Task Verify([FromBody] VerifyTokenRequest request) { void LogFailure(string reason, int code, Exception e = null, params KeyValuePair[] otherProperties) { @@ -112,52 +112,52 @@ namespace Timeline.Controllers properties[2] = Pair("Token", request.Token); otherProperties.CopyTo(properties, 3); _logger.LogInformation(LoggingEventIds.VerifyFailed, e, FormatLogMessage("Token verification failed.", properties)); - } - - try - { - var result = await _userService.VerifyToken(request.Token); + } + + try + { + var result = await _userService.VerifyToken(request.Token); _logger.LogInformation(LoggingEventIds.VerifySucceeded, FormatLogMessage("Token verification succeeded.", - Pair("Username", result.Username), Pair("Token", request.Token))); - return Ok(new VerifyTokenResponse - { - User = result - }); - } - catch (JwtTokenVerifyException e) - { - if (e.ErrorCode == JwtTokenVerifyException.ErrorCodes.Expired) - { - const string message = "Token is expired."; - var code = ErrorCodes.Verify_Expired; - var innerException = e.InnerException as SecurityTokenExpiredException; - LogFailure(message, code, e, Pair("Expires", innerException.Expires)); - return BadRequest(new CommonResponse(code, message)); - } - else - { - const string message = "Token is of bad format."; - var code = ErrorCodes.Verify_BadToken; - LogFailure(message, code, e); - return BadRequest(new CommonResponse(code, message)); - } - } - catch (UserNotExistException e) + Pair("Username", result.Username), Pair("Token", request.Token))); + return Ok(new VerifyTokenResponse + { + User = result + }); + } + catch (JwtTokenVerifyException e) { - const string message = "User does not exist. Administrator might have deleted this user."; + if (e.ErrorCode == JwtTokenVerifyException.ErrorCodes.Expired) + { + const string message = "Token is expired."; + var code = ErrorCodes.Verify_Expired; + var innerException = e.InnerException as SecurityTokenExpiredException; + LogFailure(message, code, e, Pair("Expires", innerException.Expires)); + return BadRequest(new CommonResponse(code, message)); + } + else + { + const string message = "Token is of bad format."; + var code = ErrorCodes.Verify_BadToken; + LogFailure(message, code, e); + return BadRequest(new CommonResponse(code, message)); + } + } + catch (UserNotExistException e) + { + const string message = "User does not exist. Administrator might have deleted this user."; var code = ErrorCodes.Verify_UserNotExist; - LogFailure(message, code, e); - return BadRequest(new CommonResponse(code, message)); - } - catch (BadTokenVersionException e) - { - const string message = "Token has a old version."; - var code = ErrorCodes.Verify_BadVersion; - LogFailure(message, code, e); - _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token because version is old. Code: {} Token: {}.", code, request.Token); - return BadRequest(new CommonResponse(code, message)); - } - } - } -} + LogFailure(message, code, e); + return BadRequest(new CommonResponse(code, message)); + } + catch (BadTokenVersionException e) + { + const string message = "Token has a old version."; + var code = ErrorCodes.Verify_BadVersion; + LogFailure(message, code, e); + _logger.LogInformation(LoggingEventIds.VerifyFailed, e, "Attemp to verify a bad token because version is old. Code: {} Token: {}.", code, request.Token); + return BadRequest(new CommonResponse(code, message)); + } + } + } +} diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 2099690c..8d338949 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -1,126 +1,126 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; -using Timeline.Authenticate; -using Timeline.Entities; -using Timeline.Entities.Http; -using Timeline.Services; -using static Timeline.Helpers.MyLogHelper; - -namespace Timeline.Controllers -{ - public class UserController : Controller - { - private static class ErrorCodes - { - public const int Get_NotExists = -1001; - - public const int Put_NoPassword = -2001; - - public const int Patch_NotExists = -3001; - - public const int ChangePassword_BadOldPassword = -4001; - } - - private readonly ILogger _logger; - private readonly IUserService _userService; - - public UserController(ILogger logger, IUserService userService) - { - _logger = logger; - _userService = userService; - } - - [HttpGet("users"), AdminAuthorize] - public async Task> List() - { - return Ok(await _userService.ListUsers()); - } - - [HttpGet("user/{username}"), AdminAuthorize] - public async Task Get([FromRoute] string username) - { - var user = await _userService.GetUser(username); - if (user == null) - { - _logger.LogInformation(FormatLogMessage("Attempt to get a non-existent user.", Pair("Username", username))); - return NotFound(new CommonResponse(ErrorCodes.Get_NotExists, "The user does not exist.")); - } - return Ok(user); - } - - [HttpPut("user/{username}"), AdminAuthorize] - public async Task Put([FromBody] UserPutRequest request, [FromRoute] string username) - { - if (request.Password == null) // This place will be refactored. - { - _logger.LogInformation("Attempt to put a user without a password. Username: {} .", username); - return BadRequest(); - } - - var result = await _userService.PutUser(username, request.Password, request.Administrator); - switch (result) - { - case PutResult.Created: - _logger.LogInformation(FormatLogMessage("A user is created.", Pair("Username", username))); - return CreatedAtAction("Get", new { username }, CommonPutResponse.Created); - case PutResult.Modified: - _logger.LogInformation(FormatLogMessage("A user is modified.", Pair("Username", username))); - return Ok(CommonPutResponse.Modified); - default: - throw new Exception("Unreachable code."); - } - } - - [HttpPatch("user/{username}"), AdminAuthorize] - public async Task Patch([FromBody] UserPatchRequest request, [FromRoute] string username) - { - try - { - await _userService.PatchUser(username, request.Password, request.Administrator); - return Ok(); - } - catch (UserNotExistException e) - { - _logger.LogInformation(e, FormatLogMessage("Attempt to patch a non-existent user.", Pair("Username", username))); - return BadRequest(new CommonResponse(ErrorCodes.Patch_NotExists, "The user does not exist.")); - } - } - - [HttpDelete("user/{username}"), AdminAuthorize] - public async Task Delete([FromRoute] string username) - { - try - { - await _userService.DeleteUser(username); - _logger.LogInformation(FormatLogMessage("A user is deleted.", Pair("Username", username))); - return Ok(CommonDeleteResponse.Deleted); - } - catch (UserNotExistException e) - { - _logger.LogInformation(e, FormatLogMessage("Attempt to delete a non-existent user.", Pair("Username", username))); - return Ok(CommonDeleteResponse.NotExists); - } - } - - [HttpPost("userop/changepassword"), Authorize] - public async Task ChangePassword([FromBody] ChangePasswordRequest request) - { - try - { - await _userService.ChangePassword(User.Identity.Name, request.OldPassword, request.NewPassword); - _logger.LogInformation(FormatLogMessage("A user changed password.", Pair("Username", User.Identity.Name))); - return Ok(); - } - catch (BadPasswordException e) - { +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; +using Timeline.Authenticate; +using Timeline.Entities; +using Timeline.Entities.Http; +using Timeline.Services; +using static Timeline.Helpers.MyLogHelper; + +namespace Timeline.Controllers +{ + public class UserController : Controller + { + private static class ErrorCodes + { + public const int Get_NotExists = -1001; + + public const int Put_NoPassword = -2001; + + public const int Patch_NotExists = -3001; + + public const int ChangePassword_BadOldPassword = -4001; + } + + private readonly ILogger _logger; + private readonly IUserService _userService; + + public UserController(ILogger logger, IUserService userService) + { + _logger = logger; + _userService = userService; + } + + [HttpGet("users"), AdminAuthorize] + public async Task> List() + { + return Ok(await _userService.ListUsers()); + } + + [HttpGet("user/{username}"), AdminAuthorize] + public async Task Get([FromRoute] string username) + { + var user = await _userService.GetUser(username); + if (user == null) + { + _logger.LogInformation(FormatLogMessage("Attempt to get a non-existent user.", Pair("Username", username))); + return NotFound(new CommonResponse(ErrorCodes.Get_NotExists, "The user does not exist.")); + } + return Ok(user); + } + + [HttpPut("user/{username}"), AdminAuthorize] + public async Task Put([FromBody] UserPutRequest request, [FromRoute] string username) + { + if (request.Password == null) // This place will be refactored. + { + _logger.LogInformation("Attempt to put a user without a password. Username: {} .", username); + return BadRequest(); + } + + var result = await _userService.PutUser(username, request.Password, request.Administrator); + switch (result) + { + case PutResult.Created: + _logger.LogInformation(FormatLogMessage("A user is created.", Pair("Username", username))); + return CreatedAtAction("Get", new { username }, CommonPutResponse.Created); + case PutResult.Modified: + _logger.LogInformation(FormatLogMessage("A user is modified.", Pair("Username", username))); + return Ok(CommonPutResponse.Modified); + default: + throw new Exception("Unreachable code."); + } + } + + [HttpPatch("user/{username}"), AdminAuthorize] + public async Task Patch([FromBody] UserPatchRequest request, [FromRoute] string username) + { + try + { + await _userService.PatchUser(username, request.Password, request.Administrator); + return Ok(); + } + catch (UserNotExistException e) + { + _logger.LogInformation(e, FormatLogMessage("Attempt to patch a non-existent user.", Pair("Username", username))); + return BadRequest(new CommonResponse(ErrorCodes.Patch_NotExists, "The user does not exist.")); + } + } + + [HttpDelete("user/{username}"), AdminAuthorize] + public async Task Delete([FromRoute] string username) + { + try + { + await _userService.DeleteUser(username); + _logger.LogInformation(FormatLogMessage("A user is deleted.", Pair("Username", username))); + return Ok(CommonDeleteResponse.Deleted); + } + catch (UserNotExistException e) + { + _logger.LogInformation(e, FormatLogMessage("Attempt to delete a non-existent user.", Pair("Username", username))); + return Ok(CommonDeleteResponse.NotExists); + } + } + + [HttpPost("userop/changepassword"), Authorize] + public async Task ChangePassword([FromBody] ChangePasswordRequest request) + { + try + { + await _userService.ChangePassword(User.Identity.Name, request.OldPassword, request.NewPassword); + _logger.LogInformation(FormatLogMessage("A user changed password.", Pair("Username", User.Identity.Name))); + return Ok(); + } + catch (BadPasswordException e) + { _logger.LogInformation(e, FormatLogMessage("A user attempt to change password but old password is wrong.", - Pair("Username", User.Identity.Name), Pair("Old Password", request.OldPassword))); - return BadRequest(new CommonResponse(ErrorCodes.ChangePassword_BadOldPassword, "Old password is wrong.")); - } - // User can't be non-existent or the token is bad. - } - } -} + Pair("Username", User.Identity.Name), Pair("Old Password", request.OldPassword))); + return BadRequest(new CommonResponse(ErrorCodes.ChangePassword_BadOldPassword, "Old password is wrong.")); + } + // User can't be non-existent or the token is bad. + } + } +} diff --git a/Timeline/Controllers/UserTestController.cs b/Timeline/Controllers/UserTestController.cs index 21686b81..f65d9857 100644 --- a/Timeline/Controllers/UserTestController.cs +++ b/Timeline/Controllers/UserTestController.cs @@ -1,31 +1,31 @@ -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Timeline.Authenticate; - -namespace Timeline.Controllers -{ - [Route("Test/User")] - public class UserTestController : Controller - { - [HttpGet("[action]")] - [Authorize] - public ActionResult Authorize() - { - return Ok(); - } - - [HttpGet("[action]")] - [UserAuthorize] - public new ActionResult User() - { - return Ok(); - } - - [HttpGet("[action]")] - [AdminAuthorize] - public ActionResult Admin() - { - return Ok(); - } - } -} +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Timeline.Authenticate; + +namespace Timeline.Controllers +{ + [Route("Test/User")] + public class UserTestController : Controller + { + [HttpGet("[action]")] + [Authorize] + public ActionResult Authorize() + { + return Ok(); + } + + [HttpGet("[action]")] + [UserAuthorize] + public new ActionResult User() + { + return Ok(); + } + + [HttpGet("[action]")] + [AdminAuthorize] + public ActionResult Admin() + { + return Ok(); + } + } +} diff --git a/Timeline/Entities/Http/Common.cs b/Timeline/Entities/Http/Common.cs index 3a45a0ae..4cdc85dd 100644 --- a/Timeline/Entities/Http/Common.cs +++ b/Timeline/Entities/Http/Common.cs @@ -1,37 +1,37 @@ -namespace Timeline.Entities.Http -{ - public class CommonResponse - { - public CommonResponse() - { - - } - - public CommonResponse(int code, string message) - { - Code = code; - Message = message; - } - - public int Code { get; set; } - public string Message { get; set; } - } - - public static class CommonPutResponse - { - public const int CreatedCode = 0; - public const int ModifiedCode = 1; - - public static CommonResponse Created { get; } = new CommonResponse(CreatedCode, "A new item is created."); - public static CommonResponse Modified { get; } = new CommonResponse(ModifiedCode, "An existent item is modified."); - } - - public static class CommonDeleteResponse - { - public const int DeletedCode = 0; - public const int NotExistsCode = 1; - - public static CommonResponse Deleted { get; } = new CommonResponse(DeletedCode, "An existent item is deleted."); - public static CommonResponse NotExists { get; } = new CommonResponse(NotExistsCode, "The item does not exist."); - } -} +namespace Timeline.Entities.Http +{ + public class CommonResponse + { + public CommonResponse() + { + + } + + public CommonResponse(int code, string message) + { + Code = code; + Message = message; + } + + public int Code { get; set; } + public string Message { get; set; } + } + + public static class CommonPutResponse + { + public const int CreatedCode = 0; + public const int ModifiedCode = 1; + + public static CommonResponse Created { get; } = new CommonResponse(CreatedCode, "A new item is created."); + public static CommonResponse Modified { get; } = new CommonResponse(ModifiedCode, "An existent item is modified."); + } + + public static class CommonDeleteResponse + { + public const int DeletedCode = 0; + public const int NotExistsCode = 1; + + public static CommonResponse Deleted { get; } = new CommonResponse(DeletedCode, "An existent item is deleted."); + public static CommonResponse NotExists { get; } = new CommonResponse(NotExistsCode, "The item does not exist."); + } +} diff --git a/Timeline/Entities/Http/Token.cs b/Timeline/Entities/Http/Token.cs index 8a02ed2e..5e261f30 100644 --- a/Timeline/Entities/Http/Token.cs +++ b/Timeline/Entities/Http/Token.cs @@ -1,26 +1,26 @@ -namespace Timeline.Entities.Http -{ - public class CreateTokenRequest - { - public string Username { get; set; } - public string Password { get; set; } - // in day - public double? ExpireOffset { get; set; } - } - - public class CreateTokenResponse - { - public string Token { get; set; } - public UserInfo User { get; set; } - } - - public class VerifyTokenRequest - { - public string Token { get; set; } - } - - public class VerifyTokenResponse - { - public UserInfo User { get; set; } - } -} +namespace Timeline.Entities.Http +{ + public class CreateTokenRequest + { + public string Username { get; set; } + public string Password { get; set; } + // in day + public double? ExpireOffset { get; set; } + } + + public class CreateTokenResponse + { + public string Token { get; set; } + public UserInfo User { get; set; } + } + + public class VerifyTokenRequest + { + public string Token { get; set; } + } + + public class VerifyTokenResponse + { + public UserInfo User { get; set; } + } +} diff --git a/Timeline/Entities/Http/User.cs b/Timeline/Entities/Http/User.cs index b5384778..e9aaf795 100644 --- a/Timeline/Entities/Http/User.cs +++ b/Timeline/Entities/Http/User.cs @@ -1,20 +1,20 @@ -namespace Timeline.Entities.Http -{ - public class UserPutRequest - { - public string Password { get; set; } - public bool Administrator { get; set; } - } - - public class UserPatchRequest - { - public string Password { get; set; } - public bool? Administrator { get; set; } - } - - public class ChangePasswordRequest - { - public string OldPassword { get; set; } - public string NewPassword { get; set; } - } -} +namespace Timeline.Entities.Http +{ + public class UserPutRequest + { + public string Password { get; set; } + public bool Administrator { get; set; } + } + + public class UserPatchRequest + { + public string Password { get; set; } + public bool? Administrator { get; set; } + } + + public class ChangePasswordRequest + { + public string OldPassword { get; set; } + public string NewPassword { get; set; } + } +} diff --git a/Timeline/Entities/PutResult.cs b/Timeline/Entities/PutResult.cs index 4ed48572..32b87e25 100644 --- a/Timeline/Entities/PutResult.cs +++ b/Timeline/Entities/PutResult.cs @@ -1,17 +1,17 @@ -namespace Timeline.Entities -{ - /// - /// Represents the result of a "put" operation. - /// - public enum PutResult - { - /// - /// Indicates the item did not exist and now is created. - /// - Created, - /// - /// Indicates the item exists already and is modified. - /// - Modified - } -} +namespace Timeline.Entities +{ + /// + /// Represents the result of a "put" operation. + /// + public enum PutResult + { + /// + /// Indicates the item did not exist and now is created. + /// + Created, + /// + /// Indicates the item exists already and is modified. + /// + Modified + } +} diff --git a/Timeline/Entities/UserInfo.cs b/Timeline/Entities/UserInfo.cs index 414a8dfe..c75168b8 100644 --- a/Timeline/Entities/UserInfo.cs +++ b/Timeline/Entities/UserInfo.cs @@ -1,23 +1,23 @@ -namespace Timeline.Entities -{ - public sealed class UserInfo - { - public UserInfo() - { - } - - public UserInfo(string username, bool administrator) - { - Username = username; - Administrator = administrator; - } - - public string Username { get; set; } - public bool Administrator { get; set; } - - public override string ToString() - { - return $"Username: {Username} ; Administrator: {Administrator}"; - } - } -} +namespace Timeline.Entities +{ + public sealed class UserInfo + { + public UserInfo() + { + } + + public UserInfo(string username, bool administrator) + { + Username = username; + Administrator = administrator; + } + + public string Username { get; set; } + public bool Administrator { get; set; } + + public override string ToString() + { + return $"Username: {Username} ; Administrator: {Administrator}"; + } + } +} diff --git a/Timeline/Entities/UserUtility.cs b/Timeline/Entities/UserUtility.cs index 14cdb2d6..351d0299 100644 --- a/Timeline/Entities/UserUtility.cs +++ b/Timeline/Entities/UserUtility.cs @@ -1,60 +1,60 @@ -using System; -using System.Linq; -using Timeline.Models; -using Timeline.Services; - -namespace Timeline.Entities -{ - public static class UserUtility - { - public const string UserRole = UserRoles.User; - public const string AdminRole = UserRoles.Admin; - - public static string[] UserRoleArray { get; } = new string[] { UserRole }; - public static string[] AdminRoleArray { get; } = new string[] { UserRole, AdminRole }; - - public static string[] IsAdminToRoleArray(bool isAdmin) - { - return isAdmin ? AdminRoleArray : UserRoleArray; - } - - public static bool RoleArrayToIsAdmin(string[] roles) - { - return roles.Contains(AdminRole); - } - - public static string[] RoleStringToRoleArray(string roleString) - { - return roleString.Split(',').ToArray(); - } - - public static string RoleArrayToRoleString(string[] roles) - { - return string.Join(',', roles); - } - - public static string IsAdminToRoleString(bool isAdmin) - { - return RoleArrayToRoleString(IsAdminToRoleArray(isAdmin)); - } - - public static bool RoleStringToIsAdmin(string roleString) - { - return RoleArrayToIsAdmin(RoleStringToRoleArray(roleString)); - } - - public static UserInfo CreateUserInfo(User user) - { - if (user == null) - throw new ArgumentNullException(nameof(user)); - return new UserInfo(user.Name, RoleStringToIsAdmin(user.RoleString)); - } - - internal static UserCache CreateUserCache(User user) - { - if (user == null) - throw new ArgumentNullException(nameof(user)); - return new UserCache { Username = user.Name, Administrator = RoleStringToIsAdmin(user.RoleString), Version = user.Version }; - } - } -} +using System; +using System.Linq; +using Timeline.Models; +using Timeline.Services; + +namespace Timeline.Entities +{ + public static class UserUtility + { + public const string UserRole = UserRoles.User; + public const string AdminRole = UserRoles.Admin; + + public static string[] UserRoleArray { get; } = new string[] { UserRole }; + public static string[] AdminRoleArray { get; } = new string[] { UserRole, AdminRole }; + + public static string[] IsAdminToRoleArray(bool isAdmin) + { + return isAdmin ? AdminRoleArray : UserRoleArray; + } + + public static bool RoleArrayToIsAdmin(string[] roles) + { + return roles.Contains(AdminRole); + } + + public static string[] RoleStringToRoleArray(string roleString) + { + return roleString.Split(',').ToArray(); + } + + public static string RoleArrayToRoleString(string[] roles) + { + return string.Join(',', roles); + } + + public static string IsAdminToRoleString(bool isAdmin) + { + return RoleArrayToRoleString(IsAdminToRoleArray(isAdmin)); + } + + public static bool RoleStringToIsAdmin(string roleString) + { + return RoleArrayToIsAdmin(RoleStringToRoleArray(roleString)); + } + + public static UserInfo CreateUserInfo(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + return new UserInfo(user.Name, RoleStringToIsAdmin(user.RoleString)); + } + + internal static UserCache CreateUserCache(User user) + { + if (user == null) + throw new ArgumentNullException(nameof(user)); + return new UserCache { Username = user.Name, Administrator = RoleStringToIsAdmin(user.RoleString), Version = user.Version }; + } + } +} diff --git a/Timeline/Helpers/Log.cs b/Timeline/Helpers/Log.cs index ac231810..123e8a8e 100644 --- a/Timeline/Helpers/Log.cs +++ b/Timeline/Helpers/Log.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; namespace Timeline.Helpers diff --git a/Timeline/Migrations/20190412102517_InitCreate.Designer.cs b/Timeline/Migrations/20190412102517_InitCreate.Designer.cs index c68183de..5281da05 100644 --- a/Timeline/Migrations/20190412102517_InitCreate.Designer.cs +++ b/Timeline/Migrations/20190412102517_InitCreate.Designer.cs @@ -1,43 +1,43 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; - -namespace Timeline.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20190412102517_InitCreate")] - partial class InitCreate - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("Timeline.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnName("id"); - - b.Property("EncryptedPassword") - .HasColumnName("password"); - - b.Property("Name") - .HasColumnName("name"); - - b.Property("RoleString") - .HasColumnName("roles"); - - b.HasKey("Id"); - - b.ToTable("user"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Timeline.Models; + +namespace Timeline.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20190412102517_InitCreate")] + partial class InitCreate + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Timeline.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("id"); + + b.Property("EncryptedPassword") + .HasColumnName("password"); + + b.Property("Name") + .HasColumnName("name"); + + b.Property("RoleString") + .HasColumnName("roles"); + + b.HasKey("Id"); + + b.ToTable("user"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Timeline/Migrations/20190412102517_InitCreate.cs b/Timeline/Migrations/20190412102517_InitCreate.cs index c8f3b0ac..55930f6d 100644 --- a/Timeline/Migrations/20190412102517_InitCreate.cs +++ b/Timeline/Migrations/20190412102517_InitCreate.cs @@ -1,32 +1,32 @@ -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Timeline.Migrations -{ - public partial class InitCreate : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.CreateTable( - name: "user", - columns: table => new - { - id = table.Column(nullable: false) - .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), - name = table.Column(nullable: true), - password = table.Column(nullable: true), - roles = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_user", x => x.id); - }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "user"); - } - } -} +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Timeline.Migrations +{ + public partial class InitCreate : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "user", + columns: table => new + { + id = table.Column(nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + name = table.Column(nullable: true), + password = table.Column(nullable: true), + roles = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_user", x => x.id); + }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "user"); + } + } +} diff --git a/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs b/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs index 319c646a..b3139efa 100644 --- a/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs +++ b/Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs @@ -1,43 +1,43 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; - -namespace Timeline.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20190412144150_AddAdminUser")] - partial class AddAdminUser - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("Timeline.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnName("id"); - - b.Property("EncryptedPassword") - .HasColumnName("password"); - - b.Property("Name") - .HasColumnName("name"); - - b.Property("RoleString") - .HasColumnName("roles"); - - b.HasKey("Id"); - - b.ToTable("user"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Timeline.Models; + +namespace Timeline.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20190412144150_AddAdminUser")] + partial class AddAdminUser + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Timeline.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("id"); + + b.Property("EncryptedPassword") + .HasColumnName("password"); + + b.Property("Name") + .HasColumnName("name"); + + b.Property("RoleString") + .HasColumnName("roles"); + + b.HasKey("Id"); + + b.ToTable("user"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Timeline/Migrations/20190412144150_AddAdminUser.cs b/Timeline/Migrations/20190412144150_AddAdminUser.cs index 1b3f14b7..b6760f3e 100644 --- a/Timeline/Migrations/20190412144150_AddAdminUser.cs +++ b/Timeline/Migrations/20190412144150_AddAdminUser.cs @@ -1,19 +1,19 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using Timeline.Services; - -namespace Timeline.Migrations -{ - public partial class AddAdminUser : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.InsertData("user", new string[] { "name", "password", "roles" }, - new string[] { "crupest", new PasswordService().HashPassword("yang0101"), "user,admin" }); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData("user", "name", "crupest"); - } - } -} +using Microsoft.EntityFrameworkCore.Migrations; +using Timeline.Services; + +namespace Timeline.Migrations +{ + public partial class AddAdminUser : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData("user", new string[] { "name", "password", "roles" }, + new string[] { "crupest", new PasswordService().HashPassword("yang0101"), "user,admin" }); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData("user", "name", "crupest"); + } + } +} diff --git a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs index c1d1565f..e2adf9d4 100644 --- a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs +++ b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs @@ -1,46 +1,46 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; - -namespace Timeline.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20190412153003_MakeColumnsInUserNotNull")] - partial class MakeColumnsInUserNotNull - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("Timeline.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnName("id"); - - b.Property("EncryptedPassword") - .IsRequired() - .HasColumnName("password"); - - b.Property("Name") - .IsRequired() - .HasColumnName("name"); - - b.Property("RoleString") - .IsRequired() - .HasColumnName("roles"); - - b.HasKey("Id"); - - b.ToTable("user"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Timeline.Models; + +namespace Timeline.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20190412153003_MakeColumnsInUserNotNull")] + partial class MakeColumnsInUserNotNull + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.3-servicing-35854") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Timeline.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("id"); + + b.Property("EncryptedPassword") + .IsRequired() + .HasColumnName("password"); + + b.Property("Name") + .IsRequired() + .HasColumnName("name"); + + b.Property("RoleString") + .IsRequired() + .HasColumnName("roles"); + + b.HasKey("Id"); + + b.ToTable("user"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.cs b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.cs index 0b7b5f08..12053906 100644 --- a/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.cs +++ b/Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.cs @@ -1,52 +1,52 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Timeline.Migrations -{ - public partial class MakeColumnsInUserNotNull : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "roles", - table: "user", - nullable: false, - oldClrType: typeof(string), - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "name", - table: "user", - nullable: false, - oldClrType: typeof(string), - oldNullable: true); - - migrationBuilder.AlterColumn( - name: "password", - table: "user", - nullable: false, - oldClrType: typeof(string), - oldNullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.AlterColumn( - name: "roles", - table: "user", - nullable: true, - oldClrType: typeof(string)); - - migrationBuilder.AlterColumn( - name: "name", - table: "user", - nullable: true, - oldClrType: typeof(string)); - - migrationBuilder.AlterColumn( - name: "password", - table: "user", - nullable: true, - oldClrType: typeof(string)); - } - } -} +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Timeline.Migrations +{ + public partial class MakeColumnsInUserNotNull : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "roles", + table: "user", + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "name", + table: "user", + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + + migrationBuilder.AlterColumn( + name: "password", + table: "user", + nullable: false, + oldClrType: typeof(string), + oldNullable: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AlterColumn( + name: "roles", + table: "user", + nullable: true, + oldClrType: typeof(string)); + + migrationBuilder.AlterColumn( + name: "name", + table: "user", + nullable: true, + oldClrType: typeof(string)); + + migrationBuilder.AlterColumn( + name: "password", + table: "user", + nullable: true, + oldClrType: typeof(string)); + } + } +} diff --git a/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs b/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs index 42eeeb40..0216ff5b 100644 --- a/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs +++ b/Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs @@ -1,49 +1,49 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; - -namespace Timeline.Migrations -{ - [DbContext(typeof(DatabaseContext))] - [Migration("20190719115321_Add-User-Version")] - partial class AddUserVersion - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("Timeline.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnName("id"); - - b.Property("EncryptedPassword") - .IsRequired() - .HasColumnName("password"); - - b.Property("Name") - .IsRequired() - .HasColumnName("name"); - - b.Property("RoleString") - .IsRequired() - .HasColumnName("roles"); - - b.Property("Version") - .HasColumnName("version"); - - b.HasKey("Id"); - - b.ToTable("user"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Timeline.Models; + +namespace Timeline.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20190719115321_Add-User-Version")] + partial class AddUserVersion + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Timeline.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("id"); + + b.Property("EncryptedPassword") + .IsRequired() + .HasColumnName("password"); + + b.Property("Name") + .IsRequired() + .HasColumnName("name"); + + b.Property("RoleString") + .IsRequired() + .HasColumnName("roles"); + + b.Property("Version") + .HasColumnName("version"); + + b.HasKey("Id"); + + b.ToTable("user"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Timeline/Migrations/20190719115321_Add-User-Version.cs b/Timeline/Migrations/20190719115321_Add-User-Version.cs index 715af909..4d6bd60a 100644 --- a/Timeline/Migrations/20190719115321_Add-User-Version.cs +++ b/Timeline/Migrations/20190719115321_Add-User-Version.cs @@ -1,23 +1,23 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Timeline.Migrations -{ - public partial class AddUserVersion : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "version", - table: "user", - nullable: false, - defaultValue: 0L); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "version", - table: "user"); - } - } -} +using Microsoft.EntityFrameworkCore.Migrations; + +namespace Timeline.Migrations +{ + public partial class AddUserVersion : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "version", + table: "user", + nullable: false, + defaultValue: 0L); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "version", + table: "user"); + } + } +} diff --git a/Timeline/Migrations/DatabaseContextModelSnapshot.cs b/Timeline/Migrations/DatabaseContextModelSnapshot.cs index 7d244969..c26ae5e6 100644 --- a/Timeline/Migrations/DatabaseContextModelSnapshot.cs +++ b/Timeline/Migrations/DatabaseContextModelSnapshot.cs @@ -1,47 +1,47 @@ -// -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Timeline.Models; - -namespace Timeline.Migrations -{ - [DbContext(typeof(DatabaseContext))] - partial class DatabaseContextModelSnapshot : ModelSnapshot - { - protected override void BuildModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") - .HasAnnotation("Relational:MaxIdentifierLength", 64); - - modelBuilder.Entity("Timeline.Models.User", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnName("id"); - - b.Property("EncryptedPassword") - .IsRequired() - .HasColumnName("password"); - - b.Property("Name") - .IsRequired() - .HasColumnName("name"); - - b.Property("RoleString") - .IsRequired() - .HasColumnName("roles"); - - b.Property("Version") - .HasColumnName("version"); - - b.HasKey("Id"); - - b.ToTable("user"); - }); -#pragma warning restore 612, 618 - } - } -} +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Timeline.Models; + +namespace Timeline.Migrations +{ + [DbContext(typeof(DatabaseContext))] + partial class DatabaseContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.2.6-servicing-10079") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + modelBuilder.Entity("Timeline.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnName("id"); + + b.Property("EncryptedPassword") + .IsRequired() + .HasColumnName("password"); + + b.Property("Name") + .IsRequired() + .HasColumnName("name"); + + b.Property("RoleString") + .IsRequired() + .HasColumnName("roles"); + + b.Property("Version") + .HasColumnName("version"); + + b.HasKey("Id"); + + b.ToTable("user"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Timeline/Models/DatabaseContext.cs b/Timeline/Models/DatabaseContext.cs index afd5a333..2e33bf8d 100644 --- a/Timeline/Models/DatabaseContext.cs +++ b/Timeline/Models/DatabaseContext.cs @@ -1,42 +1,42 @@ -using Microsoft.EntityFrameworkCore; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -namespace Timeline.Models -{ - public static class UserRoles - { - public const string Admin = "admin"; - public const string User = "user"; - } - - [Table("user")] - public class User - { - [Column("id"), Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] - public long Id { get; set; } - - [Column("name"), Required] - public string Name { get; set; } - - [Column("password"), Required] - public string EncryptedPassword { get; set; } - - [Column("roles"), Required] - public string RoleString { get; set; } - - [Column("version"), Required] - public long Version { get; set; } - } - - public class DatabaseContext : DbContext - { - public DatabaseContext(DbContextOptions options) - : base(options) - { - - } - - public DbSet Users { get; set; } - } -} +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace Timeline.Models +{ + public static class UserRoles + { + public const string Admin = "admin"; + public const string User = "user"; + } + + [Table("user")] + public class User + { + [Column("id"), Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public long Id { get; set; } + + [Column("name"), Required] + public string Name { get; set; } + + [Column("password"), Required] + public string EncryptedPassword { get; set; } + + [Column("roles"), Required] + public string RoleString { get; set; } + + [Column("version"), Required] + public long Version { get; set; } + } + + public class DatabaseContext : DbContext + { + public DatabaseContext(DbContextOptions options) + : base(options) + { + + } + + public DbSet Users { get; set; } + } +} diff --git a/Timeline/Program.cs b/Timeline/Program.cs index 480f5e9e..f343de44 100644 --- a/Timeline/Program.cs +++ b/Timeline/Program.cs @@ -1,25 +1,25 @@ -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.FileProviders; - -namespace Timeline -{ - public class Program - { - public static void Main(string[] args) - { - CreateWebHostBuilder(args) - .ConfigureAppConfiguration((context, config) => - { - if (context.HostingEnvironment.IsProduction()) - config.AddJsonFile(new PhysicalFileProvider("/etc/webapp/timeline/"), "config.json", true, true); - }) - .Build().Run(); - } - - public static IWebHostBuilder CreateWebHostBuilder(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup(); - } -} +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.FileProviders; + +namespace Timeline +{ + public class Program + { + public static void Main(string[] args) + { + CreateWebHostBuilder(args) + .ConfigureAppConfiguration((context, config) => + { + if (context.HostingEnvironment.IsProduction()) + config.AddJsonFile(new PhysicalFileProvider("/etc/webapp/timeline/"), "config.json", true, true); + }) + .Build().Run(); + } + + public static IWebHostBuilder CreateWebHostBuilder(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseStartup(); + } +} diff --git a/Timeline/Services/Clock.cs b/Timeline/Services/Clock.cs index 98451ad9..0499c0c6 100644 --- a/Timeline/Services/Clock.cs +++ b/Timeline/Services/Clock.cs @@ -1,32 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Timeline.Services -{ - /// - /// Convenient for unit test. - /// - public interface IClock - { - /// - /// Get current time. - /// - /// Current time. - DateTime GetCurrentTime(); - } - - public class Clock : IClock - { - public Clock() - { - - } - - public DateTime GetCurrentTime() - { - return DateTime.Now; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Timeline.Services +{ + /// + /// Convenient for unit test. + /// + public interface IClock + { + /// + /// Get current time. + /// + /// Current time. + DateTime GetCurrentTime(); + } + + public class Clock : IClock + { + public Clock() + { + + } + + public DateTime GetCurrentTime() + { + return DateTime.Now; + } + } +} diff --git a/Timeline/Services/JwtService.cs b/Timeline/Services/JwtService.cs index 94afe745..350c5e80 100644 --- a/Timeline/Services/JwtService.cs +++ b/Timeline/Services/JwtService.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; diff --git a/Timeline/Services/PasswordService.cs b/Timeline/Services/PasswordService.cs index 8c67d046..e09a1365 100644 --- a/Timeline/Services/PasswordService.cs +++ b/Timeline/Services/PasswordService.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using Microsoft.AspNetCore.Cryptography.KeyDerivation; using System; using System.Runtime.CompilerServices; using System.Security.Cryptography; diff --git a/Timeline/Startup.cs b/Timeline/Startup.cs index 242e816d..0ce6b989 100644 --- a/Timeline/Startup.cs +++ b/Timeline/Startup.cs @@ -1,90 +1,90 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Diagnostics; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Timeline.Authenticate; -using Timeline.Configs; -using Timeline.Models; -using Timeline.Services; - -namespace Timeline -{ - public class Startup - { - private const string corsPolicyName = "MyPolicy"; - - public Startup(IConfiguration configuration, IHostingEnvironment environment) - { - Environment = environment; - Configuration = configuration; - } - - public IHostingEnvironment Environment { get; } - public IConfiguration Configuration { get; } - - // 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.AddCors(options => - { - options.AddPolicy(corsPolicyName, builder => - { - if (Environment.IsProduction()) - builder.WithOrigins("https://www.crupest.xyz", "https://crupest.xyz").AllowAnyMethod().AllowAnyHeader().AllowCredentials(); - else - builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); - }); - }); - - services.Configure(Configuration.GetSection(nameof(JwtConfig))); - var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get(); - - services.AddAuthentication(AuthConstants.Scheme) - .AddScheme(AuthConstants.Scheme, AuthConstants.DisplayName, o => { }); - - services.AddScoped(); - services.AddScoped(); - services.AddTransient(); - services.AddTransient(); - - var databaseConfig = Configuration.GetSection(nameof(DatabaseConfig)).Get(); - - services.AddDbContext(options => - { - options.UseMySql(databaseConfig.ConnectionString) - .ConfigureWarnings(warnings => - { - if (Environment.IsProduction()) - warnings.Log(RelationalEventId.QueryClientEvaluationWarning); - else - warnings.Throw(RelationalEventId.QueryClientEvaluationWarning); - }); - }); - - services.AddHttpClient(); - - services.AddMemoryCache(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app) - { - app.UseCors(corsPolicyName); - - app.UseForwardedHeaders(new ForwardedHeadersOptions - { - ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto - }); - - app.UseAuthentication(); - - app.UseMvcWithDefaultRoute(); - } - } -} +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Timeline.Authenticate; +using Timeline.Configs; +using Timeline.Models; +using Timeline.Services; + +namespace Timeline +{ + public class Startup + { + private const string corsPolicyName = "MyPolicy"; + + public Startup(IConfiguration configuration, IHostingEnvironment environment) + { + Environment = environment; + Configuration = configuration; + } + + public IHostingEnvironment Environment { get; } + public IConfiguration Configuration { get; } + + // 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.AddCors(options => + { + options.AddPolicy(corsPolicyName, builder => + { + if (Environment.IsProduction()) + builder.WithOrigins("https://www.crupest.xyz", "https://crupest.xyz").AllowAnyMethod().AllowAnyHeader().AllowCredentials(); + else + builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); + }); + }); + + services.Configure(Configuration.GetSection(nameof(JwtConfig))); + var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get(); + + services.AddAuthentication(AuthConstants.Scheme) + .AddScheme(AuthConstants.Scheme, AuthConstants.DisplayName, o => { }); + + services.AddScoped(); + services.AddScoped(); + services.AddTransient(); + services.AddTransient(); + + var databaseConfig = Configuration.GetSection(nameof(DatabaseConfig)).Get(); + + services.AddDbContext(options => + { + options.UseMySql(databaseConfig.ConnectionString) + .ConfigureWarnings(warnings => + { + if (Environment.IsProduction()) + warnings.Log(RelationalEventId.QueryClientEvaluationWarning); + else + warnings.Throw(RelationalEventId.QueryClientEvaluationWarning); + }); + }); + + services.AddHttpClient(); + + services.AddMemoryCache(); + } + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app) + { + app.UseCors(corsPolicyName); + + app.UseForwardedHeaders(new ForwardedHeadersOptions + { + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto + }); + + app.UseAuthentication(); + + app.UseMvcWithDefaultRoute(); + } + } +} diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 93513bd3..5f07cabc 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -1,16 +1,16 @@ - - - netcoreapp2.2 - false - 1f6fb74d-4277-4bc0-aeea-b1fc5ffb0b43 - crupest - - - - - - - - - - + + + netcoreapp2.2 + false + 1f6fb74d-4277-4bc0-aeea-b1fc5ffb0b43 + crupest + + + + + + + + + + diff --git a/Timeline/appsettings.Development.json b/Timeline/appsettings.Development.json index b1cd5a3b..db4b074a 100644 --- a/Timeline/appsettings.Development.json +++ b/Timeline/appsettings.Development.json @@ -1,12 +1,12 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - }, - "JwtConfig": { - "SigningKey": "crupest hahahahahahahhahahahahaha" - } -} +{ + "Logging": { + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "JwtConfig": { + "SigningKey": "crupest hahahahahahahhahahahahaha" + } +} diff --git a/Timeline/appsettings.json b/Timeline/appsettings.json index 94986fbb..2d0f2b9f 100644 --- a/Timeline/appsettings.json +++ b/Timeline/appsettings.json @@ -1,11 +1,11 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Warning" - } - }, - "JwtConfig": { - "Issuer": "api.crupest.xyz", - "Audience": "api.crupest.xyz" - } -} +{ + "Logging": { + "LogLevel": { + "Default": "Warning" + } + }, + "JwtConfig": { + "Issuer": "api.crupest.xyz", + "Audience": "api.crupest.xyz" + } +} diff --git a/nuget.config b/nuget.config index 6e408d84..22519a86 100644 --- a/nuget.config +++ b/nuget.config @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/tools/convert-eol.py b/tools/convert-eol.py new file mode 100644 index 00000000..3ea8ed7c --- /dev/null +++ b/tools/convert-eol.py @@ -0,0 +1,35 @@ +# This is a python script that converts all text source codes into +# CRLF (Windows line ending) eol format and UTF-8 with NO BOM encoding. + +import glob +import os.path + +project_root = os.path.relpath(os.path.join(os.path.dirname(__file__), '..')) + + +def convert(file_path): + with open(file_path, 'r', encoding='utf-8') as open_file: + content = open_file.read() + + #if there is BOM, remove BOM + if content[0] == '\ufeff': + content = content[1:] + + with open(file_path, 'w', encoding='utf-8', newline='\r\n') as open_file: + open_file.write(content) + + +glob_list = [ + './nuget.config', + '**/*.sln', + '**/*.cs', + '**/*.csproj', + '**/appsettings*.json' +] + +for glob_pattern in glob_list: + for f in glob.glob(glob_pattern, recursive=True): + print('Converting {}'.format(f)) + convert(f) + +print('Done!!!') -- cgit v1.2.3