Added backend
This commit is contained in:
commit
b789a8f8bf
66
.gitignore
vendored
Normal file
66
.gitignore
vendored
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||||
|
|
||||||
|
# compiled output
|
||||||
|
*/dist
|
||||||
|
*/tmp
|
||||||
|
*/out-tsc
|
||||||
|
# Only exists if Bazel was run
|
||||||
|
*/bazel-out
|
||||||
|
|
||||||
|
# dependencies
|
||||||
|
*node_modules*
|
||||||
|
|
||||||
|
# profiling files
|
||||||
|
*chrome-profiler-events*.json
|
||||||
|
*speed-measure-plugin*.json
|
||||||
|
|
||||||
|
# IDEs and editors
|
||||||
|
*/.idea
|
||||||
|
*.project
|
||||||
|
*.classpath
|
||||||
|
*.c9/
|
||||||
|
*.launch
|
||||||
|
*.settings/
|
||||||
|
*.sublime-workspace
|
||||||
|
|
||||||
|
# IDE - VSCode
|
||||||
|
*.vscode/*
|
||||||
|
!*.vscode/settings.json
|
||||||
|
!*.vscode/tasks.json
|
||||||
|
!*.vscode/launch.json
|
||||||
|
!*.vscode/extensions.json
|
||||||
|
*.history/*
|
||||||
|
|
||||||
|
# misc
|
||||||
|
*/.sass-cache
|
||||||
|
*/connect.lock
|
||||||
|
*/coverage
|
||||||
|
*/libpeerconnection.log
|
||||||
|
*npm-debug.log
|
||||||
|
*yarn-error.log
|
||||||
|
*testem.log
|
||||||
|
*/typings
|
||||||
|
|
||||||
|
# System Files
|
||||||
|
*.DS_Store
|
||||||
|
*Thumbs.db
|
||||||
|
|
||||||
|
# .Net Env
|
||||||
|
*Debug*
|
||||||
|
obj
|
||||||
|
logs
|
||||||
|
-nlog.txt
|
||||||
|
.vs
|
||||||
|
.vscode
|
||||||
|
|
||||||
|
# Python Env
|
||||||
|
*__pycache__*
|
||||||
|
*.pyc
|
||||||
|
*.idea*
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# angular & .net
|
||||||
|
dist
|
||||||
|
bin
|
||||||
|
.angular
|
||||||
|
appsettings.*.json
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Sven Heidemann
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is furnished
|
||||||
|
to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||||
|
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
10
gswi.Configuration/APISettings.cs
Normal file
10
gswi.Configuration/APISettings.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class APISettings
|
||||||
|
{
|
||||||
|
public bool RedirectToHTTPS { get; set; }
|
||||||
|
public APIVersionSettings ApiVersion { get; set; }
|
||||||
|
}
|
||||||
|
}
|
15
gswi.Configuration/APIVersionSettings.cs
Normal file
15
gswi.Configuration/APIVersionSettings.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class APIVersionSettings
|
||||||
|
{
|
||||||
|
public string Major { get; set; }
|
||||||
|
public string Minor { get; set; }
|
||||||
|
public string Micro { get; set; }
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return $"{this.Major}.{this.Minor}.{this.Micro}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Configuration/AuthentificationSettings.cs
Normal file
11
gswi.Configuration/AuthentificationSettings.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class AuthentificationSettings
|
||||||
|
{
|
||||||
|
public string SecretKey { get; set; }
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
public string Audience { get; set; }
|
||||||
|
public int TokenExpireTime { get; set; }
|
||||||
|
public int RefreshTokenExpireTime { get; set; }
|
||||||
|
}
|
||||||
|
}
|
36
gswi.Configuration/ConfigurationExtensions.cs
Normal file
36
gswi.Configuration/ConfigurationExtensions.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Configuration {
|
||||||
|
public static class ConfigurationExtensions {
|
||||||
|
public static TSetting GetSetting<TSetting>(this IConfiguration config, string sectionName)
|
||||||
|
where TSetting : new() {
|
||||||
|
var settings = new TSetting();
|
||||||
|
config.GetSection(sectionName).Bind(settings);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDbConnectionString(this IConfiguration config, string sectionName) {
|
||||||
|
var connectionString = config[$"{sectionName}:ConnectionString"];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(connectionString))
|
||||||
|
throw new Exception($"ConnectionString is not set! SectionName:{sectionName}");
|
||||||
|
|
||||||
|
var dbCredentials = config[$"{sectionName}:Credentials"];
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(dbCredentials))
|
||||||
|
connectionString += dbCredentials;
|
||||||
|
|
||||||
|
return connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetCustomer(this IConfiguration config) {
|
||||||
|
return config["CUSTOMER"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetComputerName(this IConfiguration config) {
|
||||||
|
return config["COMPUTERNAME"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
7
gswi.Configuration/Constants.cs
Normal file
7
gswi.Configuration/Constants.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace gswi.Configuration {
|
||||||
|
public static class Constants {
|
||||||
|
public const string CustomerEnvironmentVariable = "CUSTOMER";
|
||||||
|
public const string ComputerNameEnvironmentVariable = "COMPUTERNAME";
|
||||||
|
public const string CustomersDirectoryName = "customers";
|
||||||
|
}
|
||||||
|
}
|
8
gswi.Configuration/DatabaseSettings.cs
Normal file
8
gswi.Configuration/DatabaseSettings.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class DatabaseSettings
|
||||||
|
{
|
||||||
|
public string ConnectionString { get; set; }
|
||||||
|
public string Credentials { get; set; }
|
||||||
|
}
|
||||||
|
}
|
14
gswi.Configuration/EMailSettings.cs
Normal file
14
gswi.Configuration/EMailSettings.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class EMailSettings
|
||||||
|
{
|
||||||
|
public string FromName { get; set; }
|
||||||
|
public string FromAddress { get; set; }
|
||||||
|
|
||||||
|
public string MailServerAddress { get; set; }
|
||||||
|
public int MailServerPort { get; set; }
|
||||||
|
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Credentials { get; set; }
|
||||||
|
}
|
||||||
|
}
|
7
gswi.Configuration/FrontendSettings.cs
Normal file
7
gswi.Configuration/FrontendSettings.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace gswi.Configuration
|
||||||
|
{
|
||||||
|
public class FrontendSettings
|
||||||
|
{
|
||||||
|
public string URL { get; set; }
|
||||||
|
}
|
||||||
|
}
|
115
gswi.Configuration/HostExtensions.cs
Normal file
115
gswi.Configuration/HostExtensions.cs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.Extensions.Logging.EventLog;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace gswi.Configuration {
|
||||||
|
public static class HostExtensions {
|
||||||
|
// copied from https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Host.cs,
|
||||||
|
// modified to use customer environment
|
||||||
|
public static IHostBuilder CreateBuilder(string[] args) {
|
||||||
|
var builder = new HostBuilder();
|
||||||
|
|
||||||
|
builder.UseContentRoot(Directory.GetCurrentDirectory()); // UseWindowsService overrides content root to AppContext.BaseDirectory
|
||||||
|
builder.ConfigureHostConfiguration(config => {
|
||||||
|
config.AddEnvironmentVariables(prefix: "DOTNET_");
|
||||||
|
config.AddEnvironmentVariables(prefix: "LOGINCOUNTER_");
|
||||||
|
if (args != null) {
|
||||||
|
config.AddCommandLine(args);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.ConfigureAppConfiguration((hostingContext, config) => {
|
||||||
|
var env = hostingContext.HostingEnvironment;
|
||||||
|
var customerEnv = hostingContext.Configuration.GetValue<string>(Constants.CustomerEnvironmentVariable);
|
||||||
|
//var customerEnv = Environment.GetEnvironmentVariable(Constants.CustomerEnvironmentVariable);
|
||||||
|
if (!string.IsNullOrEmpty(customerEnv))
|
||||||
|
config.SetBasePath(Path.Combine(hostingContext.HostingEnvironment.ContentRootPath, Constants.CustomersDirectoryName, customerEnv));
|
||||||
|
|
||||||
|
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
|
||||||
|
config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true);
|
||||||
|
|
||||||
|
var computerName = Environment.GetEnvironmentVariable(Constants.ComputerNameEnvironmentVariable);
|
||||||
|
if (!string.IsNullOrEmpty(computerName))
|
||||||
|
config.AddJsonFile($"appsettings.{computerName}.json", optional: true, reloadOnChange: true);
|
||||||
|
|
||||||
|
if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName)) {
|
||||||
|
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
|
||||||
|
if (appAssembly != null) {
|
||||||
|
config.AddUserSecrets(appAssembly, optional: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.AddEnvironmentVariables();
|
||||||
|
config.AddEnvironmentVariables("IOTHUB_");
|
||||||
|
|
||||||
|
if (args != null) {
|
||||||
|
config.AddCommandLine(args);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ConfigureLogging((hostingContext, logging) => {
|
||||||
|
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
|
||||||
|
// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
|
||||||
|
// the defaults be overridden by the configuration.
|
||||||
|
if (isWindows) {
|
||||||
|
// Default the EventLogLoggerProvider to warning or above
|
||||||
|
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
|
||||||
|
logging.AddConsole();
|
||||||
|
logging.AddDebug();
|
||||||
|
logging.AddEventSourceLogger();
|
||||||
|
|
||||||
|
if (isWindows) {
|
||||||
|
// Add the EventLogLoggerProvider on windows machines
|
||||||
|
logging.AddEventLog();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.UseDefaultServiceProvider((context, options) => {
|
||||||
|
var isDevelopment = context.HostingEnvironment.IsDevelopment();
|
||||||
|
options.ValidateScopes = isDevelopment;
|
||||||
|
options.ValidateOnBuild = isDevelopment;
|
||||||
|
});
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogHostingEnvironment<T>(this IHost host) {
|
||||||
|
var loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
|
||||||
|
var configuration = host.Services.GetRequiredService<IConfiguration>();
|
||||||
|
var hostEnvironment = host.Services.GetRequiredService<IHostEnvironment>();
|
||||||
|
var logger = loggerFactory.CreateLogger<T>();
|
||||||
|
logger.LogInformation("Running Host...");
|
||||||
|
logger.LogInformation($"EnvironmentName:{hostEnvironment.EnvironmentName}");
|
||||||
|
logger.LogInformation($"ContentRootPath:{hostEnvironment.ContentRootPath}");
|
||||||
|
logger.LogInformation($"CurrentDirectory:{Environment.CurrentDirectory}");
|
||||||
|
logger.LogInformation($"ApplicationName:{hostEnvironment.ApplicationName}");
|
||||||
|
logger.LogInformation($"Customer:{configuration.GetCustomer()}");
|
||||||
|
logger.LogInformation($"ComputerName:{configuration.GetComputerName()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogStartError(Exception ex) {
|
||||||
|
var logDir = Path.Combine(AppContext.BaseDirectory, "logs");
|
||||||
|
if (!Directory.Exists(logDir))
|
||||||
|
Directory.CreateDirectory(logDir);
|
||||||
|
var logFile = Path.Combine(logDir, "start_error.txt");
|
||||||
|
File.AppendAllText(logFile, DateTime.Now.ToString() + ": " + ex.ToString() + Environment.NewLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ChangeCurrentDirToProjectDir() {
|
||||||
|
var currentDir = Directory.GetCurrentDirectory();
|
||||||
|
var ix = currentDir.IndexOf("\\bin"); // goto project dir, if we are running from VS
|
||||||
|
if (ix >= 0) {
|
||||||
|
var newDir = currentDir.Substring(0, ix);
|
||||||
|
Directory.SetCurrentDirectory(newDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Configuration/gswi.Configuration.csproj
Normal file
11
gswi.Configuration/gswi.Configuration.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
25
gswi.CredentialManager/Base64.cs
Normal file
25
gswi.CredentialManager/Base64.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.CredentialManager
|
||||||
|
{
|
||||||
|
public static class Base64
|
||||||
|
{
|
||||||
|
public static string Encode(string credentials)
|
||||||
|
{
|
||||||
|
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(credentials);
|
||||||
|
return System.Convert.ToBase64String(plainTextBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Decode(string credentials)
|
||||||
|
{
|
||||||
|
var base64EncodedBytes = System.Convert.FromBase64String(credentials);
|
||||||
|
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string DecodeConnectionString(string connectionString, string credentials)
|
||||||
|
{
|
||||||
|
string decodedCredentials = Decode(credentials);
|
||||||
|
return connectionString += $"password={decodedCredentials};";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
89
gswi.CredentialManager/Program.cs
Normal file
89
gswi.CredentialManager/Program.cs
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using gswi.Configuration;
|
||||||
|
|
||||||
|
namespace gswi.CredentialManager
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static IConfiguration Configuration { get; set; }
|
||||||
|
|
||||||
|
static void Menu()
|
||||||
|
{
|
||||||
|
bool end = false;
|
||||||
|
while (!end)
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
Console.WriteLine("Credential Manager: \n");
|
||||||
|
Console.WriteLine("[1] Encode");
|
||||||
|
Console.WriteLine("[2] Decode");
|
||||||
|
Console.WriteLine("[x] Exit");
|
||||||
|
Console.Write("\n> ");
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
switch (input)
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
Console.Clear();
|
||||||
|
Encode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "2":
|
||||||
|
Console.Clear();
|
||||||
|
Decode();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "x":
|
||||||
|
end = true;
|
||||||
|
Continue();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "X":
|
||||||
|
end = true;
|
||||||
|
Continue();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Console.WriteLine("Invalid input");
|
||||||
|
Continue();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Continue()
|
||||||
|
{
|
||||||
|
Console.WriteLine("\n\nPress any key to continue...");
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Menu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Encode()
|
||||||
|
{
|
||||||
|
Console.Write("String to encode: ");
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
Console.WriteLine($"{input} encoded with Base64 is: {Base64.Encode(input)}");
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Decode()
|
||||||
|
{
|
||||||
|
Console.Write("String to decode: ");
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
Console.WriteLine($"{input} decoded with Base64 is: {Base64.Decode(input)}");
|
||||||
|
Continue();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected static SettingType GetTypedSettingsFromSection<SettingType>(string sectionName) where SettingType : new()
|
||||||
|
{
|
||||||
|
var settings = new SettingType();
|
||||||
|
Configuration.GetSection(sectionName).Bind(settings);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
gswi.CredentialManager/gswi.CredentialManager.csproj
Normal file
14
gswi.CredentialManager/gswi.CredentialManager.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Configuration\gswi.Configuration.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
73
gswi.Data/DatabaseContext.cs
Normal file
73
gswi.Data/DatabaseContext.cs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||||
|
using gswi.Interface.Repositories;
|
||||||
|
using gswi.Model;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace gswi.Data
|
||||||
|
{
|
||||||
|
public class DatabaseContext : DbContext, IUnitOfWork
|
||||||
|
{
|
||||||
|
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
|
||||||
|
|
||||||
|
public DbSet<AuthUser> AuthUsers { get; set; }
|
||||||
|
|
||||||
|
public Task<int> SaveChangesAsync()
|
||||||
|
{
|
||||||
|
var changedList = ChangeTracker.Entries<IAutoGenerateDateFields>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
|
||||||
|
foreach (var item in changedList)
|
||||||
|
{
|
||||||
|
item.Entity.LastModifiedOn = DateTime.UtcNow;
|
||||||
|
if (item.State == EntityState.Added)
|
||||||
|
item.Entity.CreatedOn = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
return base.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int SaveChanges()
|
||||||
|
{
|
||||||
|
var changedList = ChangeTracker.Entries<IAutoGenerateDateFields>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
|
||||||
|
foreach (var item in changedList)
|
||||||
|
{
|
||||||
|
item.Entity.LastModifiedOn = DateTime.UtcNow;
|
||||||
|
if (item.State == EntityState.Added)
|
||||||
|
item.Entity.CreatedOn = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
return base.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
// Datum der letzten Änderung, etc. setzen
|
||||||
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
||||||
|
var changedList = ChangeTracker.Entries<IAutoGenerateDateFields>().Where(x => x.State == EntityState.Added || x.State == EntityState.Modified);
|
||||||
|
foreach (var item in changedList)
|
||||||
|
{
|
||||||
|
item.Entity.LastModifiedOn = now;
|
||||||
|
if (item.State == EntityState.Added)
|
||||||
|
item.Entity.CreatedOn = now;
|
||||||
|
}
|
||||||
|
return base.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
base.OnModelCreating(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity<AuthUser>()
|
||||||
|
.HasIndex(au => au.EMail)
|
||||||
|
.IsUnique(true);
|
||||||
|
|
||||||
|
modelBuilder.Entity<AuthUser>()
|
||||||
|
.HasIndex(au => au.ConfirmationId)
|
||||||
|
.IsUnique(true);
|
||||||
|
|
||||||
|
modelBuilder.Entity<AuthUser>()
|
||||||
|
.HasIndex(au => au.ForgotPasswordId)
|
||||||
|
.IsUnique(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
gswi.Data/DesignTimeContextFactory.cs
Normal file
22
gswi.Data/DesignTimeContextFactory.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Design;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace gswi.Data
|
||||||
|
{
|
||||||
|
public class DesignTimeContextFactory : IDesignTimeDbContextFactory<DatabaseContext>
|
||||||
|
{
|
||||||
|
public DatabaseContext CreateDbContext(string[] args)
|
||||||
|
{
|
||||||
|
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
|
||||||
|
optionsBuilder.UseMySql(
|
||||||
|
"server=localhost;user=sh_login_counter;password=mZaKBHY1lhzQoCAv;database=sh_login_counter",
|
||||||
|
new MySqlServerVersion(new Version(10, 3, 32))
|
||||||
|
);
|
||||||
|
|
||||||
|
return new DatabaseContext(optionsBuilder.Options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
gswi.Data/LinqExtension.cs
Normal file
30
gswi.Data/LinqExtension.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
|
|
||||||
|
namespace gswi.Data
|
||||||
|
{
|
||||||
|
public static class LinqExtension
|
||||||
|
{
|
||||||
|
public static IQueryable<T> OrderByMember<T>(this IQueryable<T> q, string SortField)
|
||||||
|
{
|
||||||
|
var param = Expression.Parameter(typeof(T), "p");
|
||||||
|
var prop = Expression.Property(param, SortField);
|
||||||
|
var exp = Expression.Lambda(prop, param);
|
||||||
|
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
|
||||||
|
var mce = Expression.Call(typeof(Queryable), "OrderBy", types, q.Expression, exp);
|
||||||
|
return q.Provider.CreateQuery<T>(mce);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IQueryable<T> OrderByMemberDescending<T>(this IQueryable<T> q, string SortField)
|
||||||
|
{
|
||||||
|
var param = Expression.Parameter(typeof(T), "p");
|
||||||
|
var prop = Expression.Property(param, SortField);
|
||||||
|
var exp = Expression.Lambda(prop, param);
|
||||||
|
Type[] types = new Type[] { q.ElementType, exp.Body.Type };
|
||||||
|
var mce = Expression.Call(typeof(Queryable), "OrderByDescending", types, q.Expression, exp);
|
||||||
|
return q.Provider.CreateQuery<T>(mce);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
291
gswi.Data/Migrations/20210213133159_2021_03_10.Designer.cs
generated
Normal file
291
gswi.Data/Migrations/20210213133159_2021_03_10.Designer.cs
generated
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using gswi.Data;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20210213133159_2021_03_10")]
|
||||||
|
partial class _2021_03_10
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.AuthUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<string>("ConfirmationId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("EMail")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("ForgotPasswordId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("RefreshToken")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RefreshTokenExpiryTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ConfirmationId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("EMail")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ForgotPasswordId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("AuthUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Domain", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Domains");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<byte[]>("IPAddress")
|
||||||
|
.HasColumnType("varbinary(1400)")
|
||||||
|
.HasMaxLength(1400);
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<long>("OSId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasIndex("OSId");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Hosts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Logins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.OperatingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OperatingSystems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Discriminator", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("Discriminator").HasValue("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("DomainUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("HostUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Hosts")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.OperatingSystem", "OS")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OSId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("HostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.User", "User")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("HostId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
249
gswi.Data/Migrations/20210213133159_2021_03_10.cs
Normal file
249
gswi.Data/Migrations/20210213133159_2021_03_10.cs
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class _2021_03_10 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AuthUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
FirstName = table.Column<string>(nullable: true),
|
||||||
|
LastName = table.Column<string>(nullable: true),
|
||||||
|
EMail = table.Column<string>(nullable: true),
|
||||||
|
Password = table.Column<string>(nullable: true),
|
||||||
|
RefreshToken = table.Column<string>(nullable: true),
|
||||||
|
ConfirmationId = table.Column<string>(nullable: true),
|
||||||
|
ForgotPasswordId = table.Column<string>(nullable: true),
|
||||||
|
RefreshTokenExpiryTime = table.Column<DateTime>(nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AuthUsers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Domains",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
NotifyWhenLogin = table.Column<bool>(nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Domains", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "OperatingSystems",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_OperatingSystems", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Hosts",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
IPAddress = table.Column<byte[]>(maxLength: 1400, nullable: true),
|
||||||
|
NotifyWhenLogin = table.Column<bool>(nullable: false),
|
||||||
|
DomainId = table.Column<long>(nullable: true),
|
||||||
|
OSId = table.Column<long>(nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Hosts", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Hosts_Domains_DomainId",
|
||||||
|
column: x => x.DomainId,
|
||||||
|
principalTable: "Domains",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Hosts_OperatingSystems_OSId",
|
||||||
|
column: x => x.OSId,
|
||||||
|
principalTable: "OperatingSystems",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Users",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
NotifyWhenLogin = table.Column<bool>(nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
Discriminator = table.Column<string>(nullable: false),
|
||||||
|
DomainId = table.Column<long>(nullable: true),
|
||||||
|
HostId = table.Column<long>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Users", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Users_Domains_DomainId",
|
||||||
|
column: x => x.DomainId,
|
||||||
|
principalTable: "Domains",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Users_Hosts_HostId",
|
||||||
|
column: x => x.HostId,
|
||||||
|
principalTable: "Hosts",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Logins",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<long>(nullable: false)
|
||||||
|
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||||
|
Time = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
HostId = table.Column<long>(nullable: false),
|
||||||
|
UserId = table.Column<long>(nullable: false),
|
||||||
|
CreatedOn = table.Column<DateTimeOffset>(nullable: false),
|
||||||
|
LastModifiedOn = table.Column<DateTimeOffset>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Logins", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Logins_Hosts_HostId",
|
||||||
|
column: x => x.HostId,
|
||||||
|
principalTable: "Hosts",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Logins_Users_UserId",
|
||||||
|
column: x => x.UserId,
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AuthUsers_ConfirmationId",
|
||||||
|
table: "AuthUsers",
|
||||||
|
column: "ConfirmationId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AuthUsers_EMail",
|
||||||
|
table: "AuthUsers",
|
||||||
|
column: "EMail",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AuthUsers_ForgotPasswordId",
|
||||||
|
table: "AuthUsers",
|
||||||
|
column: "ForgotPasswordId",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Hosts_DomainId",
|
||||||
|
table: "Hosts",
|
||||||
|
column: "DomainId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Hosts_OSId",
|
||||||
|
table: "Hosts",
|
||||||
|
column: "OSId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Hosts_DomainId_Name",
|
||||||
|
table: "Hosts",
|
||||||
|
columns: new[] { "DomainId", "Name" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Hosts_IPAddress_Name",
|
||||||
|
table: "Hosts",
|
||||||
|
columns: new[] { "IPAddress", "Name" },
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Logins_HostId",
|
||||||
|
table: "Logins",
|
||||||
|
column: "HostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Logins_UserId",
|
||||||
|
table: "Logins",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_OperatingSystems_Name",
|
||||||
|
table: "OperatingSystems",
|
||||||
|
column: "Name",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_DomainId",
|
||||||
|
table: "Users",
|
||||||
|
column: "DomainId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_HostId",
|
||||||
|
table: "Users",
|
||||||
|
column: "HostId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_Discriminator_Name",
|
||||||
|
table: "Users",
|
||||||
|
columns: new[] { "Discriminator", "Name" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AuthUsers");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Logins");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Hosts");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Domains");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "OperatingSystems");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
294
gswi.Data/Migrations/20210217201310_2021_03_13.Designer.cs
generated
Normal file
294
gswi.Data/Migrations/20210217201310_2021_03_13.Designer.cs
generated
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using gswi.Data;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20210217201310_2021_03_13")]
|
||||||
|
partial class _2021_03_13
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.AuthUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("AuthRole")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConfirmationId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("EMail")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("ForgotPasswordId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("RefreshToken")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RefreshTokenExpiryTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ConfirmationId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("EMail")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ForgotPasswordId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("AuthUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Domain", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Domains");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<byte[]>("IPAddress")
|
||||||
|
.HasColumnType("varbinary(1400)")
|
||||||
|
.HasMaxLength(1400);
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<long>("OSId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasIndex("OSId");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Hosts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Logins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.OperatingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OperatingSystems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Discriminator", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("Discriminator").HasValue("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("DomainUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("HostUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Hosts")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.OperatingSystem", "OS")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OSId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("HostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.User", "User")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("HostId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
gswi.Data/Migrations/20210217201310_2021_03_13.cs
Normal file
23
gswi.Data/Migrations/20210217201310_2021_03_13.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class _2021_03_13 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<int>(
|
||||||
|
name: "AuthRole",
|
||||||
|
table: "AuthUsers",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AuthRole",
|
||||||
|
table: "AuthUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
291
gswi.Data/Migrations/20210220140309_2021_03_14.Designer.cs
generated
Normal file
291
gswi.Data/Migrations/20210220140309_2021_03_14.Designer.cs
generated
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using gswi.Data;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20210220140309_2021_03_14")]
|
||||||
|
partial class _2021_03_14
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.AuthUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("AuthRole")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConfirmationId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("EMail")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("ForgotPasswordId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("RefreshToken")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RefreshTokenExpiryTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ConfirmationId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("EMail")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ForgotPasswordId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("AuthUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Domain", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Domains");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<byte[]>("IPAddress")
|
||||||
|
.HasColumnType("varbinary(1400)")
|
||||||
|
.HasMaxLength(1400);
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<long>("OSId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasIndex("OSId");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Hosts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Logins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.OperatingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OperatingSystems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("Discriminator").HasValue("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("DomainUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("HostUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Hosts")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.OperatingSystem", "OS")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OSId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("HostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.User", "User")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("HostId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
gswi.Data/Migrations/20210220140309_2021_03_14.cs
Normal file
53
gswi.Data/Migrations/20210220140309_2021_03_14.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
public partial class _2021_03_14 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Users_Discriminator_Name",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
table: "Users",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(255) CHARACTER SET utf8mb4",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Discriminator",
|
||||||
|
table: "Users",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
table: "Users",
|
||||||
|
type: "varchar(255) CHARACTER SET utf8mb4",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "Discriminator",
|
||||||
|
table: "Users",
|
||||||
|
type: "varchar(255) CHARACTER SET utf8mb4",
|
||||||
|
nullable: false,
|
||||||
|
oldClrType: typeof(string));
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Users_Discriminator_Name",
|
||||||
|
table: "Users",
|
||||||
|
columns: new[] { "Discriminator", "Name" },
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
289
gswi.Data/Migrations/DatabaseContextModelSnapshot.cs
Normal file
289
gswi.Data/Migrations/DatabaseContextModelSnapshot.cs
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
using gswi.Data;
|
||||||
|
|
||||||
|
namespace gswi.Data.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
partial class DatabaseContextModelSnapshot : ModelSnapshot
|
||||||
|
{
|
||||||
|
protected override void BuildModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "3.1.9")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.AuthUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("AuthRole")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ConfirmationId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("EMail")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("FirstName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("ForgotPasswordId")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("LastName")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("Password")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<string>("RefreshToken")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTime>("RefreshTokenExpiryTime")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ConfirmationId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("EMail")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("ForgotPasswordId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("AuthUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Domain", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Domains");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<byte[]>("IPAddress")
|
||||||
|
.HasColumnType("varbinary(1400)")
|
||||||
|
.HasMaxLength(1400);
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.Property<long>("OSId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasIndex("OSId");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.HasIndex("IPAddress", "Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("Hosts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("Time")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<long>("UserId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
|
b.ToTable("Logins");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.OperatingSystem", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("varchar(255) CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("Name")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OperatingSystems");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.User", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("CreatedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Discriminator")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<DateTimeOffset>("LastModifiedOn")
|
||||||
|
.HasColumnType("datetime(6)");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext CHARACTER SET utf8mb4");
|
||||||
|
|
||||||
|
b.Property<bool>("NotifyWhenLogin")
|
||||||
|
.HasColumnType("tinyint(1)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Users");
|
||||||
|
|
||||||
|
b.HasDiscriminator<string>("Discriminator").HasValue("User");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("DomainId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("DomainId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("DomainUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasBaseType("gswi.Model.User");
|
||||||
|
|
||||||
|
b.Property<long?>("HostId")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.HasIndex("HostId");
|
||||||
|
|
||||||
|
b.HasDiscriminator().HasValue("HostUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Host", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Hosts")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.OperatingSystem", "OS")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("OSId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.Login", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("HostId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("gswi.Model.User", "User")
|
||||||
|
.WithMany("Logins")
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.DomainUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Domain", "Domain")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("DomainId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("gswi.Model.HostUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("gswi.Model.Host", "Host")
|
||||||
|
.WithMany("Users")
|
||||||
|
.HasForeignKey("HostId");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
gswi.Data/Repositories/AuthUserRepositoryImpl.cs
Normal file
125
gswi.Data/Repositories/AuthUserRepositoryImpl.cs
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using gswi.Interface.Repositories;
|
||||||
|
using gswi.Model;
|
||||||
|
using gswi.Share.Common;
|
||||||
|
|
||||||
|
namespace gswi.Data.Repositories
|
||||||
|
{
|
||||||
|
public class AuthUserRepositoryImpl : IAuthUserRepository
|
||||||
|
{
|
||||||
|
private readonly DatabaseContext _databaseContext;
|
||||||
|
|
||||||
|
private DbSet<AuthUser> _authUsers { get { return _databaseContext.AuthUsers; } }
|
||||||
|
|
||||||
|
public AuthUserRepositoryImpl(DatabaseContext databaseContext)
|
||||||
|
{
|
||||||
|
_databaseContext = databaseContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AuthUser>> GetAllAuthUsersAsync()
|
||||||
|
{
|
||||||
|
return await _authUsers
|
||||||
|
.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(List<AuthUser>, int totalCount)> GetFilteredAuthUsersAsync(AuthUserSelectCriterion selectCriterion)
|
||||||
|
{
|
||||||
|
var query = _authUsers
|
||||||
|
.Select(u => new AuthUser
|
||||||
|
{
|
||||||
|
Id = u.Id,
|
||||||
|
FirstName = u.FirstName,
|
||||||
|
LastName = u.LastName,
|
||||||
|
EMail = u.EMail,
|
||||||
|
ConfirmationId = u.ConfirmationId,
|
||||||
|
AuthRole = u.AuthRole
|
||||||
|
});
|
||||||
|
|
||||||
|
// FirstName filter
|
||||||
|
if (!string.IsNullOrWhiteSpace(selectCriterion.FirstName))
|
||||||
|
query = query.Where(u => u.FirstName.Contains(selectCriterion.FirstName) || u.FirstName == selectCriterion.FirstName);
|
||||||
|
|
||||||
|
// LastName filter
|
||||||
|
if (!string.IsNullOrWhiteSpace(selectCriterion.LastName))
|
||||||
|
query = query.Where(u => u.LastName.Contains(selectCriterion.LastName) || u.LastName == selectCriterion.LastName);
|
||||||
|
|
||||||
|
// EMail filter
|
||||||
|
if (!string.IsNullOrWhiteSpace(selectCriterion.EMail))
|
||||||
|
query = query.Where(u => u.EMail.Contains(selectCriterion.EMail) || u.EMail == selectCriterion.EMail);
|
||||||
|
|
||||||
|
// AuthRole filter
|
||||||
|
if (selectCriterion.AuthRole != null)
|
||||||
|
query = query.Where(u => u.AuthRole == (AuthRoles)selectCriterion.AuthRole);
|
||||||
|
|
||||||
|
// sort
|
||||||
|
if (!string.IsNullOrWhiteSpace(selectCriterion.SortColumn) && !string.IsNullOrWhiteSpace(selectCriterion.SortDirection))
|
||||||
|
{
|
||||||
|
var critSortDirection = selectCriterion.SortDirection?.ToLower();
|
||||||
|
if (critSortDirection == "desc" || critSortDirection == "descending")
|
||||||
|
query = query.OrderByMemberDescending(selectCriterion.SortColumn);
|
||||||
|
else
|
||||||
|
query = query.OrderByMember(selectCriterion.SortColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
var skip = selectCriterion.PageSize * selectCriterion.PageIndex;
|
||||||
|
if (skip < 0)
|
||||||
|
skip = 0;
|
||||||
|
|
||||||
|
var totalCount = await query.CountAsync();
|
||||||
|
|
||||||
|
var list = await query.Skip(skip).Take(selectCriterion.PageSize).AsNoTracking().ToListAsync();
|
||||||
|
|
||||||
|
return (list, totalCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUser> GetAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
return await _authUsers
|
||||||
|
.Where(au => au.EMail == email)
|
||||||
|
.FirstAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUser> FindAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
return await _authUsers
|
||||||
|
.Where(au => au.EMail == email)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUser> FindAuthUserByEMailConfirmationIdAsync(string id)
|
||||||
|
{
|
||||||
|
return await _authUsers
|
||||||
|
.Where(au => au.ConfirmationId == id)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUser> FindAuthUserByEMailForgotPasswordIdAsync(string id)
|
||||||
|
{
|
||||||
|
return await _authUsers
|
||||||
|
.Where(au => au.ForgotPasswordId == id)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAuthUser(AuthUser user)
|
||||||
|
{
|
||||||
|
_authUsers.Add(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
var au = await _authUsers
|
||||||
|
.Where(au => au.EMail == email)
|
||||||
|
.FirstAsync();
|
||||||
|
|
||||||
|
_authUsers.Remove(au);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteAuthUser(AuthUser user)
|
||||||
|
{
|
||||||
|
_authUsers.Remove(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
gswi.Data/gswi.Data.csproj
Normal file
23
gswi.Data/gswi.Data.csproj
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.2">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.2">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Model\gswi.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Interface\gswi.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Share.Common\gswi.Share.Common.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
20
gswi.Interface/Repositories/IAuthUserRepository.cs
Normal file
20
gswi.Interface/Repositories/IAuthUserRepository.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using gswi.Model;
|
||||||
|
using gswi.Share.Common;
|
||||||
|
|
||||||
|
namespace gswi.Interface.Repositories
|
||||||
|
{
|
||||||
|
public interface IAuthUserRepository
|
||||||
|
{
|
||||||
|
Task<List<AuthUser>> GetAllAuthUsersAsync();
|
||||||
|
Task<(List<AuthUser>, int totalCount)> GetFilteredAuthUsersAsync(AuthUserSelectCriterion selectCriterion);
|
||||||
|
Task<AuthUser> GetAuthUserByEMailAsync(string email);
|
||||||
|
Task<AuthUser> FindAuthUserByEMailAsync(string email);
|
||||||
|
Task<AuthUser> FindAuthUserByEMailConfirmationIdAsync(string id);
|
||||||
|
Task<AuthUser> FindAuthUserByEMailForgotPasswordIdAsync(string id);
|
||||||
|
void AddAuthUser(AuthUser user);
|
||||||
|
Task DeleteAuthUserByEMailAsync(string email);
|
||||||
|
void DeleteAuthUser(AuthUser user);
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Interface/Repositories/IUnitOfWork.cs
Normal file
11
gswi.Interface/Repositories/IUnitOfWork.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace gswi.Interface.Repositories {
|
||||||
|
public interface IUnitOfWork : IDisposable {
|
||||||
|
int SaveChanges();
|
||||||
|
Task<int> SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
28
gswi.Interface/Services/IAuthService.cs
Normal file
28
gswi.Interface/Services/IAuthService.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using gswi.Model.DTOs;
|
||||||
|
using gswi.Share.Common;
|
||||||
|
|
||||||
|
namespace gswi.Interface.Services
|
||||||
|
{
|
||||||
|
public interface IAuthService
|
||||||
|
{
|
||||||
|
Task<List<AuthUserDTO>> GetAllAuthUsersAsync();
|
||||||
|
Task<GetFilteredAuthUsersResultDTO> GetFilteredAuthUsersAsync(AuthUserSelectCriterion selectCriterion);
|
||||||
|
Task<AuthUserDTO> GetAuthUserByEMailAsync(string email);
|
||||||
|
Task<AuthUserDTO> FindAuthUserByEMailAsync(string email);
|
||||||
|
Task<long> AddAuthUserAsync(AuthUserDTO userDTO);
|
||||||
|
Task<bool> ConfirmEMail(string id);
|
||||||
|
Task<TokenDTO> Login(AuthUserDTO userDTO);
|
||||||
|
Task ForgotPassword(string email);
|
||||||
|
Task<EMailStringDTO> ConfirmForgotPassword(string id);
|
||||||
|
Task ResetPassword(ResetPasswordDTO rpDTO);
|
||||||
|
Task UpdateUser(UpdateUserDTO updateUserDTO);
|
||||||
|
Task UpdateUserAsAdmin(AdminUpdateUserDTO updateUserDTO);
|
||||||
|
Task<TokenDTO> Refresh(TokenDTO tokenDTO);
|
||||||
|
Task Revoke(TokenDTO tokenDTO);
|
||||||
|
Task DeleteAuthUserByEMailAsync(string email);
|
||||||
|
Task DeleteAuthUserAsync(AuthUserDTO userDTO);
|
||||||
|
}
|
||||||
|
}
|
12
gswi.Interface/gswi.Interface.csproj
Normal file
12
gswi.Interface/gswi.Interface.csproj
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Model\gswi.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Share.Common\gswi.Share.Common.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
10
gswi.Model/AuthRoles.cs
Normal file
10
gswi.Model/AuthRoles.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model
|
||||||
|
{
|
||||||
|
public enum AuthRoles
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
Admin = 1
|
||||||
|
}
|
||||||
|
}
|
34
gswi.Model/AuthUser.cs
Normal file
34
gswi.Model/AuthUser.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using gswi.Model.DTOs;
|
||||||
|
|
||||||
|
namespace gswi.Model
|
||||||
|
{
|
||||||
|
public class AuthUser : IAutoGenerateDateFields
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
public string LastName { get; set; }
|
||||||
|
public string EMail { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public AuthRoles AuthRole { get; set; }
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
public string ConfirmationId { get; set; }
|
||||||
|
public string ForgotPasswordId { get; set; }
|
||||||
|
public DateTime RefreshTokenExpiryTime { get; set; }
|
||||||
|
public DateTimeOffset CreatedOn { get; set; }
|
||||||
|
public DateTimeOffset LastModifiedOn { get; set; }
|
||||||
|
|
||||||
|
public AuthUserDTO ToAuthUserDTO()
|
||||||
|
{
|
||||||
|
return new AuthUserDTO
|
||||||
|
{
|
||||||
|
Id = this.Id,
|
||||||
|
FirstName = this.FirstName,
|
||||||
|
LastName = this.LastName,
|
||||||
|
EMail = this.EMail,
|
||||||
|
IsConfirmed = this.ConfirmationId == null,
|
||||||
|
AuthRole = this.AuthRole
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Model/DTOs/AdminUpdateUserDTO.cs
Normal file
11
gswi.Model/DTOs/AdminUpdateUserDTO.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class AdminUpdateUserDTO
|
||||||
|
{
|
||||||
|
public AuthUserDTO AuthUserDTO { get; set; }
|
||||||
|
public AuthUserDTO NewAuthUserDTO { get; set; }
|
||||||
|
public bool ChangePassword { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Model/DTOs/ApiVersionDTO.cs
Normal file
11
gswi.Model/DTOs/ApiVersionDTO.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class ApiVersionDTO
|
||||||
|
{
|
||||||
|
public string Major { get; set; }
|
||||||
|
public string Minor { get; set; }
|
||||||
|
public string Micro { get; set; }
|
||||||
|
}
|
||||||
|
}
|
27
gswi.Model/DTOs/AuthUserDTO.cs
Normal file
27
gswi.Model/DTOs/AuthUserDTO.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class AuthUserDTO
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
public string LastName { get; set; }
|
||||||
|
public string EMail { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public bool IsConfirmed { get; set; }
|
||||||
|
public AuthRoles AuthRole { get; set; }
|
||||||
|
|
||||||
|
public AuthUser ToAuthUser()
|
||||||
|
{
|
||||||
|
return new AuthUser
|
||||||
|
{
|
||||||
|
Id = this.Id,
|
||||||
|
FirstName = this.FirstName,
|
||||||
|
LastName = this.LastName,
|
||||||
|
EMail = this.EMail,
|
||||||
|
Password = this.Password,
|
||||||
|
AuthRole = this.AuthRole
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
9
gswi.Model/DTOs/EMailStringDTO.cs
Normal file
9
gswi.Model/DTOs/EMailStringDTO.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class EMailStringDTO
|
||||||
|
{
|
||||||
|
public string EMail { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
gswi.Model/DTOs/GetFilteredAuthUsersResultDTO.cs
Normal file
10
gswi.Model/DTOs/GetFilteredAuthUsersResultDTO.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class GetFilteredAuthUsersResultDTO
|
||||||
|
{
|
||||||
|
public List<AuthUserDTO> Users { get; set; }
|
||||||
|
public int TotalCount { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
gswi.Model/DTOs/ResetPasswordDTO.cs
Normal file
10
gswi.Model/DTOs/ResetPasswordDTO.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class ResetPasswordDTO
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
22
gswi.Model/DTOs/SettingsDTO.cs
Normal file
22
gswi.Model/DTOs/SettingsDTO.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class SettingsDTO
|
||||||
|
{
|
||||||
|
public string WebVersion { get; set; }
|
||||||
|
public string ApiVersion { get; set; }
|
||||||
|
public string ConfigPath { get; set; }
|
||||||
|
public string WebBaseURL { get; set; }
|
||||||
|
public string ApiBaseURL { get; set; }
|
||||||
|
|
||||||
|
public int TokenExpireTime { get; set; }
|
||||||
|
public int RefreshTokenExpireTime { get; set; }
|
||||||
|
|
||||||
|
public string MailUser { get; set; }
|
||||||
|
public int MailPort { get; set; }
|
||||||
|
public string MailHost { get; set; }
|
||||||
|
public string MailTransceiver { get; set; }
|
||||||
|
public string MailTransceiverAddress { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
gswi.Model/DTOs/TokenDTO.cs
Normal file
8
gswi.Model/DTOs/TokenDTO.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class TokenDTO
|
||||||
|
{
|
||||||
|
public string Token { get; set; }
|
||||||
|
public string RefreshToken { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
gswi.Model/DTOs/UpdateUserDTO.cs
Normal file
10
gswi.Model/DTOs/UpdateUserDTO.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public class UpdateUserDTO
|
||||||
|
{
|
||||||
|
public AuthUserDTO AuthUserDTO { get; set; }
|
||||||
|
public AuthUserDTO NewAuthUserDTO { get; set; }
|
||||||
|
}
|
||||||
|
}
|
13
gswi.Model/DTOs/UserDTO.cs
Normal file
13
gswi.Model/DTOs/UserDTO.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace gswi.Model.DTOs
|
||||||
|
{
|
||||||
|
public abstract class UserDTO
|
||||||
|
{
|
||||||
|
public long Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public bool NotifyWhenLogin { get; set; }
|
||||||
|
}
|
||||||
|
}
|
21
gswi.Model/Filter/ErrorDTO.cs
Normal file
21
gswi.Model/Filter/ErrorDTO.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
namespace gswi.Model.Filters
|
||||||
|
{
|
||||||
|
public enum ErrorType {
|
||||||
|
ValidationError,
|
||||||
|
Exception
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ErrorDto {
|
||||||
|
public ServiceErrorCode ErrorCode { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
|
||||||
|
public ErrorDto(string message)
|
||||||
|
: this(ServiceErrorCode.Unknown, message) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ErrorDto(ServiceErrorCode errorCode, string message) {
|
||||||
|
Message = message;
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
gswi.Model/Filter/ServiceErrorCode.cs
Normal file
21
gswi.Model/Filter/ServiceErrorCode.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Threading;
|
||||||
|
namespace gswi.Model.Filters
|
||||||
|
{
|
||||||
|
public enum ServiceErrorCode
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
|
||||||
|
InvalidDependencies = 1,
|
||||||
|
InvalidData = 2,
|
||||||
|
NotFound = 3,
|
||||||
|
DataAlreadyExists = 4,
|
||||||
|
UnableToAdd = 5,
|
||||||
|
UnableToDelete = 6,
|
||||||
|
|
||||||
|
InvalidUser = 7,
|
||||||
|
|
||||||
|
ConnectionFailed = 8,
|
||||||
|
Timeout = 9,
|
||||||
|
MailError = 10
|
||||||
|
}
|
||||||
|
}
|
23
gswi.Model/Filter/ServiceException.cs
Normal file
23
gswi.Model/Filter/ServiceException.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.Model.Filters
|
||||||
|
{
|
||||||
|
public class ServiceException: Exception {
|
||||||
|
public ServiceErrorCode ErrorCode { get; set; }
|
||||||
|
public string ErrorMessage { get; set; }
|
||||||
|
public string Nameof { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public ServiceException(ServiceErrorCode errorCode, string errorMessage) {
|
||||||
|
ErrorCode = errorCode;
|
||||||
|
ErrorMessage = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetMessage() {
|
||||||
|
return ErrorMessage;
|
||||||
|
}
|
||||||
|
public string GetDetailedMessage() {
|
||||||
|
return $"{nameof(ServiceException)} - ErrorCode: {ErrorCode} - ErrorMessage: {ErrorMessage}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
gswi.Model/IAutoGenerateDateFields.cs
Normal file
10
gswi.Model/IAutoGenerateDateFields.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace gswi.Model {
|
||||||
|
public interface IAutoGenerateDateFields {
|
||||||
|
DateTimeOffset CreatedOn { get; set; }
|
||||||
|
DateTimeOffset LastModifiedOn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
8
gswi.Model/gswi.Model.csproj
Normal file
8
gswi.Model/gswi.Model.csproj
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
10
gswi.SMTP.Interface/ISMTPClient.cs
Normal file
10
gswi.SMTP.Interface/ISMTPClient.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using gswi.SMTP.Model;
|
||||||
|
|
||||||
|
namespace gswi.SMTP.Interface
|
||||||
|
{
|
||||||
|
public interface ISMTPClient
|
||||||
|
{
|
||||||
|
Task SendEmailAsync(EMail email);
|
||||||
|
}
|
||||||
|
}
|
11
gswi.SMTP.Interface/gswi.SMTP.Interface.csproj
Normal file
11
gswi.SMTP.Interface/gswi.SMTP.Interface.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Model\gswi.SMTP.Model.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
11
gswi.SMTP.Model/EMail.cs
Normal file
11
gswi.SMTP.Model/EMail.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi.SMTP.Model
|
||||||
|
{
|
||||||
|
public class EMail
|
||||||
|
{
|
||||||
|
public string Receiver { get; set; }
|
||||||
|
public string Subject { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
7
gswi.SMTP.Model/gswi.SMTP.Model.csproj
Normal file
7
gswi.SMTP.Model/gswi.SMTP.Model.csproj
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
80
gswi.SMTP.Service/SMTPClientImpl.cs
Normal file
80
gswi.SMTP.Service/SMTPClientImpl.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using MailKit.Net.Smtp;
|
||||||
|
using MailKit.Security;
|
||||||
|
using MimeKit;
|
||||||
|
using MimeKit.Text;
|
||||||
|
using NLog;
|
||||||
|
using gswi.Configuration;
|
||||||
|
using gswi.Model.Filters;
|
||||||
|
using gswi.SMTP.Interface;
|
||||||
|
using gswi.SMTP.Model;
|
||||||
|
|
||||||
|
namespace gswi.SMTP.Service
|
||||||
|
{
|
||||||
|
public class SMTPClientImpl : ISMTPClient
|
||||||
|
{
|
||||||
|
private readonly EMailSettings _emailSettings;
|
||||||
|
private static Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public SMTPClientImpl(EMailSettings emailSettings)
|
||||||
|
{
|
||||||
|
this._emailSettings = emailSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendEmailAsync(EMail email)
|
||||||
|
{
|
||||||
|
var emailMessage = new MimeMessage();
|
||||||
|
|
||||||
|
emailMessage.From.Add(new MailboxAddress(_emailSettings.FromName, _emailSettings.FromAddress));
|
||||||
|
emailMessage.To.Add(new MailboxAddress("", email.Receiver));
|
||||||
|
emailMessage.Subject = email.Subject;
|
||||||
|
emailMessage.Body = new TextPart(TextFormat.Html) { Text = $"{email.Message}<br><br>Dies ist eine Automatische E-Mail.<br>Gesendet von Login counter @ {System.Net.Dns.GetHostName()}" };
|
||||||
|
|
||||||
|
using (var client = new SmtpClient())
|
||||||
|
{
|
||||||
|
client.Timeout = 30000;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client.ConnectAsync(_emailSettings.MailServerAddress, _emailSettings.MailServerPort, SecureSocketOptions.Auto).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex);
|
||||||
|
throw new ServiceException(ServiceErrorCode.ConnectionFailed, "Connection to mail server failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client.AuthenticateAsync(new NetworkCredential(_emailSettings.Username, _emailSettings.Credentials));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex);
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "Authentification to mail server failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client.SendAsync(emailMessage).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex);
|
||||||
|
throw new ServiceException(ServiceErrorCode.MailError, "Unable to send email");
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await client.DisconnectAsync(true).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex);
|
||||||
|
throw new ServiceException(ServiceErrorCode.ConnectionFailed, "Unable to disconnect from mail server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
gswi.SMTP.Service/gswi.SMTP.Service.csproj
Normal file
15
gswi.SMTP.Service/gswi.SMTP.Service.csproj
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Model\gswi.SMTP.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Interface\gswi.SMTP.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Configuration\gswi.Configuration.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Model\gswi.Model.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NETCore.MailKit" Version="2.0.3"/>
|
||||||
|
<PackageReference Include="nlog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
604
gswi.Service/AuthServiceImpl.cs
Normal file
604
gswi.Service/AuthServiceImpl.cs
Normal file
@ -0,0 +1,604 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using NLog;
|
||||||
|
using gswi.Configuration;
|
||||||
|
using gswi.Interface.Repositories;
|
||||||
|
using gswi.Interface.Services;
|
||||||
|
using gswi.Model;
|
||||||
|
using gswi.Model.DTOs;
|
||||||
|
using gswi.Model.Filters;
|
||||||
|
using gswi.Share.Common;
|
||||||
|
using gswi.SMTP.Interface;
|
||||||
|
using gswi.SMTP.Model;
|
||||||
|
|
||||||
|
namespace gswi.Service
|
||||||
|
{
|
||||||
|
public class AuthServiceImpl : IAuthService
|
||||||
|
{
|
||||||
|
private readonly IAuthUserRepository _authUserRepository;
|
||||||
|
private readonly IUnitOfWork _unitOfWork;
|
||||||
|
private readonly AuthentificationSettings _authSettings;
|
||||||
|
private readonly ISMTPClient _smtpClient;
|
||||||
|
private readonly FrontendSettings _frontendSettings;
|
||||||
|
private static Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
private static Random random = new Random();
|
||||||
|
|
||||||
|
public AuthServiceImpl(
|
||||||
|
IAuthUserRepository authUserRepository,
|
||||||
|
IUnitOfWork unitOfWork,
|
||||||
|
AuthentificationSettings authSettings,
|
||||||
|
ISMTPClient smtpClient,
|
||||||
|
FrontendSettings frontendSettings
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_unitOfWork = unitOfWork;
|
||||||
|
_authUserRepository = authUserRepository;
|
||||||
|
_authSettings = authSettings;
|
||||||
|
_smtpClient = smtpClient;
|
||||||
|
_frontendSettings = frontendSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string _randomString(int length)
|
||||||
|
{
|
||||||
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||||
|
return new string(Enumerable.Repeat(chars, length)
|
||||||
|
.Select(s => s[random.Next(s.Length)]).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _generateToken(IEnumerable<Claim> claims)
|
||||||
|
{
|
||||||
|
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_authSettings.SecretKey));
|
||||||
|
var signingCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256);
|
||||||
|
|
||||||
|
var tokenOptions = new JwtSecurityToken(
|
||||||
|
issuer: _authSettings.Issuer,
|
||||||
|
audience: _authSettings.Audience,
|
||||||
|
claims: claims,
|
||||||
|
expires: DateTime.Now.AddMinutes(_authSettings.TokenExpireTime),
|
||||||
|
signingCredentials: signingCredentials
|
||||||
|
);
|
||||||
|
|
||||||
|
return new JwtSecurityTokenHandler().WriteToken(tokenOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _generateRefreshToken()
|
||||||
|
{
|
||||||
|
var randomNumber = new byte[32];
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
rng.GetBytes(randomNumber);
|
||||||
|
return Convert.ToBase64String(randomNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> _createAndSaveRefreshToken(AuthUser user)
|
||||||
|
{
|
||||||
|
var refreshToken = this._generateRefreshToken();
|
||||||
|
|
||||||
|
user.RefreshToken = refreshToken;
|
||||||
|
user.RefreshTokenExpiryTime = DateTime.Now.AddDays(_authSettings.RefreshTokenExpireTime);
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
|
||||||
|
return refreshToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClaimsPrincipal _getPrincipalFromExpiredToken(string token)
|
||||||
|
{
|
||||||
|
var tokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case
|
||||||
|
ValidateIssuer = false,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this._authSettings.SecretKey)),
|
||||||
|
ValidateLifetime = false //here we are saying that we don't care about the token's expiration date
|
||||||
|
};
|
||||||
|
var tokenHandler = new JwtSecurityTokenHandler();
|
||||||
|
SecurityToken securityToken;
|
||||||
|
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out securityToken);
|
||||||
|
var jwtSecurityToken = securityToken as JwtSecurityToken;
|
||||||
|
if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
throw new SecurityTokenException("Invalid token");
|
||||||
|
return principal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _createAndSaveConfirmationId(AuthUser user)
|
||||||
|
{
|
||||||
|
bool end = false;
|
||||||
|
while (!end)
|
||||||
|
{
|
||||||
|
string id = _randomString(16);
|
||||||
|
var userFromDb = await _authUserRepository.FindAuthUserByEMailConfirmationIdAsync(id);
|
||||||
|
if (userFromDb is null)
|
||||||
|
{
|
||||||
|
end = true;
|
||||||
|
user.ConfirmationId = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _createAndSaveForgotPasswordId(AuthUser user)
|
||||||
|
{
|
||||||
|
bool end = false;
|
||||||
|
while (!end)
|
||||||
|
{
|
||||||
|
string id = _randomString(16);
|
||||||
|
var userFromDb = await _authUserRepository.FindAuthUserByEMailForgotPasswordIdAsync(id);
|
||||||
|
if (userFromDb is null)
|
||||||
|
{
|
||||||
|
end = true;
|
||||||
|
user.ForgotPasswordId = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _sendConfirmationIdToUser(AuthUser user)
|
||||||
|
{
|
||||||
|
string url = _frontendSettings.URL.EndsWith("/") ? _frontendSettings.URL : $"{_frontendSettings}/";
|
||||||
|
await _smtpClient.SendEmailAsync(new EMail()
|
||||||
|
{
|
||||||
|
Receiver = user.EMail,
|
||||||
|
Subject = $"E-Mail für {user.FirstName} {user.LastName} bestätigen",
|
||||||
|
Message = $"{url}auth/register/{user.ConfirmationId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task _sendForgotPasswordIdToUser(AuthUser user)
|
||||||
|
{
|
||||||
|
string url = _frontendSettings.URL.EndsWith("/") ? _frontendSettings.URL : $"{_frontendSettings}/";
|
||||||
|
await _smtpClient.SendEmailAsync(new EMail()
|
||||||
|
{
|
||||||
|
Receiver = user.EMail,
|
||||||
|
Subject = $"Passwort für {user.FirstName} {user.LastName} zurücksetzen",
|
||||||
|
Message = $"{url}auth/forgot-password/{user.ForgotPasswordId}"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<AuthUserDTO>> GetAllAuthUsersAsync()
|
||||||
|
{
|
||||||
|
var authUserDTOs = new List<AuthUserDTO>();
|
||||||
|
var authUsers = await _authUserRepository.GetAllAuthUsersAsync();
|
||||||
|
authUsers.ForEach(authUser =>
|
||||||
|
{
|
||||||
|
authUserDTOs.Add(authUser.ToAuthUserDTO());
|
||||||
|
});
|
||||||
|
return authUserDTOs;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<GetFilteredAuthUsersResultDTO> GetFilteredAuthUsersAsync(AuthUserSelectCriterion selectCriterion) {
|
||||||
|
(var users, var totalCount) = await _authUserRepository.GetFilteredAuthUsersAsync(selectCriterion);
|
||||||
|
var result = new List<AuthUserDTO>();
|
||||||
|
|
||||||
|
users.ForEach(user => {
|
||||||
|
result.Add(user.ToAuthUserDTO());
|
||||||
|
});
|
||||||
|
|
||||||
|
return new GetFilteredAuthUsersResultDTO() {
|
||||||
|
Users = result,
|
||||||
|
TotalCount = totalCount
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUserDTO> GetAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var authUser = await _authUserRepository.GetAuthUserByEMailAsync(email);
|
||||||
|
return authUser.ToAuthUserDTO();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"AuthUser with email {email} not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AuthUserDTO> FindAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
var authUser = await _authUserRepository.FindAuthUserByEMailAsync(email);
|
||||||
|
return authUser != null ? authUser.ToAuthUserDTO() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<long> AddAuthUserAsync(AuthUserDTO authUserDTO)
|
||||||
|
{
|
||||||
|
var authUserDb = await _authUserRepository.FindAuthUserByEMailAsync(authUserDTO.EMail);
|
||||||
|
if (authUserDb != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
authUserDTO.Password = ComputeHash(authUserDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
|
||||||
|
var authUser = authUserDTO.ToAuthUser();
|
||||||
|
|
||||||
|
if (!IsValidEmail(authUser.EMail))
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Invalid E-Mail");
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
_authUserRepository.AddAuthUser(authUser);
|
||||||
|
await _createAndSaveConfirmationId(authUser);
|
||||||
|
await _sendConfirmationIdToUser(authUser);
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
_logger.Info($"Added authUser with email: {authUser.EMail}");
|
||||||
|
return authUser.Id;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
throw new ServiceException(ServiceErrorCode.UnableToAdd, $"Cannot add authUser {authUserDTO.EMail}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> ConfirmEMail(string id)
|
||||||
|
{
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailConfirmationIdAsync(id);
|
||||||
|
if (user.ConfirmationId == id)
|
||||||
|
{
|
||||||
|
user.ConfirmationId = null;
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TokenDTO> Login(AuthUserDTO userDTO)
|
||||||
|
{
|
||||||
|
if (userDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"User is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
var userFromDb = await _authUserRepository.FindAuthUserByEMailAsync(userDTO.EMail);
|
||||||
|
if (userFromDb == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userFromDb.ConfirmationId != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "E-Mail not confirmed");
|
||||||
|
}
|
||||||
|
|
||||||
|
userDTO.Password = ComputeHash(userDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
if (userFromDb.Password != userDTO.Password)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "Wrong password");
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokenString = this._generateToken(new List<Claim>() {
|
||||||
|
new Claim(ClaimTypes.Name, userDTO.EMail),
|
||||||
|
new Claim(ClaimTypes.Role, userFromDb.AuthRole.ToString())
|
||||||
|
});
|
||||||
|
|
||||||
|
var refreshString = await this._createAndSaveRefreshToken(userFromDb);
|
||||||
|
|
||||||
|
if (userFromDb.ForgotPasswordId != null)
|
||||||
|
{
|
||||||
|
userFromDb.ForgotPasswordId = null;
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TokenDTO
|
||||||
|
{
|
||||||
|
Token = tokenString,
|
||||||
|
RefreshToken = refreshString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ForgotPassword(string email)
|
||||||
|
{
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailAsync(email);
|
||||||
|
if (user is null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await _createAndSaveForgotPasswordId(user);
|
||||||
|
await _sendForgotPasswordIdToUser(user);
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<EMailStringDTO> ConfirmForgotPassword(string id)
|
||||||
|
{
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailForgotPasswordIdAsync(id);
|
||||||
|
return new EMailStringDTO()
|
||||||
|
{
|
||||||
|
EMail = user.EMail
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ResetPassword(ResetPasswordDTO rpDTO)
|
||||||
|
{
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailForgotPasswordIdAsync(rpDTO.Id);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.ConfirmationId != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "E-Mail not confirmed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rpDTO.Password == null || rpDTO.Password == "")
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, "Password is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
rpDTO.Password = ComputeHash(rpDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
user.Password = rpDTO.Password;
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateUser(UpdateUserDTO updateUserDTO)
|
||||||
|
{
|
||||||
|
if (updateUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"User is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.AuthUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Existing user is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.NewAuthUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"New user is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidEmail(updateUserDTO.AuthUserDTO.EMail) || !IsValidEmail(updateUserDTO.NewAuthUserDTO.EMail))
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Invalid E-Mail");
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailAsync(updateUserDTO.AuthUserDTO.EMail);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.ConfirmationId != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "E-Mail not confirmed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update first name
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.FirstName != null && updateUserDTO.AuthUserDTO.FirstName != updateUserDTO.NewAuthUserDTO.FirstName)
|
||||||
|
{
|
||||||
|
user.FirstName = updateUserDTO.NewAuthUserDTO.FirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update last name
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.LastName != null && updateUserDTO.NewAuthUserDTO.LastName != "" && updateUserDTO.AuthUserDTO.LastName != updateUserDTO.NewAuthUserDTO.LastName)
|
||||||
|
{
|
||||||
|
user.LastName = updateUserDTO.NewAuthUserDTO.LastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update E-Mail
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.EMail != null && updateUserDTO.NewAuthUserDTO.EMail != "" && updateUserDTO.AuthUserDTO.EMail != updateUserDTO.NewAuthUserDTO.EMail)
|
||||||
|
{
|
||||||
|
var userByNewEMail = await _authUserRepository.FindAuthUserByEMailAsync(updateUserDTO.NewAuthUserDTO.EMail);
|
||||||
|
if (userByNewEMail != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User already exists");
|
||||||
|
}
|
||||||
|
user.EMail = updateUserDTO.NewAuthUserDTO.EMail;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isExistingPasswordSet = false;
|
||||||
|
bool isnewPasswordSet = false;
|
||||||
|
// hash passwords in DTOs
|
||||||
|
if (updateUserDTO.AuthUserDTO.Password != null && updateUserDTO.AuthUserDTO.Password != "")
|
||||||
|
{
|
||||||
|
isExistingPasswordSet = true;
|
||||||
|
updateUserDTO.AuthUserDTO.Password = ComputeHash(updateUserDTO.AuthUserDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.AuthUserDTO.Password != user.Password)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "Wrong password");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.Password != null && updateUserDTO.NewAuthUserDTO.Password != "")
|
||||||
|
{
|
||||||
|
isnewPasswordSet = true;
|
||||||
|
updateUserDTO.NewAuthUserDTO.Password = ComputeHash(updateUserDTO.NewAuthUserDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
// update password
|
||||||
|
if (isExistingPasswordSet && isnewPasswordSet && updateUserDTO.AuthUserDTO.Password != updateUserDTO.NewAuthUserDTO.Password)
|
||||||
|
{
|
||||||
|
user.Password = updateUserDTO.NewAuthUserDTO.Password;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateUserAsAdmin(AdminUpdateUserDTO updateUserDTO)
|
||||||
|
{
|
||||||
|
if (updateUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"User is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.AuthUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Existing user is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateUserDTO.NewAuthUserDTO == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"New user is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsValidEmail(updateUserDTO.AuthUserDTO.EMail) || !IsValidEmail(updateUserDTO.NewAuthUserDTO.EMail))
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Invalid E-Mail");
|
||||||
|
}
|
||||||
|
|
||||||
|
var user = await _authUserRepository.FindAuthUserByEMailAsync(updateUserDTO.AuthUserDTO.EMail);
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user.ConfirmationId != null && updateUserDTO.NewAuthUserDTO.IsConfirmed)
|
||||||
|
{
|
||||||
|
user.ConfirmationId = null;
|
||||||
|
}
|
||||||
|
else if (user.ConfirmationId == null && !updateUserDTO.NewAuthUserDTO.IsConfirmed)
|
||||||
|
{
|
||||||
|
|
||||||
|
await _createAndSaveConfirmationId(user);
|
||||||
|
}
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// throw new ServiceException(ServiceErrorCode.InvalidUser, "E-Mail not confirmed");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// update first name
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.FirstName != null && updateUserDTO.AuthUserDTO.FirstName != updateUserDTO.NewAuthUserDTO.FirstName)
|
||||||
|
{
|
||||||
|
user.FirstName = updateUserDTO.NewAuthUserDTO.FirstName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update last name
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.LastName != null && updateUserDTO.NewAuthUserDTO.LastName != "" && updateUserDTO.AuthUserDTO.LastName != updateUserDTO.NewAuthUserDTO.LastName)
|
||||||
|
{
|
||||||
|
user.LastName = updateUserDTO.NewAuthUserDTO.LastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update E-Mail
|
||||||
|
if (updateUserDTO.NewAuthUserDTO.EMail != null && updateUserDTO.NewAuthUserDTO.EMail != "" && updateUserDTO.AuthUserDTO.EMail != updateUserDTO.NewAuthUserDTO.EMail)
|
||||||
|
{
|
||||||
|
var userByNewEMail = await _authUserRepository.FindAuthUserByEMailAsync(updateUserDTO.NewAuthUserDTO.EMail);
|
||||||
|
if (userByNewEMail != null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidUser, "User already exists");
|
||||||
|
}
|
||||||
|
user.EMail = updateUserDTO.NewAuthUserDTO.EMail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update password
|
||||||
|
if (updateUserDTO.ChangePassword && updateUserDTO.AuthUserDTO.Password != updateUserDTO.NewAuthUserDTO.Password)
|
||||||
|
{
|
||||||
|
user.Password = ComputeHash(updateUserDTO.NewAuthUserDTO.Password, new SHA256CryptoServiceProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
// update role
|
||||||
|
if (user.AuthRole == updateUserDTO.AuthUserDTO.AuthRole && user.AuthRole != updateUserDTO.NewAuthUserDTO.AuthRole)
|
||||||
|
{
|
||||||
|
user.AuthRole = updateUserDTO.NewAuthUserDTO.AuthRole;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TokenDTO> Refresh(TokenDTO tokenDTO)
|
||||||
|
{
|
||||||
|
if (tokenDTO is null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Token is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
var principal = this._getPrincipalFromExpiredToken(tokenDTO.Token);
|
||||||
|
var email = principal.Identity.Name;
|
||||||
|
|
||||||
|
var user = await this._authUserRepository.FindAuthUserByEMailAsync(email);
|
||||||
|
if (user == null || user.RefreshToken != tokenDTO.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.Now)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Token is expired");
|
||||||
|
}
|
||||||
|
|
||||||
|
var newToken = this._generateToken(principal.Claims);
|
||||||
|
var newRefreshToken = await this._createAndSaveRefreshToken(user);
|
||||||
|
|
||||||
|
return new TokenDTO()
|
||||||
|
{
|
||||||
|
Token = newToken,
|
||||||
|
RefreshToken = newRefreshToken
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Revoke(TokenDTO tokenDTO)
|
||||||
|
{
|
||||||
|
if (tokenDTO == null || tokenDTO.Token == null || tokenDTO.RefreshToken == null)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Token is empty");
|
||||||
|
};
|
||||||
|
|
||||||
|
var principal = this._getPrincipalFromExpiredToken(tokenDTO.Token);
|
||||||
|
var email = principal.Identity.Name;
|
||||||
|
|
||||||
|
var user = await this._authUserRepository.FindAuthUserByEMailAsync(email);
|
||||||
|
if (user == null || user.RefreshToken != tokenDTO.RefreshToken || user.RefreshTokenExpiryTime <= DateTime.Now)
|
||||||
|
{
|
||||||
|
throw new ServiceException(ServiceErrorCode.InvalidData, $"Token is expired");
|
||||||
|
}
|
||||||
|
user.RefreshToken = null;
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAuthUserByEMailAsync(string email)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await _authUserRepository.DeleteAuthUserByEMailAsync(email);
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
_logger.Info($"Deleted authUser with email: {email}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
throw new ServiceException(ServiceErrorCode.UnableToDelete, $"Cannot delete authUser with email {email}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task DeleteAuthUserAsync(AuthUserDTO authUserDTO)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_authUserRepository.DeleteAuthUser(authUserDTO.ToAuthUser());
|
||||||
|
await _unitOfWork.SaveChangesAsync();
|
||||||
|
_logger.Info($"Deleted authUser {authUserDTO.EMail}");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
throw new ServiceException(ServiceErrorCode.UnableToDelete, $"Cannot delete authUser {authUserDTO.EMail}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ComputeHash(string input, HashAlgorithm algorithm)
|
||||||
|
{
|
||||||
|
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
|
||||||
|
Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
|
||||||
|
return BitConverter.ToString(hashedBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsValidEmail(string email)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var addr = new System.Net.Mail.MailAddress(email);
|
||||||
|
return addr.Address == email;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
gswi.Service/gswi.Service.csproj
Normal file
19
gswi.Service/gswi.Service.csproj
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Interface\gswi.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Model\gswi.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Data\gswi.Data.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Configuration\gswi.Configuration.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Interface\gswi.SMTP.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Model\gswi.SMTP.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Share.Common\gswi.Share.Common.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
11
gswi.Share.Common/AuthUserSelectCriterion.cs
Normal file
11
gswi.Share.Common/AuthUserSelectCriterion.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace gswi.Share.Common
|
||||||
|
{
|
||||||
|
public class AuthUserSelectCriterion : SelectCriterion
|
||||||
|
{
|
||||||
|
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
public string LastName { get; set; }
|
||||||
|
public string EMail { get; set; }
|
||||||
|
public int? AuthRole { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
gswi.Share.Common/SelectCriterion.cs
Normal file
10
gswi.Share.Common/SelectCriterion.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace gswi.Share.Common
|
||||||
|
{
|
||||||
|
public class SelectCriterion
|
||||||
|
{
|
||||||
|
public int PageIndex { get; set; }
|
||||||
|
public int PageSize { get; set; }
|
||||||
|
public string SortDirection { get; set; }
|
||||||
|
public string SortColumn { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
gswi.Share.Common/gswi.Share.Common.csproj
Normal file
11
gswi.Share.Common/gswi.Share.Common.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Share.Common.Interface\gswi.Share.Common.Interface.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
9
gswi.SignalR/NotifyHub.cs
Normal file
9
gswi.SignalR/NotifyHub.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace gswi.SignalR
|
||||||
|
{
|
||||||
|
public class NotifyHub : Hub
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
11
gswi.SignalR/gswi.SignalR.csproj
Normal file
11
gswi.SignalR/gswi.SignalR.csproj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
127
gswi.sln
Normal file
127
gswi.sln
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.30621.155
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi", "gswi\gswi.csproj", "{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Configuration", "gswi.Configuration\gswi.Configuration.csproj", "{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.CredentialManager", "gswi.CredentialManager\gswi.CredentialManager.csproj", "{90969785-C60C-45DB-A84E-E92A65755DF0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Data", "gswi.Data\gswi.Data.csproj", "{1F380FAE-D068-40BB-869A-80CE076A2C81}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Interface", "gswi.Interface\gswi.Interface.csproj", "{447C2465-462F-4DBC-95F8-2330BBE36C4E}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Model", "gswi.Model\gswi.Model.csproj", "{185EDC35-E150-4404-90EC-562819397D80}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Service", "gswi.Service\gswi.Service.csproj", "{F90A1288-0A41-449F-A856-F8988E77547F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.SMTP.Interface", "gswi.SMTP.Interface\gswi.SMTP.Interface.csproj", "{EAE98478-F76B-4A37-A428-3A4F9DF18458}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.SMTP.Service", "gswi.SMTP.Service\gswi.SMTP.Service.csproj", "{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.SMTP.Model", "gswi.SMTP.Model\gswi.SMTP.Model.csproj", "{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.SignalR", "gswi.SignalR\gswi.SignalR.csproj", "{B55249FD-3E4B-497B-810F-C7D60DB7A09C}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gswi.Share.Common", "gswi.Share.Common\gswi.Share.Common.csproj", "{53841805-BF4C-4197-98C8-79CA3609D670}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{31207121-94AB-4E14-9533-0E14E5A1D7B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{31207121-94AB-4E14-9533-0E14E5A1D7B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{31207121-94AB-4E14-9533-0E14E5A1D7B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{31207121-94AB-4E14-9533-0E14E5A1D7B7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{24ADC76B-B4B8-4BE7-AA45-DDD70C703746}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{24ADC76B-B4B8-4BE7-AA45-DDD70C703746}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{24ADC76B-B4B8-4BE7-AA45-DDD70C703746}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{24ADC76B-B4B8-4BE7-AA45-DDD70C703746}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{256CDBD1-03A3-45B3-AEC2-D47C8E27D297}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{256CDBD1-03A3-45B3-AEC2-D47C8E27D297}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{256CDBD1-03A3-45B3-AEC2-D47C8E27D297}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{256CDBD1-03A3-45B3-AEC2-D47C8E27D297}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1B2288C0-7376-417F-B6E7-4722674A3865}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1B2288C0-7376-417F-B6E7-4722674A3865}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1B2288C0-7376-417F-B6E7-4722674A3865}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1B2288C0-7376-417F-B6E7-4722674A3865}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{4EB016C1-4193-4935-9E83-C127F6B31E90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{4EB016C1-4193-4935-9E83-C127F6B31E90}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{4EB016C1-4193-4935-9E83-C127F6B31E90}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{4EB016C1-4193-4935-9E83-C127F6B31E90}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{DE15C470-100E-4D31-B81B-C28B53C244CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{DE15C470-100E-4D31-B81B-C28B53C244CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{DE15C470-100E-4D31-B81B-C28B53C244CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{DE15C470-100E-4D31-B81B-C28B53C244CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{0D798502-DF95-453D-B3D4-A49D2536A83D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{0D798502-DF95-453D-B3D4-A49D2536A83D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{0D798502-DF95-453D-B3D4-A49D2536A83D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{0D798502-DF95-453D-B3D4-A49D2536A83D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F62CDD28-A656-40DF-8D40-5CC8949A3A9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F62CDD28-A656-40DF-8D40-5CC8949A3A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F62CDD28-A656-40DF-8D40-5CC8949A3A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F62CDD28-A656-40DF-8D40-5CC8949A3A9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{90969785-C60C-45DB-A84E-E92A65755DF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{90969785-C60C-45DB-A84E-E92A65755DF0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{90969785-C60C-45DB-A84E-E92A65755DF0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{90969785-C60C-45DB-A84E-E92A65755DF0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{1F380FAE-D068-40BB-869A-80CE076A2C81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{1F380FAE-D068-40BB-869A-80CE076A2C81}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{1F380FAE-D068-40BB-869A-80CE076A2C81}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{1F380FAE-D068-40BB-869A-80CE076A2C81}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{447C2465-462F-4DBC-95F8-2330BBE36C4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{447C2465-462F-4DBC-95F8-2330BBE36C4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{447C2465-462F-4DBC-95F8-2330BBE36C4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{447C2465-462F-4DBC-95F8-2330BBE36C4E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{185EDC35-E150-4404-90EC-562819397D80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{185EDC35-E150-4404-90EC-562819397D80}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{185EDC35-E150-4404-90EC-562819397D80}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{185EDC35-E150-4404-90EC-562819397D80}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F90A1288-0A41-449F-A856-F8988E77547F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F90A1288-0A41-449F-A856-F8988E77547F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F90A1288-0A41-449F-A856-F8988E77547F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F90A1288-0A41-449F-A856-F8988E77547F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EAE98478-F76B-4A37-A428-3A4F9DF18458}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EAE98478-F76B-4A37-A428-3A4F9DF18458}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EAE98478-F76B-4A37-A428-3A4F9DF18458}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EAE98478-F76B-4A37-A428-3A4F9DF18458}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B55249FD-3E4B-497B-810F-C7D60DB7A09C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B55249FD-3E4B-497B-810F-C7D60DB7A09C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B55249FD-3E4B-497B-810F-C7D60DB7A09C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B55249FD-3E4B-497B-810F-C7D60DB7A09C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{53841805-BF4C-4197-98C8-79CA3609D670}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{53841805-BF4C-4197-98C8-79CA3609D670}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{53841805-BF4C-4197-98C8-79CA3609D670}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{53841805-BF4C-4197-98C8-79CA3609D670}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{539E128A-E0B2-4593-A13A-9641922A50EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{539E128A-E0B2-4593-A13A-9641922A50EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{539E128A-E0B2-4593-A13A-9641922A50EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{539E128A-E0B2-4593-A13A-9641922A50EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {27320AC8-C9ED-452B-9C99-074215D41C63}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
148
gswi/Controllers/AuthController.cs
Normal file
148
gswi/Controllers/AuthController.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using gswi.Interface.Services;
|
||||||
|
using gswi.Model.DTOs;
|
||||||
|
using gswi.Share.Common;
|
||||||
|
|
||||||
|
namespace gswi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/auth")]
|
||||||
|
[ApiController]
|
||||||
|
public class AuthController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IAuthService _authService;
|
||||||
|
|
||||||
|
public AuthController(
|
||||||
|
IAuthService authServce
|
||||||
|
)
|
||||||
|
{
|
||||||
|
_authService = authServce;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Data requests */
|
||||||
|
// Get /api/auth/users
|
||||||
|
[HttpGet("users")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<List<AuthUserDTO>> GetAllAuthUsers()
|
||||||
|
{
|
||||||
|
return await _authService.GetAllAuthUsersAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/users/get/filtered
|
||||||
|
[HttpPost("users/get/filtered")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<GetFilteredAuthUsersResultDTO> GetFilteredAuthUsers(AuthUserSelectCriterion selectCriterion)
|
||||||
|
{
|
||||||
|
return await _authService.GetFilteredAuthUsersAsync(selectCriterion);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get /api/auth/users/get/<mail>
|
||||||
|
[HttpGet("users/get/{email}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<AuthUserDTO> GetUserFromEMail(string email)
|
||||||
|
{
|
||||||
|
return await _authService.GetAuthUserByEMailAsync(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get /api/auth/users/find/<mail>
|
||||||
|
[HttpGet("users/find/{email}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task<AuthUserDTO> FindUserFromEMail(string email)
|
||||||
|
{
|
||||||
|
return await _authService.FindAuthUserByEMailAsync(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Auth requests */
|
||||||
|
// POST /api/auth/register
|
||||||
|
[HttpPost("register")]
|
||||||
|
public async Task Register(AuthUserDTO userDTO)
|
||||||
|
{
|
||||||
|
await _authService.AddAuthUserAsync(userDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/register/<id>
|
||||||
|
[HttpPost("register/{id}")]
|
||||||
|
public async Task<bool> ConfirmEMail(string id)
|
||||||
|
{
|
||||||
|
return await _authService.ConfirmEMail(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/login
|
||||||
|
[HttpPost("login")]
|
||||||
|
public async Task<TokenDTO> Login(AuthUserDTO userDTO)
|
||||||
|
{
|
||||||
|
return await _authService.Login(userDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/forgot-password
|
||||||
|
[HttpPost("forgot-password")]
|
||||||
|
public async Task ForgotPassword([FromBody] string email)
|
||||||
|
{
|
||||||
|
await _authService.ForgotPassword(email);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/confirm-forgot-password
|
||||||
|
[HttpPost("confirm-forgot-password")]
|
||||||
|
public async Task<EMailStringDTO> ConfirmForgotPassword([FromBody] string id)
|
||||||
|
{
|
||||||
|
return await _authService.ConfirmForgotPassword(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/reset-password
|
||||||
|
[HttpPost("reset-password")]
|
||||||
|
public async Task ResetPassword(ResetPasswordDTO rpDTO)
|
||||||
|
{
|
||||||
|
await _authService.ResetPassword(rpDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/update-user
|
||||||
|
[HttpPost("update-user")]
|
||||||
|
public async Task UpdateUser(UpdateUserDTO updateUserDTO)
|
||||||
|
{
|
||||||
|
await _authService.UpdateUser(updateUserDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/update-user-as-admin
|
||||||
|
[HttpPost("update-user-as-admin")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task UpdateUserAsAdmin(AdminUpdateUserDTO updateUserDTO)
|
||||||
|
{
|
||||||
|
await _authService.UpdateUserAsAdmin(updateUserDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/refresh
|
||||||
|
[HttpPost("refresh")]
|
||||||
|
public async Task<TokenDTO> Refresh(TokenDTO tokenDTO)
|
||||||
|
{
|
||||||
|
return await _authService.Refresh(tokenDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/revoke
|
||||||
|
[HttpPost("revoke")]
|
||||||
|
public async Task Revoke(TokenDTO tokenDTO)
|
||||||
|
{
|
||||||
|
await _authService.Revoke(tokenDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/delete-user
|
||||||
|
[HttpPost("delete-user")]
|
||||||
|
public async Task DeleteAuthUserAsync(AuthUserDTO userDTO)
|
||||||
|
{
|
||||||
|
await _authService.DeleteAuthUserAsync(userDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/auth/delete-user
|
||||||
|
[HttpPost("delete-user-by-mail/{mail}")]
|
||||||
|
public async Task DeleteAuthUserByEMailAsync(string mail)
|
||||||
|
{
|
||||||
|
await _authService.DeleteAuthUserByEMailAsync(mail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
92
gswi/Controllers/GUIController.cs
Normal file
92
gswi/Controllers/GUIController.cs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using gswi.Configuration;
|
||||||
|
using gswi.Model.DTOs;
|
||||||
|
using gswi.SMTP.Interface;
|
||||||
|
using gswi.SMTP.Model;
|
||||||
|
|
||||||
|
namespace gswi.Controllers
|
||||||
|
{
|
||||||
|
[Route("api/gui")]
|
||||||
|
[ApiController]
|
||||||
|
public class GUIController : ControllerBase
|
||||||
|
{
|
||||||
|
private APISettings _apiSettings;
|
||||||
|
private DatabaseSettings _databaseSettings;
|
||||||
|
private AuthentificationSettings _authSettings;
|
||||||
|
private EMailSettings _mailSettings;
|
||||||
|
private FrontendSettings _frontendSettings;
|
||||||
|
private IHostEnvironment _env;
|
||||||
|
private readonly ISMTPClient _smtpClient;
|
||||||
|
|
||||||
|
public GUIController(
|
||||||
|
APISettings apiSettings,
|
||||||
|
DatabaseSettings databaseSettings,
|
||||||
|
AuthentificationSettings authSettings,
|
||||||
|
EMailSettings mailSettings,
|
||||||
|
FrontendSettings frontendSettings,
|
||||||
|
IHostEnvironment env,
|
||||||
|
ISMTPClient smtpClient
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this._apiSettings = apiSettings;
|
||||||
|
this._databaseSettings = databaseSettings;
|
||||||
|
this._authSettings = authSettings;
|
||||||
|
this._mailSettings = mailSettings;
|
||||||
|
this._frontendSettings = frontendSettings;
|
||||||
|
this._env = env;
|
||||||
|
this._smtpClient = smtpClient;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/gui/api-version
|
||||||
|
[HttpGet("api-version")]
|
||||||
|
public ApiVersionDTO GetApiVersion()
|
||||||
|
{
|
||||||
|
return new ApiVersionDTO()
|
||||||
|
{
|
||||||
|
Major = this._apiSettings.ApiVersion.Major,
|
||||||
|
Minor = this._apiSettings.ApiVersion.Minor,
|
||||||
|
Micro = this._apiSettings.ApiVersion.Micro
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/gui/settings
|
||||||
|
[HttpGet("settings")]
|
||||||
|
[Authorize]
|
||||||
|
public SettingsDTO GetSettingsDTO()
|
||||||
|
{
|
||||||
|
return new SettingsDTO()
|
||||||
|
{
|
||||||
|
ApiVersion = this._apiSettings.ApiVersion.ToString(),
|
||||||
|
ConfigPath = this._env.ContentRootPath,
|
||||||
|
WebBaseURL = this._frontendSettings.URL,
|
||||||
|
ApiBaseURL = "",
|
||||||
|
|
||||||
|
TokenExpireTime = this._authSettings.TokenExpireTime,
|
||||||
|
RefreshTokenExpireTime = this._authSettings.RefreshTokenExpireTime,
|
||||||
|
|
||||||
|
MailUser = this._mailSettings.Username,
|
||||||
|
MailPort = this._mailSettings.MailServerPort,
|
||||||
|
MailHost = this._mailSettings.MailServerAddress,
|
||||||
|
MailTransceiver = this._mailSettings.FromName,
|
||||||
|
MailTransceiverAddress = this._mailSettings.FromAddress
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /api/gui/send-test-mail/<email>
|
||||||
|
[HttpPost("send-test-mail/{email}")]
|
||||||
|
[Authorize]
|
||||||
|
public async Task SendTestMail(string email)
|
||||||
|
{
|
||||||
|
await _smtpClient.SendEmailAsync(new EMail()
|
||||||
|
{
|
||||||
|
Receiver = email,
|
||||||
|
Subject = $"Login counter Test E-Mail",
|
||||||
|
Message = $"Login counter Test E-Mail"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
gswi/DataSeeder.cs
Normal file
76
gswi/DataSeeder.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using gswi.Data;
|
||||||
|
using gswi.Model;
|
||||||
|
|
||||||
|
namespace gswi
|
||||||
|
{
|
||||||
|
public class DataSeeder
|
||||||
|
{
|
||||||
|
private readonly DatabaseContext _databaseContext;
|
||||||
|
|
||||||
|
public DataSeeder(DatabaseContext databaseContext)
|
||||||
|
{
|
||||||
|
_databaseContext = databaseContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SeedData()
|
||||||
|
{
|
||||||
|
_databaseContext.Database.EnsureCreated();
|
||||||
|
|
||||||
|
if (!_databaseContext.AuthUsers.Any())
|
||||||
|
{
|
||||||
|
|
||||||
|
var admin = new AuthUser()
|
||||||
|
{
|
||||||
|
FirstName = "Admin",
|
||||||
|
LastName = "Administator",
|
||||||
|
EMail = "admin@localhost",
|
||||||
|
Password = ComputeHash("Administator", new SHA256CryptoServiceProvider()),
|
||||||
|
AuthRole = AuthRoles.Admin
|
||||||
|
};
|
||||||
|
|
||||||
|
var authUser = new AuthUser()
|
||||||
|
{
|
||||||
|
FirstName = "Max",
|
||||||
|
LastName = "Mustermann",
|
||||||
|
EMail = "max.mustermann@gmail.com",
|
||||||
|
Password = ComputeHash("test1234", new SHA256CryptoServiceProvider()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var authUser1 = new AuthUser()
|
||||||
|
{
|
||||||
|
FirstName = "Max",
|
||||||
|
LastName = "Tester",
|
||||||
|
EMail = "max.mustermann@mustermail.com",
|
||||||
|
Password = ComputeHash("test1234", new SHA256CryptoServiceProvider()),
|
||||||
|
};
|
||||||
|
|
||||||
|
var authUser2 = new AuthUser()
|
||||||
|
{
|
||||||
|
FirstName = "Max",
|
||||||
|
LastName = "Muster",
|
||||||
|
EMail = "max.mustermann@yahoo.com",
|
||||||
|
Password = ComputeHash("test1234", new SHA256CryptoServiceProvider()),
|
||||||
|
};
|
||||||
|
|
||||||
|
_databaseContext.AuthUsers.Add(admin);
|
||||||
|
_databaseContext.AuthUsers.Add(authUser);
|
||||||
|
_databaseContext.AuthUsers.Add(authUser1);
|
||||||
|
_databaseContext.AuthUsers.Add(authUser2);
|
||||||
|
}
|
||||||
|
_databaseContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ComputeHash(string input, HashAlgorithm algorithm)
|
||||||
|
{
|
||||||
|
Byte[] inputBytes = Encoding.UTF8.GetBytes(input);
|
||||||
|
Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
|
||||||
|
return BitConverter.ToString(hashedBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
55
gswi/Filters/CustomExceptionFilterAttribute.cs
Normal file
55
gswi/Filters/CustomExceptionFilterAttribute.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
|
using NLog;
|
||||||
|
using gswi.Model.Filters;
|
||||||
|
|
||||||
|
namespace gswi.Filters
|
||||||
|
{
|
||||||
|
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
private static Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public CustomExceptionFilterAttribute() { }
|
||||||
|
|
||||||
|
public override void OnException(ExceptionContext context)
|
||||||
|
{
|
||||||
|
context.Result = CreateJsonErrorResult(context);
|
||||||
|
base.OnException(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonResult CreateJsonErrorResult(ExceptionContext context)
|
||||||
|
{
|
||||||
|
JsonResult result = null;
|
||||||
|
|
||||||
|
// create jsonresult
|
||||||
|
var exception = context.Exception;
|
||||||
|
if (exception is ServiceException)
|
||||||
|
{
|
||||||
|
var bex = exception as ServiceException;
|
||||||
|
_logger.Error($"{bex.GetDetailedMessage()}");
|
||||||
|
var error = new ErrorDto(bex.ErrorCode, bex.GetMessage());
|
||||||
|
result = new JsonResult(error)
|
||||||
|
{
|
||||||
|
StatusCode = (int)HttpStatusCode.BadRequest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var trackingId = Guid.NewGuid();
|
||||||
|
string userMsg = $"Tracking Id: {trackingId}";
|
||||||
|
_logger.Error(exception, userMsg);
|
||||||
|
var error = new ErrorDto($"Tracking Id: {trackingId}");
|
||||||
|
result = new JsonResult(error)
|
||||||
|
{
|
||||||
|
StatusCode = (int)HttpStatusCode.InternalServerError
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
30
gswi/HostExtensions.cs
Normal file
30
gswi/HostExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using gswi.Data;
|
||||||
|
|
||||||
|
namespace gswi
|
||||||
|
{
|
||||||
|
public static class HostExtensions
|
||||||
|
{
|
||||||
|
public static IHost SeedData(this IHost host)
|
||||||
|
{
|
||||||
|
using (var scope = host.Services.CreateScope())
|
||||||
|
{
|
||||||
|
var services = scope.ServiceProvider;
|
||||||
|
var context = services.GetService<DatabaseContext>();
|
||||||
|
|
||||||
|
// now we have the DbContext. Run migrations
|
||||||
|
context.Database.Migrate();
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
// now that the database is up to date. Let's seed
|
||||||
|
new DataSeeder(context).SeedData();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
gswi/JSONConverter/JsonCreationConverter.cs
Normal file
54
gswi/JSONConverter/JsonCreationConverter.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace gswi.JSONConverter
|
||||||
|
{
|
||||||
|
public abstract class JsonCreationConverter<T> : JsonConverter
|
||||||
|
{
|
||||||
|
static Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
protected abstract T Create(Type objectType, JObject jObject);
|
||||||
|
|
||||||
|
public override bool CanConvert(Type objectType)
|
||||||
|
{
|
||||||
|
return typeof(T).IsAssignableFrom(objectType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ReadJson(JsonReader reader,
|
||||||
|
Type objectType,
|
||||||
|
object existingValue,
|
||||||
|
JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Load JObject from stream
|
||||||
|
JObject jObject = JObject.Load(reader);
|
||||||
|
|
||||||
|
// Create target object based on JObject
|
||||||
|
T target = Create(objectType, jObject);
|
||||||
|
|
||||||
|
// Populate the object properties
|
||||||
|
serializer.Populate(jObject.CreateReader(), target);
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
43
gswi/Program.cs
Normal file
43
gswi/Program.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using NLog.Extensions.Logging;
|
||||||
|
using gswi.Configuration;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace gswi
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Configuration.HostExtensions.ChangeCurrentDirToProjectDir();
|
||||||
|
var host = CreateHostBuilder(args).Build();
|
||||||
|
host.LogHostingEnvironment<Program>();
|
||||||
|
host.SeedData();
|
||||||
|
host.Run();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Configuration.HostExtensions.LogStartError(ex);
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
NLog.LogManager.Shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
|
Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>
|
||||||
|
{
|
||||||
|
webBuilder.UseStartup<Startup>();
|
||||||
|
}).ConfigureLogging((hostCtx, loggingBuilder) =>
|
||||||
|
{
|
||||||
|
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
|
||||||
|
loggingBuilder.AddNLog($"nlog-{hostCtx.HostingEnvironment.EnvironmentName}.config");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
28
gswi/Properties/launchSettings.json
Normal file
28
gswi/Properties/launchSettings.json
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"iisSettings": {
|
||||||
|
"windowsAuthentication": false,
|
||||||
|
"anonymousAuthentication": true,
|
||||||
|
"iisExpress": {
|
||||||
|
"applicationUrl": "http://localhost:50843",
|
||||||
|
"sslPort": 44360
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||||
|
"profiles": {
|
||||||
|
"IIS Express": {
|
||||||
|
"commandName": "IISExpress",
|
||||||
|
"launchUrl": "weatherforecast",
|
||||||
|
"environmentVariables": {
|
||||||
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"login_counter": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"launchUrl": "weatherforecast",
|
||||||
|
"environmentVariables": {
|
||||||
|
"DOTNET_ENVIRONMENT": "development"
|
||||||
|
},
|
||||||
|
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
gswi/Startup.cs
Normal file
186
gswi/Startup.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
using System.Text;
|
||||||
|
using System;
|
||||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using NLog.Extensions.Logging;
|
||||||
|
using NLog;
|
||||||
|
using gswi.Configuration;
|
||||||
|
using gswi.CredentialManager;
|
||||||
|
using gswi.Data;
|
||||||
|
using gswi.Data.Repositories;
|
||||||
|
using gswi.Filters;
|
||||||
|
using gswi.Interface.Repositories;
|
||||||
|
using gswi.Interface.Services;
|
||||||
|
using gswi.Service;
|
||||||
|
using gswi.SMTP.Interface;
|
||||||
|
using gswi.SMTP.Service;
|
||||||
|
using gswi.SignalR;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
|
||||||
|
namespace gswi
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public IConfiguration Configuration { get; }
|
||||||
|
private static Logger _logger = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public Startup(IHostEnvironment env)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||||
|
if (string.IsNullOrEmpty(environmentName))
|
||||||
|
environmentName = "production";
|
||||||
|
var builder = new ConfigurationBuilder().SetBasePath(env.ContentRootPath)
|
||||||
|
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||||
|
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
|
||||||
|
.AddJsonFile($"appsettings.{System.Net.Dns.GetHostName()}.json", optional: true)
|
||||||
|
.AddEnvironmentVariables();
|
||||||
|
|
||||||
|
Configuration = builder.Build();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddLogging(builder =>
|
||||||
|
{
|
||||||
|
builder.ClearProviders();
|
||||||
|
builder.AddConfiguration(Configuration.GetSection("Logging"));
|
||||||
|
builder.AddNLog();
|
||||||
|
builder.AddConsole();
|
||||||
|
});
|
||||||
|
|
||||||
|
var frontend = GetTypedSettingsFromSection<FrontendSettings>("Frontend");
|
||||||
|
|
||||||
|
services.AddCors(options =>
|
||||||
|
{
|
||||||
|
options.AddPolicy("CorsPolicy", builder => builder.WithOrigins(frontend.URL)
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials()
|
||||||
|
.SetIsOriginAllowed((host) => true));
|
||||||
|
});
|
||||||
|
|
||||||
|
var dbSettings = GetTypedSettingsFromSection<DatabaseSettings>("Database");
|
||||||
|
var authSettings = GetTypedSettingsFromSection<AuthentificationSettings>("Authentification");
|
||||||
|
var emailSettings = GetTypedSettingsFromSection<EMailSettings>("EMail");
|
||||||
|
var apiSettings = GetTypedSettingsFromSection<APISettings>("API");
|
||||||
|
emailSettings.Credentials = Base64.Decode(emailSettings.Credentials);
|
||||||
|
|
||||||
|
services.AddSingleton(dbSettings);
|
||||||
|
services.AddSingleton(authSettings);
|
||||||
|
services.AddSingleton(emailSettings);
|
||||||
|
services.AddSingleton(apiSettings);
|
||||||
|
services.AddSingleton(GetTypedSettingsFromSection<FrontendSettings>("Frontend"));
|
||||||
|
|
||||||
|
services.AddDbContextPool<DatabaseContext>(opt => opt.UseMySql(
|
||||||
|
Base64.DecodeConnectionString(dbSettings.ConnectionString, dbSettings.Credentials),
|
||||||
|
new MySqlServerVersion(new Version(10, 3, 32))
|
||||||
|
));
|
||||||
|
|
||||||
|
services.AddTransient<IAuthService, AuthServiceImpl>();
|
||||||
|
services.AddTransient<ISMTPClient, SMTPClientImpl>();
|
||||||
|
|
||||||
|
services.AddScoped<IUnitOfWork>((s) => s.GetRequiredService<DatabaseContext>());
|
||||||
|
services.AddScoped<IAuthUserRepository>((s) => new AuthUserRepositoryImpl((DatabaseContext)s.GetService<IUnitOfWork>()));
|
||||||
|
|
||||||
|
services.AddSignalR();
|
||||||
|
|
||||||
|
services.AddAuthentication(opt =>
|
||||||
|
{
|
||||||
|
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
}).AddJwtBearer(opt =>
|
||||||
|
{
|
||||||
|
opt.RequireHttpsMetadata = false;
|
||||||
|
opt.SaveToken = true;
|
||||||
|
opt.TokenValidationParameters = new TokenValidationParameters
|
||||||
|
{
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
|
||||||
|
ValidIssuer = authSettings.Issuer,
|
||||||
|
ValidAudience = authSettings.Audience,
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.SecretKey))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddControllers()
|
||||||
|
.AddNewtonsoftJson(options =>
|
||||||
|
{
|
||||||
|
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
|
||||||
|
// options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
|
||||||
|
});
|
||||||
|
|
||||||
|
services.AddControllers(options =>
|
||||||
|
{
|
||||||
|
options.Filters.Add(typeof(CustomExceptionFilterAttribute));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||||
|
public void Configure(IApplicationBuilder gswi, IWebHostEnvironment env, ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
gswi.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||||
|
{
|
||||||
|
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||||
|
});
|
||||||
|
|
||||||
|
if (env.IsDevelopment())
|
||||||
|
{
|
||||||
|
gswi.UseDeveloperExceptionPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
NLog.LogManager.LoadConfiguration($"nlog-{env.EnvironmentName}.config");
|
||||||
|
|
||||||
|
gswi.UseCors("CorsPolicy");
|
||||||
|
|
||||||
|
var apiSettings = GetTypedSettingsFromSection<APISettings>("API");
|
||||||
|
if (apiSettings.RedirectToHTTPS)
|
||||||
|
{
|
||||||
|
gswi.UseHttpsRedirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
gswi.UseRouting();
|
||||||
|
|
||||||
|
gswi.UseAuthentication();
|
||||||
|
gswi.UseAuthorization();
|
||||||
|
|
||||||
|
gswi.UseEndpoints(endpoints =>
|
||||||
|
{
|
||||||
|
endpoints.MapControllers();
|
||||||
|
endpoints.MapHub<NotifyHub>("/notify");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SettingType GetTypedSettingsFromSection<SettingType>(string sectionName) where SettingType : new()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = new SettingType();
|
||||||
|
Configuration.GetSection(sectionName).Bind(settings);
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e);
|
||||||
|
return new SettingType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
gswi/appsettings.json
Normal file
18
gswi/appsettings.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"API": {
|
||||||
|
"RedirectToHTTPS": true,
|
||||||
|
"ApiVersion": {
|
||||||
|
"Major": "HEAD",
|
||||||
|
"Minor": "0",
|
||||||
|
"Micro": "0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*"
|
||||||
|
}
|
43
gswi/gswi.csproj
Normal file
43
gswi/gswi.csproj
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RootNamespace>gswi</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="nlog-production.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="nlog-staging.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="nlog-development.config">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<Target Name="BeforeBuildEvent" BeforeTargets="BeforeBuild">
|
||||||
|
<Exec Command="powershell -executionpolicy remotesigned -File ./update-version.ps1" Condition="'$(OS)' == 'Windows_NT'"/>
|
||||||
|
<Exec Command="pwsh -executionpolicy remotesigned -File ./update-version.ps1" Condition="$([MSBuild]::IsOSPlatform('Linux'))"/>
|
||||||
|
</Target>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.2"/>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0"/>
|
||||||
|
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||||
|
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0"/>
|
||||||
|
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.1"/>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\gswi.Service\gswi.Service.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Data\gswi.Data.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Configuration\gswi.Configuration.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Model\gswi.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Interface\gswi.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.CredentialManager\gswi.CredentialManager.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Model\gswi.SMTP.Model.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Interface\gswi.SMTP.Interface.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SMTP.Service\gswi.SMTP.Service.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.SignalR\gswi.SignalR.csproj"/>
|
||||||
|
<ProjectReference Include="..\gswi.Share.Common\gswi.Share.Common.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
26
gswi/nlog-development.config
Normal file
26
gswi/nlog-development.config
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
autoReload="true"
|
||||||
|
internalLogLevel="Warn"
|
||||||
|
internalLogFile="logs/internal-nlog.txt">
|
||||||
|
|
||||||
|
<targets>
|
||||||
|
<target name="login_counter-specific-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/${logger}/${logger}-lc.{##}.txt" fileName="logs/${logger}/${logger}-lc.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
<target name="common-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/login-counter.{##}.txt" fileName="logs/login-counter.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<rules>
|
||||||
|
<logger name="LC-*" minlevel="Warn" writeTo="common-file" />
|
||||||
|
<logger name="LC-*" minlevel="Info" writeTo="gateway-specific-file" final="true"/>
|
||||||
|
<logger name="*" minLevel="Trace" writeTo="common-file"/>
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
26
gswi/nlog-production.config
Normal file
26
gswi/nlog-production.config
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
autoReload="true"
|
||||||
|
internalLogLevel="Warn"
|
||||||
|
internalLogFile="logs/internal-nlog.txt">
|
||||||
|
|
||||||
|
<targets>
|
||||||
|
<target name="login_counter-specific-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/${logger}/${logger}-lc.{##}.txt" fileName="logs/${logger}/${logger}-lc.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
<target name="common-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/login-counter.{##}.txt" fileName="logs/login-counter.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<rules>
|
||||||
|
<logger name="LC-*" minlevel="Warn" writeTo="common-file" />
|
||||||
|
<logger name="LC-*" minlevel="Trace" writeTo="gateway-specific-file" final="true"/>
|
||||||
|
<logger name="*" minLevel="Trace" writeTo="common-file"/>
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
26
gswi/nlog-staging.config
Normal file
26
gswi/nlog-staging.config
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
autoReload="true"
|
||||||
|
internalLogLevel="Warn"
|
||||||
|
internalLogFile="logs/internal-nlog.txt">
|
||||||
|
|
||||||
|
<targets>
|
||||||
|
<target name="login_counter-specific-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/${logger}/${logger}-lc.{##}.txt" fileName="logs/${logger}/${logger}-lc.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
<target name="common-file" xsi:type="AsyncWrapper" overflowAction="Grow" >
|
||||||
|
<target xsi:type="File" archiveFileName="logs/login-counter.{##}.txt" fileName="logs/login-counter.txt"
|
||||||
|
layout="${longdate} [${threadid}] ${level:uppercase=true} ${logger} - ${message} ${exception:format=ToString}"
|
||||||
|
maxArchiveFiles="10" archiveNumbering="Rolling" archiveEvery="Day" />
|
||||||
|
</target>
|
||||||
|
</targets>
|
||||||
|
|
||||||
|
<rules>
|
||||||
|
<logger name="LC-*" minlevel="Warn" writeTo="common-file" />
|
||||||
|
<logger name="LC-*" minlevel="Trace" writeTo="gateway-specific-file" final="true"/>
|
||||||
|
<logger name="*" minLevel="Trace" writeTo="common-file"/>
|
||||||
|
</rules>
|
||||||
|
</nlog>
|
52
gswi/update-version.ps1
Normal file
52
gswi/update-version.ps1
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#! /snap/bin/pwsh
|
||||||
|
|
||||||
|
function Get-VersionFromBranch {
|
||||||
|
$branch = git rev-parse --abbrev-ref HEAD
|
||||||
|
$versions = $branch.Split('.')
|
||||||
|
$major = "0"
|
||||||
|
$minor = "0"
|
||||||
|
$micro = "0"
|
||||||
|
|
||||||
|
if ($versions.Count -gt 0) {
|
||||||
|
$major = $versions[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($versions.Count -gt 1) {
|
||||||
|
$minor = $versions[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($versions.Count -gt 2) {
|
||||||
|
$micro = $versions[2]
|
||||||
|
}
|
||||||
|
|
||||||
|
return $major, $minor, $micro
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-VersionAsJSON([string]$major, [string]$minor, [string]$micro) {
|
||||||
|
return @{
|
||||||
|
"Major" = "$major"
|
||||||
|
"Minor" = "$minor"
|
||||||
|
"Micro" = "$micro"
|
||||||
|
} | ConvertTo-Json
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AppsettingsAsJSON() {
|
||||||
|
return Get-Content -Raw -Path "./appsettings.json" | ConvertFrom-Json
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-AppsettingsAsJSON($settings) {
|
||||||
|
$settings | ConvertTo-Json | Out-File "./appsettings.json"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Set-VersionFromBranch([string]$major, [string]$minor, [string]$micro) {
|
||||||
|
$versionJSON = Get-VersionAsJSON $major $minor $micro
|
||||||
|
$appsettings = Get-AppsettingsAsJSON
|
||||||
|
|
||||||
|
$appsettings.API.ApiVersion.Major = $major
|
||||||
|
$appsettings.API.ApiVersion.Minor = $minor
|
||||||
|
$appsettings.API.ApiVersion.Micro = $micro
|
||||||
|
Set-AppsettingsAsJSON $appsettings
|
||||||
|
}
|
||||||
|
|
||||||
|
$res = Get-VersionFromBranch
|
||||||
|
Set-VersionFromBranch $res[0] $res[1] $res[2]
|
Reference in New Issue
Block a user