aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <crupest@outlook.com>2019-08-07 17:38:56 +0800
committerunknown <crupest@outlook.com>2019-08-07 17:38:56 +0800
commite283a3e745bad05a55c572646d7b20fbaaeb522d (patch)
treedf5d1325c3b73b17f4f86b71097775e9ce3fa122
parent5f5458518df0475fa36af754cae52eb31eb92fa3 (diff)
downloadtimeline-e283a3e745bad05a55c572646d7b20fbaaeb522d.tar.gz
timeline-e283a3e745bad05a55c572646d7b20fbaaeb522d.tar.bz2
timeline-e283a3e745bad05a55c572646d7b20fbaaeb522d.zip
Add script to convert encoding and eof. And of course run it.
-rw-r--r--.vscode/launch.json17
-rw-r--r--Timeline.Tests/AuthorizationUnitTest.cs136
-rw-r--r--Timeline.Tests/Helpers/Authentication/AuthenticationExtensions.cs56
-rw-r--r--Timeline.Tests/Helpers/MyWebApplicationFactory.cs46
-rw-r--r--Timeline.Tests/Helpers/ResponseExtensions.cs28
-rw-r--r--Timeline.Tests/Helpers/TestClock.cs2
-rw-r--r--Timeline.Tests/Helpers/TestUsers.cs84
-rw-r--r--Timeline.Tests/Helpers/UserInfoComparers.cs94
-rw-r--r--Timeline.Tests/Timeline.Tests.csproj2
-rw-r--r--Timeline.Tests/TokenUnitTest.cs2
-rw-r--r--Timeline.Tests/UserUnitTest.cs72
-rw-r--r--Timeline.sln61
-rw-r--r--Timeline/Authenticate/Attribute.cs42
-rw-r--r--Timeline/Authenticate/AuthHandler.cs202
-rw-r--r--Timeline/Configs/DatabaseConfig.cs14
-rw-r--r--Timeline/Configs/JwtConfig.cs30
-rw-r--r--Timeline/Controllers/TokenController.cs276
-rw-r--r--Timeline/Controllers/UserController.cs250
-rw-r--r--Timeline/Controllers/UserTestController.cs62
-rw-r--r--Timeline/Entities/Http/Common.cs74
-rw-r--r--Timeline/Entities/Http/Token.cs52
-rw-r--r--Timeline/Entities/Http/User.cs40
-rw-r--r--Timeline/Entities/PutResult.cs34
-rw-r--r--Timeline/Entities/UserInfo.cs46
-rw-r--r--Timeline/Entities/UserUtility.cs120
-rw-r--r--Timeline/Helpers/Log.cs2
-rw-r--r--Timeline/Migrations/20190412102517_InitCreate.Designer.cs86
-rw-r--r--Timeline/Migrations/20190412102517_InitCreate.cs64
-rw-r--r--Timeline/Migrations/20190412144150_AddAdminUser.Designer.cs86
-rw-r--r--Timeline/Migrations/20190412144150_AddAdminUser.cs38
-rw-r--r--Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.Designer.cs92
-rw-r--r--Timeline/Migrations/20190412153003_MakeColumnsInUserNotNull.cs104
-rw-r--r--Timeline/Migrations/20190719115321_Add-User-Version.Designer.cs98
-rw-r--r--Timeline/Migrations/20190719115321_Add-User-Version.cs46
-rw-r--r--Timeline/Migrations/DatabaseContextModelSnapshot.cs94
-rw-r--r--Timeline/Models/DatabaseContext.cs84
-rw-r--r--Timeline/Program.cs50
-rw-r--r--Timeline/Services/Clock.cs64
-rw-r--r--Timeline/Services/JwtService.cs2
-rw-r--r--Timeline/Services/PasswordService.cs2
-rw-r--r--Timeline/Startup.cs180
-rw-r--r--Timeline/Timeline.csproj32
-rw-r--r--Timeline/appsettings.Development.json24
-rw-r--r--Timeline/appsettings.json22
-rw-r--r--nuget.config16
-rw-r--r--tools/convert-eol.py35
46 files changed, 1552 insertions, 1511 deletions
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<MyWebApplicationFactory<Startup>>
- {
- private const string AuthorizeUrl = "Test/User/Authorize";
- private const string UserUrl = "Test/User/User";
- private const string AdminUrl = "Test/User/Admin";
-
- private readonly WebApplicationFactory<Startup> _factory;
-
- public AuthorizationUnitTest(MyWebApplicationFactory<Startup> 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<MyWebApplicationFactory<Startup>>
+ {
+ private const string AuthorizeUrl = "Test/User/Authorize";
+ private const string UserUrl = "Test/User/User";
+ private const string AdminUrl = "Test/User/Admin";
+
+ private readonly WebApplicationFactory<Startup> _factory;
+
+ public AuthorizationUnitTest(MyWebApplicationFactory<Startup> 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<CreateTokenResponse> 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<CreateTokenResponse>(await response.Content.ReadAsStringAsync());
- return result;
- }
-
- public static async Task<HttpClient> CreateClientWithUser<T>(this WebApplicationFactory<T> 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<CreateTokenResponse> 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<CreateTokenResponse>(await response.Content.ReadAsStringAsync());
+ return result;
+ }
+
+ public static async Task<HttpClient> CreateClientWithUser<T>(this WebApplicationFactory<T> 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<TStartup> : WebApplicationFactory<TStartup> 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<TEntry> WithTestLogging<TEntry>(this WebApplicationFactory<TEntry> factory, ITestOutputHelper outputHelper) where TEntry : class
- {
- return factory.WithWebHostBuilder(builder =>
- {
+ }
+
+ public static class WebApplicationFactoryExtensions
+ {
+ public static WebApplicationFactory<TEntry> WithTestLogging<TEntry>(this WebApplicationFactory<TEntry> 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<T> ReadBodyAsJson<T>(this HttpResponseMessage response)
- {
- return JsonConvert.DeserializeObject<T>(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<T> ReadBodyAsJson<T>(this HttpResponseMessage response)
+ {
+ return JsonConvert.DeserializeObject<T>(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<User>();
- 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<User> MockUsers { get; }
-
- public static IReadOnlyList<UserInfo> 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<User>();
+ 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<User> MockUsers { get; }
+
+ public static IReadOnlyList<UserInfo> 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<UserInfo> EqualityComparer { get; } = new EqualityComparerImpl();
- public static IComparer<UserInfo> Comparer { get; } = Comparer<UserInfo>.Create(Compare);
-
-
- private class EqualityComparerImpl : IEqualityComparer<UserInfo>
- {
- bool IEqualityComparer<UserInfo>.Equals(UserInfo x, UserInfo y)
- {
- return Compare(x, y) == 0;
- }
-
- int IEqualityComparer<UserInfo>.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<UserInfo> EqualityComparer { get; } = new EqualityComparerImpl();
+ public static IComparer<UserInfo> Comparer { get; } = Comparer<UserInfo>.Create(Compare);
+
+
+ private class EqualityComparerImpl : IEqualityComparer<UserInfo>
+ {
+ bool IEqualityComparer<UserInfo>.Equals(UserInfo x, UserInfo y)
+ {
+ return Compare(x, y) == 0;
+ }
+
+ int IEqualityComparer<UserInfo>.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 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
+<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
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<MyWebApplicationFactory<Startup>>
- {
- private readonly WebApplicationFactory<Startup> _factory;
-
- public UserUnitTest(MyWebApplicationFactory<Startup> 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<UserInfo[]>(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<MyWebApplicationFactory<Startup>>
+ {
+ private readonly WebApplicationFactory<Startup> _factory;
+
+ public UserUnitTest(MyWebApplicationFactory<Startup> 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<UserInfo[]>(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
- {
- /// <summary>
- /// The query param key to search for token. If null then query params are not searched for token. Default to <c>"token"</c>.
- /// </summary>
- public string TokenQueryParamKey { get; set; } = "token";
- }
-
- class AuthHandler : AuthenticationHandler<AuthOptions>
- {
- private readonly ILogger<AuthHandler> _logger;
- private readonly IUserService _userService;
-
- public AuthHandler(IOptionsMonitor<AuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
- : base(options, logger, encoder, clock)
- {
- _logger = logger.CreateLogger<AuthHandler>();
- _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<AuthenticateResult> 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
+ {
+ /// <summary>
+ /// The query param key to search for token. If null then query params are not searched for token. Default to <c>"token"</c>.
+ /// </summary>
+ public string TokenQueryParamKey { get; set; } = "token";
+ }
+
+ class AuthHandler : AuthenticationHandler<AuthOptions>
+ {
+ private readonly ILogger<AuthHandler> _logger;
+ private readonly IUserService _userService;
+
+ public AuthHandler(IOptionsMonitor<AuthOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
+ : base(options, logger, encoder, clock)
+ {
+ _logger = logger.CreateLogger<AuthHandler>();
+ _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<AuthenticateResult> 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; }
-
- /// <summary>
- /// Set the default value of expire offset of jwt token.
- /// Unit is second. Default is 3600 * 24 seconds, aka 1 day.
- /// </summary>
- 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; }
+
+ /// <summary>
+ /// Set the default value of expire offset of jwt token.
+ /// Unit is second. Default is 3600 * 24 seconds, aka 1 day.
+ /// </summary>
+ 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<TokenController> _logger;
- private readonly IClock _clock;
-
- public TokenController(IUserService userService, ILogger<TokenController> logger, IClock clock)
- {
- _userService = userService;
- _logger = logger;
- _clock = clock;
- }
-
- [HttpPost("create")]
- [AllowAnonymous]
- public async Task<IActionResult> 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<TokenController> _logger;
+ private readonly IClock _clock;
+
+ public TokenController(IUserService userService, ILogger<TokenController> logger, IClock clock)
+ {
+ _userService = userService;
+ _logger = logger;
+ _clock = clock;
+ }
+
+ [HttpPost("create")]
+ [AllowAnonymous]
+ public async Task<IActionResult> 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<IActionResult> 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<IActionResult> Verify([FromBody] VerifyTokenRequest request)
{
void LogFailure(string reason, int code, Exception e = null, params KeyValuePair<string, object>[] 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<UserController> _logger;
- private readonly IUserService _userService;
-
- public UserController(ILogger<UserController> logger, IUserService userService)
- {
- _logger = logger;
- _userService = userService;
- }
-
- [HttpGet("users"), AdminAuthorize]
- public async Task<ActionResult<UserInfo[]>> List()
- {
- return Ok(await _userService.ListUsers());
- }
-
- [HttpGet("user/{username}"), AdminAuthorize]
- public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<UserController> _logger;
+ private readonly IUserService _userService;
+
+ public UserController(ILogger<UserController> logger, IUserService userService)
+ {
+ _logger = logger;
+ _userService = userService;
+ }
+
+ [HttpGet("users"), AdminAuthorize]
+ public async Task<ActionResult<UserInfo[]>> List()
+ {
+ return Ok(await _userService.ListUsers());
+ }
+
+ [HttpGet("user/{username}"), AdminAuthorize]
+ public async Task<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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<IActionResult> 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
-{
- /// <summary>
- /// Represents the result of a "put" operation.
- /// </summary>
- public enum PutResult
- {
- /// <summary>
- /// Indicates the item did not exist and now is created.
- /// </summary>
- Created,
- /// <summary>
- /// Indicates the item exists already and is modified.
- /// </summary>
- Modified
- }
-}
+namespace Timeline.Entities
+{
+ /// <summary>
+ /// Represents the result of a "put" operation.
+ /// </summary>
+ public enum PutResult
+ {
+ /// <summary>
+ /// Indicates the item did not exist and now is created.
+ /// </summary>
+ Created,
+ /// <summary>
+ /// Indicates the item exists already and is modified.
+ /// </summary>
+ 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 @@
-// <auto-generated />
-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<long>("Id")
- .ValueGeneratedOnAdd()
- .HasColumnName("id");
-
- b.Property<string>("EncryptedPassword")
- .HasColumnName("password");
-
- b.Property<string>("Name")
- .HasColumnName("name");
-
- b.Property<string>("RoleString")
- .HasColumnName("roles");
-
- b.HasKey("Id");
-
- b.ToTable("user");
- });
-#pragma warning restore 612, 618
- }
- }
-}
+// <auto-generated />
+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<long>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("id");
+
+ b.Property<string>("EncryptedPassword")
+ .HasColumnName("password");
+
+ b.Property<string>("Name")
+ .HasColumnName("name");
+
+ b.Property<string>("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<long>(nullable: false)
- .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
- name = table.Column<string>(nullable: true),
- password = table.Column<string>(nullable: true),
- roles = table.Column<string>(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<long>(nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ name = table.Column<string>(nullable: true),
+ password = table.Column<string>(nullable: true),
+ roles = table.Column<string>(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 @@
-// <auto-generated />
-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<long>("Id")
- .ValueGeneratedOnAdd()
- .HasColumnName("id");
-
- b.Property<string>("EncryptedPassword")
- .HasColumnName("password");
-
- b.Property<string>("Name")
- .HasColumnName("name");
-
- b.Property<string>("RoleString")
- .HasColumnName("roles");
-
- b.HasKey("Id");
-
- b.ToTable("user");
- });
-#pragma warning restore 612, 618
- }
- }
-}
+// <auto-generated />
+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<long>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("id");
+
+ b.Property<string>("EncryptedPassword")
+ .HasColumnName("password");
+
+ b.Property<string>("Name")
+ .HasColumnName("name");
+
+ b.Property<string>("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 @@
-// <auto-generated />
-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<long>("Id")
- .ValueGeneratedOnAdd()
- .HasColumnName("id");
-
- b.Property<string>("EncryptedPassword")
- .IsRequired()
- .HasColumnName("password");
-
- b.Property<string>("Name")
- .IsRequired()
- .HasColumnName("name");
-
- b.Property<string>("RoleString")
- .IsRequired()
- .HasColumnName("roles");
-
- b.HasKey("Id");
-
- b.ToTable("user");
- });
-#pragma warning restore 612, 618
- }
- }
-}
+// <auto-generated />
+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<long>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("id");
+
+ b.Property<string>("EncryptedPassword")
+ .IsRequired()
+ .HasColumnName("password");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnName("name");
+
+ b.Property<string>("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<string>(
- name: "roles",
- table: "user",
- nullable: false,
- oldClrType: typeof(string),
- oldNullable: true);
-
- migrationBuilder.AlterColumn<string>(
- name: "name",
- table: "user",
- nullable: false,
- oldClrType: typeof(string),
- oldNullable: true);
-
- migrationBuilder.AlterColumn<string>(
- name: "password",
- table: "user",
- nullable: false,
- oldClrType: typeof(string),
- oldNullable: true);
- }
-
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.AlterColumn<string>(
- name: "roles",
- table: "user",
- nullable: true,
- oldClrType: typeof(string));
-
- migrationBuilder.AlterColumn<string>(
- name: "name",
- table: "user",
- nullable: true,
- oldClrType: typeof(string));
-
- migrationBuilder.AlterColumn<string>(
- 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<string>(
+ name: "roles",
+ table: "user",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldNullable: true);
+
+ migrationBuilder.AlterColumn<string>(
+ name: "name",
+ table: "user",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldNullable: true);
+
+ migrationBuilder.AlterColumn<string>(
+ name: "password",
+ table: "user",
+ nullable: false,
+ oldClrType: typeof(string),
+ oldNullable: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AlterColumn<string>(
+ name: "roles",
+ table: "user",
+ nullable: true,
+ oldClrType: typeof(string));
+
+ migrationBuilder.AlterColumn<string>(
+ name: "name",
+ table: "user",
+ nullable: true,
+ oldClrType: typeof(string));
+
+ migrationBuilder.AlterColumn<string>(
+ 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 @@
-// <auto-generated />
-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<long>("Id")
- .ValueGeneratedOnAdd()
- .HasColumnName("id");
-
- b.Property<string>("EncryptedPassword")
- .IsRequired()
- .HasColumnName("password");
-
- b.Property<string>("Name")
- .IsRequired()
- .HasColumnName("name");
-
- b.Property<string>("RoleString")
- .IsRequired()
- .HasColumnName("roles");
-
- b.Property<long>("Version")
- .HasColumnName("version");
-
- b.HasKey("Id");
-
- b.ToTable("user");
- });
-#pragma warning restore 612, 618
- }
- }
-}
+// <auto-generated />
+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<long>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("id");
+
+ b.Property<string>("EncryptedPassword")
+ .IsRequired()
+ .HasColumnName("password");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnName("name");
+
+ b.Property<string>("RoleString")
+ .IsRequired()
+ .HasColumnName("roles");
+
+ b.Property<long>("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<long>(
- 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<long>(
+ 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 @@
-// <auto-generated />
-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<long>("Id")
- .ValueGeneratedOnAdd()
- .HasColumnName("id");
-
- b.Property<string>("EncryptedPassword")
- .IsRequired()
- .HasColumnName("password");
-
- b.Property<string>("Name")
- .IsRequired()
- .HasColumnName("name");
-
- b.Property<string>("RoleString")
- .IsRequired()
- .HasColumnName("roles");
-
- b.Property<long>("Version")
- .HasColumnName("version");
-
- b.HasKey("Id");
-
- b.ToTable("user");
- });
-#pragma warning restore 612, 618
- }
- }
-}
+// <auto-generated />
+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<long>("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnName("id");
+
+ b.Property<string>("EncryptedPassword")
+ .IsRequired()
+ .HasColumnName("password");
+
+ b.Property<string>("Name")
+ .IsRequired()
+ .HasColumnName("name");
+
+ b.Property<string>("RoleString")
+ .IsRequired()
+ .HasColumnName("roles");
+
+ b.Property<long>("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<DatabaseContext> options)
- : base(options)
- {
-
- }
-
- public DbSet<User> 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<DatabaseContext> options)
+ : base(options)
+ {
+
+ }
+
+ public DbSet<User> 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<Startup>();
- }
-}
+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<Startup>();
+ }
+}
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
-{
- /// <summary>
- /// Convenient for unit test.
- /// </summary>
- public interface IClock
- {
- /// <summary>
- /// Get current time.
- /// </summary>
- /// <returns>Current time.</returns>
- 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
+{
+ /// <summary>
+ /// Convenient for unit test.
+ /// </summary>
+ public interface IClock
+ {
+ /// <summary>
+ /// Get current time.
+ /// </summary>
+ /// <returns>Current time.</returns>
+ 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<JwtConfig>(Configuration.GetSection(nameof(JwtConfig)));
- var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>();
-
- services.AddAuthentication(AuthConstants.Scheme)
- .AddScheme<AuthOptions, AuthHandler>(AuthConstants.Scheme, AuthConstants.DisplayName, o => { });
-
- services.AddScoped<IUserService, UserService>();
- services.AddScoped<IJwtService, JwtService>();
- services.AddTransient<IPasswordService, PasswordService>();
- services.AddTransient<IClock, Clock>();
-
- var databaseConfig = Configuration.GetSection(nameof(DatabaseConfig)).Get<DatabaseConfig>();
-
- services.AddDbContext<DatabaseContext>(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<JwtConfig>(Configuration.GetSection(nameof(JwtConfig)));
+ var jwtConfig = Configuration.GetSection(nameof(JwtConfig)).Get<JwtConfig>();
+
+ services.AddAuthentication(AuthConstants.Scheme)
+ .AddScheme<AuthOptions, AuthHandler>(AuthConstants.Scheme, AuthConstants.DisplayName, o => { });
+
+ services.AddScoped<IUserService, UserService>();
+ services.AddScoped<IJwtService, JwtService>();
+ services.AddTransient<IPasswordService, PasswordService>();
+ services.AddTransient<IClock, Clock>();
+
+ var databaseConfig = Configuration.GetSection(nameof(DatabaseConfig)).Get<DatabaseConfig>();
+
+ services.AddDbContext<DatabaseContext>(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 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
- <PropertyGroup>
- <TargetFramework>netcoreapp2.2</TargetFramework>
- <IsPackable>false</IsPackable>
- <UserSecretsId>1f6fb74d-4277-4bc0-aeea-b1fc5ffb0b43</UserSecretsId>
- <Authors>crupest</Authors>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.App" />
- <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
- <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
- <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
- <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
- </ItemGroup>
-</Project>
+<Project Sdk="Microsoft.NET.Sdk.Web">
+ <PropertyGroup>
+ <TargetFramework>netcoreapp2.2</TargetFramework>
+ <IsPackable>false</IsPackable>
+ <UserSecretsId>1f6fb74d-4277-4bc0-aeea-b1fc5ffb0b43</UserSecretsId>
+ <Authors>crupest</Authors>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.AspNetCore.App" />
+ <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.2.0" PrivateAssets="All" />
+ <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.2.3" />
+ <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.2.0" />
+ <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
+ </ItemGroup>
+</Project>
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 @@
-<?xml version="1.0" encoding="utf-8"?>
-<configuration>
- <packageSources>
- <clear/>
- <add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
- <add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" />
- </packageSources>
-</configuration>
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+ <packageSources>
+ <clear/>
+ <add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
+ <add key="aspnetcore-dev" value="https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json" />
+ </packageSources>
+</configuration>
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!!!')