Added first app template
This commit is contained in:
commit
fb2a0080bc
64
.gitignore
vendored
Normal file
64
.gitignore
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
# 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
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 sh-edraft.de
|
||||
|
||||
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
backend/login-counter/app.Configuration/APISettings.cs
Normal file
10
backend/login-counter/app.Configuration/APISettings.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace app.Configuration
|
||||
{
|
||||
public class APISettings
|
||||
{
|
||||
public bool RedirectToHTTPS { get; set; }
|
||||
public APIVersionSettings ApiVersion { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace app.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}";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace app.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; }
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Configuration/Constants.cs
Normal file
7
backend/login-counter/app.Configuration/Constants.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace app.Configuration {
|
||||
public static class Constants {
|
||||
public const string CustomerEnvironmentVariable = "CUSTOMER";
|
||||
public const string ComputerNameEnvironmentVariable = "COMPUTERNAME";
|
||||
public const string CustomersDirectoryName = "customers";
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace app.Configuration
|
||||
{
|
||||
public class DatabaseSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public string Credentials { get; set; }
|
||||
}
|
||||
}
|
14
backend/login-counter/app.Configuration/EMailSettings.cs
Normal file
14
backend/login-counter/app.Configuration/EMailSettings.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace app.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; }
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
namespace app.Configuration
|
||||
{
|
||||
public class FrontendSettings
|
||||
{
|
||||
public string URL { get; set; }
|
||||
}
|
||||
}
|
115
backend/login-counter/app.Configuration/HostExtensions.cs
Normal file
115
backend/login-counter/app.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 app.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
backend/login-counter/app.CredentialManager/Base64.cs
Normal file
25
backend/login-counter/app.CredentialManager/Base64.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace app.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
backend/login-counter/app.CredentialManager/Program.cs
Normal file
89
backend/login-counter/app.CredentialManager/Program.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using app.Configuration;
|
||||
|
||||
namespace app.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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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="..\app.Configuration\app.Configuration.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
73
backend/login-counter/app.Data/DatabaseContext.cs
Normal file
73
backend/login-counter/app.Data/DatabaseContext.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using app.Interface.Repositories;
|
||||
using app.Model;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Data/DesignTimeContextFactory.cs
Normal file
22
backend/login-counter/app.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 app.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
backend/login-counter/app.Data/LinqExtension.cs
Normal file
30
backend/login-counter/app.Data/LinqExtension.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Data/Migrations/20210213133159_2021_03_10.Designer.cs
generated
Normal file
291
backend/login-counter/app.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 app.Data;
|
||||
|
||||
namespace app.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("app.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("app.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("app.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("app.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("app.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("app.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("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("DomainId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("DomainId");
|
||||
|
||||
b.HasDiscriminator().HasValue("DomainUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("HostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("HostId");
|
||||
|
||||
b.HasDiscriminator().HasValue("HostUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Host", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("DomainId");
|
||||
|
||||
b.HasOne("app.Model.OperatingSystem", "OS")
|
||||
.WithMany()
|
||||
.HasForeignKey("OSId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Login", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("HostId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("app.Model.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("DomainId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("HostId");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,249 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Data/Migrations/20210217201310_2021_03_13.Designer.cs
generated
Normal file
294
backend/login-counter/app.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 app.Data;
|
||||
|
||||
namespace app.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("app.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("app.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("app.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("app.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("app.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("app.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("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("DomainId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("DomainId");
|
||||
|
||||
b.HasDiscriminator().HasValue("DomainUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("HostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("HostId");
|
||||
|
||||
b.HasDiscriminator().HasValue("HostUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Host", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("DomainId");
|
||||
|
||||
b.HasOne("app.Model.OperatingSystem", "OS")
|
||||
.WithMany()
|
||||
.HasForeignKey("OSId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Login", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("HostId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("app.Model.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("DomainId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("HostId");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Data/Migrations/20210220140309_2021_03_14.Designer.cs
generated
Normal file
291
backend/login-counter/app.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 app.Data;
|
||||
|
||||
namespace app.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("app.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("app.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("app.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("app.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("app.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("app.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("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("DomainId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("DomainId");
|
||||
|
||||
b.HasDiscriminator().HasValue("DomainUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("HostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("HostId");
|
||||
|
||||
b.HasDiscriminator().HasValue("HostUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Host", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("DomainId");
|
||||
|
||||
b.HasOne("app.Model.OperatingSystem", "OS")
|
||||
.WithMany()
|
||||
.HasForeignKey("OSId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Login", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("HostId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("app.Model.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("DomainId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("HostId");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace app.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,289 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using app.Data;
|
||||
|
||||
namespace app.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("app.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("app.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("app.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("app.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("app.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("app.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("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("DomainId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("DomainId");
|
||||
|
||||
b.HasDiscriminator().HasValue("DomainUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasBaseType("app.Model.User");
|
||||
|
||||
b.Property<long?>("HostId")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.HasIndex("HostId");
|
||||
|
||||
b.HasDiscriminator().HasValue("HostUser");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Host", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Hosts")
|
||||
.HasForeignKey("DomainId");
|
||||
|
||||
b.HasOne("app.Model.OperatingSystem", "OS")
|
||||
.WithMany()
|
||||
.HasForeignKey("OSId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.Login", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("HostId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("app.Model.User", "User")
|
||||
.WithMany("Logins")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.DomainUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Domain", "Domain")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("DomainId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("app.Model.HostUser", b =>
|
||||
{
|
||||
b.HasOne("app.Model.Host", "Host")
|
||||
.WithMany("Users")
|
||||
.HasForeignKey("HostId");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using app.Interface.Repositories;
|
||||
using app.Model;
|
||||
using app.Share.Common;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Data/app.Data.csproj
Normal file
23
backend/login-counter/app.Data/app.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="..\app.Model\app.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.Interface\app.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.Share.Common\app.Share.Common.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using app.Model;
|
||||
using app.Share.Common;
|
||||
|
||||
namespace app.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);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace app.Interface.Repositories {
|
||||
public interface IUnitOfWork : IDisposable {
|
||||
int SaveChanges();
|
||||
Task<int> SaveChangesAsync();
|
||||
}
|
||||
}
|
28
backend/login-counter/app.Interface/Services/IAuthService.cs
Normal file
28
backend/login-counter/app.Interface/Services/IAuthService.cs
Normal file
@ -0,0 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
using app.Model.DTOs;
|
||||
using app.Share.Common;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Interface/app.Interface.csproj
Normal file
12
backend/login-counter/app.Interface/app.Interface.csproj
Normal file
@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\app.Model\app.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.Share.Common\app.Share.Common.csproj"/>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NLog" Version="4.7.13"/>
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
</Project>
|
10
backend/login-counter/app.Model/AuthRoles.cs
Normal file
10
backend/login-counter/app.Model/AuthRoles.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model
|
||||
{
|
||||
public enum AuthRoles
|
||||
{
|
||||
Normal = 0,
|
||||
Admin = 1
|
||||
}
|
||||
}
|
34
backend/login-counter/app.Model/AuthUser.cs
Normal file
34
backend/login-counter/app.Model/AuthUser.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using app.Model.DTOs;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Model/DTOs/AdminUpdateUserDTO.cs
Normal file
11
backend/login-counter/app.Model/DTOs/AdminUpdateUserDTO.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class AdminUpdateUserDTO
|
||||
{
|
||||
public AuthUserDTO AuthUserDTO { get; set; }
|
||||
public AuthUserDTO NewAuthUserDTO { get; set; }
|
||||
public bool ChangePassword { get; set; }
|
||||
}
|
||||
}
|
11
backend/login-counter/app.Model/DTOs/ApiVersionDTO.cs
Normal file
11
backend/login-counter/app.Model/DTOs/ApiVersionDTO.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class ApiVersionDTO
|
||||
{
|
||||
public string Major { get; set; }
|
||||
public string Minor { get; set; }
|
||||
public string Micro { get; set; }
|
||||
}
|
||||
}
|
27
backend/login-counter/app.Model/DTOs/AuthUserDTO.cs
Normal file
27
backend/login-counter/app.Model/DTOs/AuthUserDTO.cs
Normal file
@ -0,0 +1,27 @@
|
||||
namespace app.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
backend/login-counter/app.Model/DTOs/EMailStringDTO.cs
Normal file
9
backend/login-counter/app.Model/DTOs/EMailStringDTO.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class EMailStringDTO
|
||||
{
|
||||
public string EMail { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class GetFilteredAuthUsersResultDTO
|
||||
{
|
||||
public List<AuthUserDTO> Users { get; set; }
|
||||
public int TotalCount { get; set; }
|
||||
}
|
||||
}
|
10
backend/login-counter/app.Model/DTOs/ResetPasswordDTO.cs
Normal file
10
backend/login-counter/app.Model/DTOs/ResetPasswordDTO.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class ResetPasswordDTO
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
22
backend/login-counter/app.Model/DTOs/SettingsDTO.cs
Normal file
22
backend/login-counter/app.Model/DTOs/SettingsDTO.cs
Normal file
@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Model/DTOs/TokenDTO.cs
Normal file
8
backend/login-counter/app.Model/DTOs/TokenDTO.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class TokenDTO
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
}
|
10
backend/login-counter/app.Model/DTOs/UpdateUserDTO.cs
Normal file
10
backend/login-counter/app.Model/DTOs/UpdateUserDTO.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public class UpdateUserDTO
|
||||
{
|
||||
public AuthUserDTO AuthUserDTO { get; set; }
|
||||
public AuthUserDTO NewAuthUserDTO { get; set; }
|
||||
}
|
||||
}
|
13
backend/login-counter/app.Model/DTOs/UserDTO.cs
Normal file
13
backend/login-counter/app.Model/DTOs/UserDTO.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace app.Model.DTOs
|
||||
{
|
||||
public abstract class UserDTO
|
||||
{
|
||||
public long Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool NotifyWhenLogin { get; set; }
|
||||
}
|
||||
}
|
21
backend/login-counter/app.Model/Filter/ErrorDTO.cs
Normal file
21
backend/login-counter/app.Model/Filter/ErrorDTO.cs
Normal file
@ -0,0 +1,21 @@
|
||||
namespace app.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
backend/login-counter/app.Model/Filter/ServiceErrorCode.cs
Normal file
21
backend/login-counter/app.Model/Filter/ServiceErrorCode.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Threading;
|
||||
namespace app.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
backend/login-counter/app.Model/Filter/ServiceException.cs
Normal file
23
backend/login-counter/app.Model/Filter/ServiceException.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Model/IAutoGenerateDateFields.cs
Normal file
10
backend/login-counter/app.Model/IAutoGenerateDateFields.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace app.Model {
|
||||
public interface IAutoGenerateDateFields {
|
||||
DateTimeOffset CreatedOn { get; set; }
|
||||
DateTimeOffset LastModifiedOn { get; set; }
|
||||
}
|
||||
}
|
8
backend/login-counter/app.Model/app.Model.csproj
Normal file
8
backend/login-counter/app.Model/app.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
backend/login-counter/app.SMTP.Interface/ISMTPClient.cs
Normal file
10
backend/login-counter/app.SMTP.Interface/ISMTPClient.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System.Threading.Tasks;
|
||||
using app.SMTP.Model;
|
||||
|
||||
namespace app.SMTP.Interface
|
||||
{
|
||||
public interface ISMTPClient
|
||||
{
|
||||
Task SendEmailAsync(EMail email);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\app.SMTP.Model\app.SMTP.Model.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
11
backend/login-counter/app.SMTP.Model/EMail.cs
Normal file
11
backend/login-counter/app.SMTP.Model/EMail.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace app.SMTP.Model
|
||||
{
|
||||
public class EMail
|
||||
{
|
||||
public string Receiver { get; set; }
|
||||
public string Subject { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
80
backend/login-counter/app.SMTP.Service/SMTPClientImpl.cs
Normal file
80
backend/login-counter/app.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 app.Configuration;
|
||||
using app.Model.Filters;
|
||||
using app.SMTP.Interface;
|
||||
using app.SMTP.Model;
|
||||
|
||||
namespace app.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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\app.SMTP.Model\app.SMTP.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Interface\app.SMTP.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.Configuration\app.Configuration.csproj"/>
|
||||
<ProjectReference Include="..\app.Model\app.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
backend/login-counter/app.Service/AuthServiceImpl.cs
Normal file
604
backend/login-counter/app.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 app.Configuration;
|
||||
using app.Interface.Repositories;
|
||||
using app.Interface.Services;
|
||||
using app.Model;
|
||||
using app.Model.DTOs;
|
||||
using app.Model.Filters;
|
||||
using app.Share.Common;
|
||||
using app.SMTP.Interface;
|
||||
using app.SMTP.Model;
|
||||
|
||||
namespace app.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
backend/login-counter/app.Service/app.Service.csproj
Normal file
19
backend/login-counter/app.Service/app.Service.csproj
Normal file
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\app.Interface\app.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.Model\app.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.Data\app.Data.csproj"/>
|
||||
<ProjectReference Include="..\app.Configuration\app.Configuration.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Interface\app.SMTP.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Model\app.SMTP.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.Share.Common\app.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>
|
@ -0,0 +1,11 @@
|
||||
namespace app.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; }
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using System;
|
||||
namespace app.Share.Common
|
||||
{
|
||||
public class DomainSelectCriterion : SelectCriterion
|
||||
{
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
namespace app.Share.Common
|
||||
{
|
||||
public class HostSelectCriterion : SelectCriterion
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int[] IPAddress { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public string OSName { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
namespace app.Share.Common
|
||||
{
|
||||
public class LoginSelectCriterion : SelectCriterion
|
||||
{
|
||||
public DateTimeOffset? TimeFrom { get; set; }
|
||||
public DateTimeOffset? TimeTo { get; set; }
|
||||
public string HostName { get; set; }
|
||||
public string UserName { get; set; }
|
||||
}
|
||||
}
|
10
backend/login-counter/app.Share.Common/SelectCriterion.cs
Normal file
10
backend/login-counter/app.Share.Common/SelectCriterion.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace app.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; }
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
namespace app.Share.Common
|
||||
{
|
||||
public class UserSelectCriterion : SelectCriterion
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string DomainName { get; set; }
|
||||
public string HostName { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\app.Share.Common.Interface\app.Share.Common.Interface.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
9
backend/login-counter/app.SignalR/NotifyHub.cs
Normal file
9
backend/login-counter/app.SignalR/NotifyHub.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
|
||||
namespace app.SignalR
|
||||
{
|
||||
public class NotifyHub : Hub
|
||||
{
|
||||
}
|
||||
}
|
11
backend/login-counter/app.SignalR/app.SignalR.csproj
Normal file
11
backend/login-counter/app.SignalR/app.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
backend/login-counter/app.sln
Normal file
127
backend/login-counter/app.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}") = "app", "app\app.csproj", "{9AB6095F-23EF-4925-9637-7F0B7DE57D4A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Configuration", "app.Configuration\app.Configuration.csproj", "{6079B54E-42E1-4B68-8BE5-C831E6C0B3A3}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.CredentialManager", "app.CredentialManager\app.CredentialManager.csproj", "{90969785-C60C-45DB-A84E-E92A65755DF0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Data", "app.Data\app.Data.csproj", "{1F380FAE-D068-40BB-869A-80CE076A2C81}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Interface", "app.Interface\app.Interface.csproj", "{447C2465-462F-4DBC-95F8-2330BBE36C4E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Model", "app.Model\app.Model.csproj", "{185EDC35-E150-4404-90EC-562819397D80}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Service", "app.Service\app.Service.csproj", "{F90A1288-0A41-449F-A856-F8988E77547F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.SMTP.Interface", "app.SMTP.Interface\app.SMTP.Interface.csproj", "{EAE98478-F76B-4A37-A428-3A4F9DF18458}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.SMTP.Service", "app.SMTP.Service\app.SMTP.Service.csproj", "{EC9B5EB4-EADC-4A95-8E67-4DF8B6BB8ED6}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.SMTP.Model", "app.SMTP.Model\app.SMTP.Model.csproj", "{7A792724-5EBF-4B12-AB8B-ACEF17F3E752}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.SignalR", "app.SignalR\app.SignalR.csproj", "{B55249FD-3E4B-497B-810F-C7D60DB7A09C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "app.Share.Common", "app.Share.Common\app.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
backend/login-counter/app/Controllers/AuthController.cs
Normal file
148
backend/login-counter/app/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 app.Interface.Services;
|
||||
using app.Model.DTOs;
|
||||
using app.Share.Common;
|
||||
|
||||
namespace app.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
backend/login-counter/app/Controllers/GUIController.cs
Normal file
92
backend/login-counter/app/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 app.Configuration;
|
||||
using app.Model.DTOs;
|
||||
using app.SMTP.Interface;
|
||||
using app.SMTP.Model;
|
||||
|
||||
namespace app.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
backend/login-counter/app/DataSeeder.cs
Normal file
76
backend/login-counter/app/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 app.Data;
|
||||
using app.Model;
|
||||
|
||||
namespace app
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using NLog;
|
||||
using app.Model.Filters;
|
||||
|
||||
namespace app.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
backend/login-counter/app/HostExtensions.cs
Normal file
30
backend/login-counter/app/HostExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using app.Data;
|
||||
|
||||
namespace app
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
|
||||
namespace app.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
backend/login-counter/app/Program.cs
Normal file
43
backend/login-counter/app/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 app.Configuration;
|
||||
using System;
|
||||
|
||||
namespace app
|
||||
{
|
||||
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
backend/login-counter/app/Properties/launchSettings.json
Normal file
28
backend/login-counter/app/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
backend/login-counter/app/Startup.cs
Normal file
186
backend/login-counter/app/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 app.Configuration;
|
||||
using app.CredentialManager;
|
||||
using app.Data;
|
||||
using app.Data.Repositories;
|
||||
using app.Filters;
|
||||
using app.Interface.Repositories;
|
||||
using app.Interface.Services;
|
||||
using app.Service;
|
||||
using app.SMTP.Interface;
|
||||
using app.SMTP.Service;
|
||||
using app.SignalR;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
|
||||
namespace app
|
||||
{
|
||||
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 app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
|
||||
{
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
NLog.LogManager.LoadConfiguration($"nlog-{env.EnvironmentName}.config");
|
||||
|
||||
app.UseCors("CorsPolicy");
|
||||
|
||||
var apiSettings = GetTypedSettingsFromSection<APISettings>("API");
|
||||
if (apiSettings.RedirectToHTTPS)
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
|
||||
app.UseRouting();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
backend/login-counter/app/app.csproj
Normal file
43
backend/login-counter/app/app.csproj
Normal file
@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>app</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="..\app.Service\app.Service.csproj"/>
|
||||
<ProjectReference Include="..\app.Data\app.Data.csproj"/>
|
||||
<ProjectReference Include="..\app.Configuration\app.Configuration.csproj"/>
|
||||
<ProjectReference Include="..\app.Model\app.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.Interface\app.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.CredentialManager\app.CredentialManager.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Model\app.SMTP.Model.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Interface\app.SMTP.Interface.csproj"/>
|
||||
<ProjectReference Include="..\app.SMTP.Service\app.SMTP.Service.csproj"/>
|
||||
<ProjectReference Include="..\app.SignalR\app.SignalR.csproj"/>
|
||||
<ProjectReference Include="..\app.Share.Common\app.Share.Common.csproj"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
13
backend/login-counter/app/appsettings.development.json
Normal file
13
backend/login-counter/app/appsettings.development.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Debug"
|
||||
}
|
||||
},
|
||||
|
||||
"Database": {
|
||||
"ConnectionString": ""
|
||||
}
|
||||
}
|
18
backend/login-counter/app/appsettings.json
Normal file
18
backend/login-counter/app/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": "*"
|
||||
}
|
13
backend/login-counter/app/appsettings.production.json
Normal file
13
backend/login-counter/app/appsettings.production.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
|
||||
"Database": {
|
||||
"ConnectionString": ""
|
||||
}
|
||||
}
|
13
backend/login-counter/app/appsettings.staging.json
Normal file
13
backend/login-counter/app/appsettings.staging.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
|
||||
"Database": {
|
||||
"ConnectionString": ""
|
||||
}
|
||||
}
|
26
backend/login-counter/app/nlog-development.config
Normal file
26
backend/login-counter/app/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
backend/login-counter/app/nlog-production.config
Normal file
26
backend/login-counter/app/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
backend/login-counter/app/nlog-staging.config
Normal file
26
backend/login-counter/app/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
backend/login-counter/app/update-version.ps1
Normal file
52
backend/login-counter/app/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]
|
18
frontend/login-counter/.browserslistrc
Normal file
18
frontend/login-counter/.browserslistrc
Normal file
@ -0,0 +1,18 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# For the full list of supported browsers by the Angular framework, please see:
|
||||
# https://angular.io/guide/browser-support
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
last 1 Chrome version
|
||||
last 1 Firefox version
|
||||
last 2 Edge major versions
|
||||
last 2 Safari major versions
|
||||
last 2 iOS major versions
|
||||
Firefox ESR
|
||||
not IE 9-10 # Angular support for IE 9-10 has been deprecated and will be removed as of Angular v11. To opt-in, remove the 'not' prefix on this line.
|
||||
not IE 11 # Angular supports IE 11 only as an opt-in. To opt-in, remove the 'not' prefix on this line.
|
16
frontend/login-counter/.editorconfig
Normal file
16
frontend/login-counter/.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.ts]
|
||||
quote_type = single
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
27
frontend/login-counter/README.md
Normal file
27
frontend/login-counter/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# LoginCounter
|
||||
|
||||
This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.1.3.
|
||||
|
||||
## Development server
|
||||
|
||||
Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Running end-to-end tests
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
140
frontend/login-counter/angular.json
Normal file
140
frontend/login-counter/angular.json
Normal file
@ -0,0 +1,140 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"app": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/app",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": [
|
||||
"src/assets/images/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss",
|
||||
"node_modules/primeicons/primeicons.css",
|
||||
"node_modules/primeng/resources/themes/saga-blue/theme.css",
|
||||
"node_modules/primeng/resources/primeng.min.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"vendorChunk": true,
|
||||
"extractLicenses": false,
|
||||
"buildOptimizer": false,
|
||||
"sourceMap": true,
|
||||
"optimization": false,
|
||||
"namedChunks": true
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"defaultConfiguration": ""
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "app:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "app:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.scss"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "app:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "app:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "app",
|
||||
"cli": {
|
||||
"analytics": "dcc5d68a-d438-4579-bac1-5bc2d574bd1a"
|
||||
}
|
||||
}
|
36
frontend/login-counter/e2e/protractor.conf.js
Normal file
36
frontend/login-counter/e2e/protractor.conf.js
Normal file
@ -0,0 +1,36 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({
|
||||
spec: {
|
||||
displayStacktrace: StacktraceOption.PRETTY
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
23
frontend/login-counter/e2e/src/app.e2e-spec.ts
Normal file
23
frontend/login-counter/e2e/src/app.e2e-spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('app app is running!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
11
frontend/login-counter/e2e/src/app.po.ts
Normal file
11
frontend/login-counter/e2e/src/app.po.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo(): Promise<unknown> {
|
||||
return browser.get(browser.baseUrl) as Promise<unknown>;
|
||||
}
|
||||
|
||||
getTitleText(): Promise<string> {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||
}
|
||||
}
|
14
frontend/login-counter/e2e/tsconfig.json
Normal file
14
frontend/login-counter/e2e/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
32
frontend/login-counter/karma.conf.js
Normal file
32
frontend/login-counter/karma.conf.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/app'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
33392
frontend/login-counter/package-lock.json
generated
Normal file
33392
frontend/login-counter/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
58
frontend/login-counter/package.json
Normal file
58
frontend/login-counter/package.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "app",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"update-version": "ts-node -O '{\"module\": \"commonjs\"}' update-version.ts",
|
||||
"#prestart": "npm run update-version",
|
||||
"start": "ng serve",
|
||||
"#prebuild": "npm run update-version",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~12.2.5",
|
||||
"@angular/cdk": "^12.2.5",
|
||||
"@angular/common": "~12.2.5",
|
||||
"@angular/compiler": "~12.2.5",
|
||||
"@angular/core": "~12.2.5",
|
||||
"@angular/forms": "~12.2.5",
|
||||
"@angular/platform-browser": "~12.2.5",
|
||||
"@angular/platform-browser-dynamic": "~12.2.5",
|
||||
"@angular/router": "~12.2.5",
|
||||
"@aspnet/signalr": "^3.0.0-preview6.19307.2",
|
||||
"@auth0/angular-jwt": "^5.0.2",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"primeicons": "^4.1.0",
|
||||
"primeng": "^12.1.1",
|
||||
"rxjs": "^6.6.7",
|
||||
"ts-lint": "^4.5.1",
|
||||
"tslib": "^2.3.1",
|
||||
"zone.js": "~0.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~12.2.5",
|
||||
"@angular/cli": "~12.2.5",
|
||||
"@angular/compiler-cli": "~12.2.5",
|
||||
"@angular/localize": "^12.2.5",
|
||||
"@types/jasmine": "^3.9.0",
|
||||
"@types/jasminewd2": "^2.0.10",
|
||||
"@types/node": "^12.20.24",
|
||||
"codelyzer": "^6.0.2",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~6.3.4",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.7.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~8.3.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~4.2.4"
|
||||
}
|
||||
}
|
23
frontend/login-counter/src/app/app-routing.module.ts
Normal file
23
frontend/login-counter/src/app/app-routing.module.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { NotFoundComponent } from './components/error/not-found/not-found.component';
|
||||
import { HomeComponent } from './components/home/home.component';
|
||||
import { AuthRoles } from './models/auth/auth-roles.enum';
|
||||
import { AuthGuard } from './modules/shared/guards/auth/auth.guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'home', pathMatch: 'full' },
|
||||
{ path: 'home', component: HomeComponent, pathMatch: 'full' },
|
||||
{ path: 'change-password', loadChildren: () => import('./modules/view/change-password/change-password.module').then(m => m.ChangePasswordModule), canActivate: [AuthGuard] },
|
||||
{ path: 'user-settings', loadChildren: () => import('./modules/view/user-settings/user-settings.module').then(m => m.UserSettingsModule), canActivate: [AuthGuard] },
|
||||
{ path: 'auth', loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule) },
|
||||
{ path: 'admin/settings', loadChildren: () => import('./modules/admin/settings/settings.module').then(m => m.SettingsModule), canActivate: [AuthGuard], data: { role: AuthRoles.Admin } },
|
||||
{ path: 'admin/users', loadChildren: () => import('./modules/admin/auth-users/auth-user.module').then(m => m.AuthUserModule), canActivate: [AuthGuard], data: { role: AuthRoles.Admin } },
|
||||
{ path: '404', component: NotFoundComponent}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
36
frontend/login-counter/src/app/app.component.html
Normal file
36
frontend/login-counter/src/app/app.component.html
Normal file
@ -0,0 +1,36 @@
|
||||
<main [class]="themeService.themeName">
|
||||
<ng-container *ngIf="authService.isLoggedIn; else login">
|
||||
<app-header (isSidebarFullWidth)="themeService.setSideWidth($event)"></app-header>
|
||||
|
||||
<section class="app">
|
||||
<div>
|
||||
<section class="sidebar" [style.width]="themeService.sidebarWidth">
|
||||
<app-sidebar [isSidebarOpen]="themeService.isSidebarOpen"></app-sidebar>
|
||||
</section>
|
||||
</div>
|
||||
<div class="component-wrapper">
|
||||
<section class="component">
|
||||
<router-outlet></router-outlet>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<app-footer></app-footer>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-template #login>
|
||||
<router-outlet></router-outlet>
|
||||
</ng-template>
|
||||
|
||||
<app-spinner></app-spinner>
|
||||
<p-confirmDialog #cd key="confirmConfirmationDialog" [baseZIndex]="10000">
|
||||
<ng-template pTemplate="footer">
|
||||
<div class="wrapper-right btn-wrapper">
|
||||
<button pButton label="{{'dialog.abort' | translate}}" class="btn icon-btn danger-icon-btn" icon="pi pi-times-circle" (click)="cd.reject()"></button>
|
||||
<button pButton label="{{'dialog.confirm' | translate}}" class="btn" icon="pi pi-check-circle" (click)="cd.accept()"></button>
|
||||
</div>
|
||||
</ng-template>
|
||||
</p-confirmDialog>
|
||||
<p-toast></p-toast>
|
||||
</main>
|
0
frontend/login-counter/src/app/app.component.scss
Normal file
0
frontend/login-counter/src/app/app.component.scss
Normal file
35
frontend/login-counter/src/app/app.component.spec.ts
Normal file
35
frontend/login-counter/src/app/app.component.spec.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'app'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.componentInstance;
|
||||
expect(app.title).toEqual('app');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain('app app is running!');
|
||||
});
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user