diff --git a/BlueWest.Api/Controllers/AuthController.cs b/BlueWest.Api/Controllers/AuthController.cs index 3ce2a23..d429524 100644 --- a/BlueWest.Api/Controllers/AuthController.cs +++ b/BlueWest.Api/Controllers/AuthController.cs @@ -3,6 +3,7 @@ using BlueWest.Data.Auth; using BlueWest.Data.Auth.Context.Users; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; @@ -35,13 +36,13 @@ namespace BlueWest.WebApi.Controllers; /// /// Signup user /// - /// + /// /// [AllowAnonymous] [HttpPost("register")] - public async Task> SignupUserAsync(RegisterViewModel registerViewModel) + public async Task> SignupUserAsync(RegisterRequest registerRequest) { - return await _authManager.CreateUserAsync(registerViewModel); + return await _authManager.CreateUserAsync(registerRequest); } @@ -55,7 +56,7 @@ namespace BlueWest.WebApi.Controllers; [HttpPost("login")] public async Task> GetSessionToken(LoginRequest loginViewModel) { - var (success, sessionToken, _) = await _authManager.GetSessionTokenIdByLoginRequest(loginViewModel); + var (success, sessionToken, _) = await _authManager.GetSessionTokenIdByLoginRequest(loginViewModel, JwtBearerDefaults.AuthenticationScheme); if (success) { diff --git a/BlueWest.Api/Startup.cs b/BlueWest.Api/Startup.cs index 2047125..c8379ec 100644 --- a/BlueWest.Api/Startup.cs +++ b/BlueWest.Api/Startup.cs @@ -54,7 +54,14 @@ namespace BlueWest.WebApi .AllowCredentials(); }); }); - + services.AddDistributedMemoryCache(); + + services.AddSession(options => + { + options.Cookie.Name = ".BlueWest.Session"; + options.Cookie.Domain = SessionConstants.CookieDomain; + options.Cookie.HttpOnly = true; + }); services .AddResponseCaching() .AddControllers(options => @@ -71,12 +78,8 @@ namespace BlueWest.WebApi { builder.AddSimpleConsole(); }); - - services.AddSession(options => - { - options.Cookie.Domain = SessionConstants.CookieDomain; - options.Cookie.HttpOnly = true; - }); + + services .AddSwaggerGen(options => { @@ -136,20 +139,15 @@ namespace BlueWest.WebApi ); */ - - IConfigurationRoot configuration = new ConfigurationBuilder() - .AddJsonFile("config.json") - .Build(); - services .AddSingleton(); - services.AddAuthServerServices( _configuration, _environment, configuration); + services.AddAuthServerServices( _configuration, _environment); services.AddScoped(); - services.PrepareMySqlDatabasePool(_configuration, _environment, configuration); + services.PrepareMySqlDatabasePool(_configuration, _environment); @@ -180,6 +178,7 @@ namespace BlueWest.WebApi app.UseRouting(); app.UseCors(MyAllowSpecificOrigins); + app.UseSession(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => diff --git a/BlueWest.Api/StartupExtensions.cs b/BlueWest.Api/StartupExtensions.cs index 667685b..d17b5ae 100644 --- a/BlueWest.Api/StartupExtensions.cs +++ b/BlueWest.Api/StartupExtensions.cs @@ -32,23 +32,23 @@ namespace BlueWest.WebApi { private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) => new (new Version(major, minor, build)); - private static BlueWestConnectionString GetConnectionString(this IConfigurationRoot configurationRoot) + private static string GetConnectionString(this IConfiguration configurationRoot, string db) { // Docker / No-Docker var startupMode = configurationRoot["mode"]; if (startupMode == "docker") { - var config = configurationRoot.Get(); + var config = configurationRoot.GetSection("ConnectionStringDocker")[db]; return config; } else { - var config = configurationRoot.Get(); + var config = configurationRoot.GetSection("ConnectionStringNoDocker")[db]; return config; } - return null; + return string.Empty; } /// @@ -60,14 +60,13 @@ namespace BlueWest.WebApi private static DbContextOptionsBuilder GetMySqlSettings( this DbContextOptionsBuilder optionsBuilder, IConfiguration configuration, - IConfigurationRoot configurationRoot, IWebHostEnvironment environment) { var sqlVersion = GetMySqlServerVersion(8, 0, 11); // Docker / No-Docker - - string mySqlConnectionString = configurationRoot.GetConnectionString().MySql; + + var mySqlConnectionString = configuration.GetConnectionString("MySQL"); if (mySqlConnectionString == string.Empty) { @@ -106,25 +105,25 @@ namespace BlueWest.WebApi /// /// public static IServiceCollection PrepareMySqlDatabasePool(this IServiceCollection serviceCollection, - IConfiguration configuration, IWebHostEnvironment environment, IConfigurationRoot configurationRoot) + IConfiguration configuration, IWebHostEnvironment environment) { return serviceCollection .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) + options.GetMySqlSettings(configuration, environment)) .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) + options.GetMySqlSettings(configuration, environment)) .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) + options.GetMySqlSettings(configuration, environment)) .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) + options.GetMySqlSettings(configuration, environment)) .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)); + options.GetMySqlSettings(configuration, environment)); } - internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, IConfiguration configuration , IWebHostEnvironment environment, IConfigurationRoot configurationRoot) + internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, IConfiguration configuration , IWebHostEnvironment environment) { - var connectionString = configurationRoot.GetConnectionString(); + var connectionString = configuration.GetConnectionString("Redis"); if (connectionString == null) { @@ -132,7 +131,7 @@ namespace BlueWest.WebApi } services - .AddSingleton(new RedisConnectionProvider(connectionString.Redis)) + .AddSingleton(new RedisConnectionProvider(connectionString)) .AddScoped() .AddScoped() .AddHostedService() diff --git a/BlueWest.Api/config.json b/BlueWest.Api/config.json deleted file mode 100644 index 4cf70fd..0000000 --- a/BlueWest.Api/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "mode": "no-docker", - "database": "mysql" -} \ No newline at end of file diff --git a/BlueWest.Data.Auth/BlueWest.Data.Auth.csproj b/BlueWest.Data.Auth/BlueWest.Data.Auth.csproj index bc92b8f..24fb517 100644 --- a/BlueWest.Data.Auth/BlueWest.Data.Auth.csproj +++ b/BlueWest.Data.Auth/BlueWest.Data.Auth.csproj @@ -44,4 +44,12 @@ + + + true + PreserveNewest + PreserveNewest + + + diff --git a/BlueWest.Data.Auth/Class1.cs b/BlueWest.Data.Auth/Class1.cs deleted file mode 100644 index 77bc2b9..0000000 --- a/BlueWest.Data.Auth/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace BlueWest.Data.Auth; - -public class Class1 -{ -} \ No newline at end of file diff --git a/BlueWest.Data.Auth/Configuration/BlueWestConnectionString.cs b/BlueWest.Data.Auth/Configuration/BlueWestConnectionString.cs index 9d3813a..54475bc 100644 --- a/BlueWest.Data.Auth/Configuration/BlueWestConnectionString.cs +++ b/BlueWest.Data.Auth/Configuration/BlueWestConnectionString.cs @@ -1,12 +1,16 @@ namespace BlueWest.WebApi.Configuration { - public class BlueWestConnectionString + public class ConnectionStringDocker { public string Redis { get; set; } public string MySql { get; set; } } - public class ConnectionStringDocker : BlueWestConnectionString { } - public class ConnectionStringNoDocker : BlueWestConnectionString { } + public class ConnectionStringNoDocker + { + public string Redis { get; set; } + public string MySql { get; set; } + } + } diff --git a/BlueWest.Data.Auth/Session/LoginRequest.cs b/BlueWest.Data.Auth/Session/LoginRequest.cs index 8beadb5..8a1867a 100644 --- a/BlueWest.Data.Auth/Session/LoginRequest.cs +++ b/BlueWest.Data.Auth/Session/LoginRequest.cs @@ -23,7 +23,7 @@ namespace BlueWest.Data.Auth.Context.Users public string Password { get; set; } [Required] - public string Uuid { get; set; } + public string Uuid { get ; set; } /// /// Gets Uuid for this login request diff --git a/BlueWest.Data.Auth/Session/RegisterViewModel.cs b/BlueWest.Data.Auth/Session/RegisterRequest.cs similarity index 98% rename from BlueWest.Data.Auth/Session/RegisterViewModel.cs rename to BlueWest.Data.Auth/Session/RegisterRequest.cs index b3348c1..5b3f826 100644 --- a/BlueWest.Data.Auth/Session/RegisterViewModel.cs +++ b/BlueWest.Data.Auth/Session/RegisterRequest.cs @@ -6,7 +6,7 @@ namespace BlueWest.Data.Auth.Context.Users; /// /// /// -public class RegisterViewModel +public class RegisterRequest { /// /// Email diff --git a/BlueWest.Data.Auth/Session/SessionConstants.cs b/BlueWest.Data.Auth/Session/SessionConstants.cs index 16fa5ef..97cd2e7 100644 --- a/BlueWest.Data.Auth/Session/SessionConstants.cs +++ b/BlueWest.Data.Auth/Session/SessionConstants.cs @@ -5,10 +5,17 @@ namespace BlueWest.Data.Auth public static class SessionConstants { + /// + /// Max age for the Session + /// public static TimeSpan DefaultSessionMaxAge = TimeSpan.FromHours(24); + /// + /// API User policy Key + /// public const string ApiNamePolicy = "ApiUser"; public const string SessionTokenHeaderName = "x-bw2-auth"; - public const string CookieDomain = "http://localhost:5173"; + public const string CookieDomain = "https://localhost:7022"; + } } diff --git a/BlueWest.Data.Auth/Users/Auth/AuthManager.cs b/BlueWest.Data.Auth/Users/Auth/AuthManager.cs index 7cf8669..79632cf 100644 --- a/BlueWest.Data.Auth/Users/Auth/AuthManager.cs +++ b/BlueWest.Data.Auth/Users/Auth/AuthManager.cs @@ -3,12 +3,16 @@ using System.Security.Claims; using BlueWest.Cryptography; using BlueWest.Data.Application; using BlueWest.Data.Application.Users; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Identity; using static BlueWest.Data.Auth.Context.Users.AuthConsts; namespace BlueWest.Data.Auth.Context.Users { + /// + /// Authentication Manager for the Application Users + /// public class AuthManager : IAuthManager { private readonly ApplicationUserManager _userManager; @@ -48,7 +52,7 @@ namespace BlueWest.Data.Auth.Context.Users return _hasher.CreateHash(uuid, BaseCryptoItem.HashAlgorithm.SHA2_512); } - private SessionToken GetNewSessionToken(LoginRequest loginRequest, ApplicationUser user, string token) + private SessionToken GetNewSessionToken(LoginRequest loginRequest, ApplicationUser user) { long timeNow = DateTimeOffset.Now.ToUnixTimeMilliseconds(); @@ -58,8 +62,7 @@ namespace BlueWest.Data.Auth.Context.Users UserId = user.Id, CreatedDate = timeNow, IsValid = true, - ValidFor = SessionConstants.DefaultSessionMaxAge.Milliseconds, - AccessToken = token + ValidFor = SessionConstants.DefaultSessionMaxAge.Milliseconds }; return newToken; @@ -77,7 +80,7 @@ namespace BlueWest.Data.Auth.Context.Users return token.IsValid; } - public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest) + public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest, string authenticationType = JwtBearerDefaults.AuthenticationScheme) { var user = await _userManager.FindByEmailAsync(loginRequest.Email); @@ -85,24 +88,55 @@ namespace BlueWest.Data.Auth.Context.Users if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken; - var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme); + var identity = new ClaimsIdentity(authenticationType); identity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); + identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber)); + identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); + var sessionToken = await GetSessionToken(loginRequest); if (sessionToken == null || !SessionTokenIsValid(sessionToken)) { var (success, bearerToken) = await GenerateBearerToken(identity, user); - var newSessionToken = GetNewSessionToken(loginRequest, user, bearerToken); + var newSessionToken = GetNewSessionToken(loginRequest, user); await _sessionCache.AddSessionToken(newSessionToken); var tokenUnique = new SessionTokenUnique(newSessionToken); - return OkAuth(tokenUnique, identity, success); } var response = new SessionTokenUnique(sessionToken); return OkAuth(response, identity); } + + public async Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequestViaCookie(LoginRequest loginRequest, string authenticationType = CookieAuthenticationDefaults.AuthenticationScheme) + { + var user = await _userManager.FindByEmailAsync(loginRequest.Email); + + if (user == null) return NegativeToken; + + if (!await _userManager.CheckPasswordAsync(user, loginRequest.Password)) return NegativeToken; + + var identity = new ClaimsIdentity(authenticationType); + identity.AddClaim(new Claim(ClaimTypes.Email, user.Email)); + identity.AddClaim(new Claim(ClaimTypes.MobilePhone, user.PhoneNumber)); + identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); + + + var sessionToken = await GetSessionToken(loginRequest); + + if (sessionToken == null || !SessionTokenIsValid(sessionToken)) + { + var newSessionToken = GetNewSessionToken(loginRequest, user); + await _sessionCache.AddSessionToken(newSessionToken); + var tokenUnique = new SessionTokenUnique(newSessionToken); + return OkAuth(tokenUnique, identity); + } + + var response = new SessionTokenUnique(sessionToken); + return OkAuth(response, identity); + } + private async Task<(bool, string)> GenerateBearerToken(ClaimsIdentity identity, ApplicationUser user) { @@ -113,6 +147,12 @@ namespace BlueWest.Data.Auth.Context.Users } + /// + /// Verify Password + /// + /// + /// + /// public async Task VerifyLoginByEmailAsync(string email, string password) { var user = await _userManager.FindByEmailAsync(email); @@ -120,7 +160,12 @@ namespace BlueWest.Data.Auth.Context.Users } - public async Task CreateUserAsync(RegisterViewModel userSignupDto) + /// + /// Create user + /// + /// + /// + public async Task CreateUserAsync(RegisterRequest userSignupDto) { userSignupDto.Password = _hasher.CreateHash(userSignupDto.Password, BaseCryptoItem.HashAlgorithm.SHA3_512);; var newUser = userSignupDto.ToUser(); diff --git a/BlueWest.Data.Auth/Users/Auth/IAuthManager.cs b/BlueWest.Data.Auth/Users/Auth/IAuthManager.cs index 7743f93..f63b38f 100644 --- a/BlueWest.Data.Auth/Users/Auth/IAuthManager.cs +++ b/BlueWest.Data.Auth/Users/Auth/IAuthManager.cs @@ -14,16 +14,26 @@ public interface IAuthManager /// /// CreateUserAsync /// - /// + /// /// - Task CreateUserAsync(RegisterViewModel registerViewModel); + Task CreateUserAsync(RegisterRequest registerRequest); /// /// Does Login /// /// /// - public Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest); + public Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequest(LoginRequest loginRequest, string authenticationType); + + + /// + /// Does Login + /// + /// + /// + public Task<(bool, SessionTokenUnique, ClaimsIdentity)> GetSessionTokenIdByLoginRequestViaCookie(LoginRequest loginRequest, string authenticationType); + + } \ No newline at end of file diff --git a/BlueWest.Data.Auth/Users/IUserManager.cs b/BlueWest.Data.Auth/Users/IUserManager.cs index 981eccc..598f996 100644 --- a/BlueWest.Data.Auth/Users/IUserManager.cs +++ b/BlueWest.Data.Auth/Users/IUserManager.cs @@ -1,4 +1,5 @@ +using System.Security.Claims; using BlueWest.Data.Application.Users; using Microsoft.AspNetCore.Identity; @@ -6,6 +7,12 @@ namespace BlueWest.Data.Auth.Context.Users { public interface IUserManager { + /// + /// + /// + /// + /// + Task GetUserAsync(ClaimsPrincipal principal); /// /// Create user. /// @@ -28,8 +35,8 @@ namespace BlueWest.Data.Auth.Context.Users /// Task FindByEmailAsync(string email); - - + string GetUserId(ClaimsPrincipal principal); + } } diff --git a/BlueWest.Data.Auth/appsettings.json b/BlueWest.Data.Auth/appsettings.json new file mode 100644 index 0000000..0a4a6fc --- /dev/null +++ b/BlueWest.Data.Auth/appsettings.json @@ -0,0 +1,24 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStringDocker": { + "MySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;", + "Redis": "redis://redisinstance:6379" + }, + "ConnectionStringNoDocker": { + "MySQL": "server=localhost;user=blueuser;password=dXjw127124dJ;database=bluedb;", + "Redis": "redis://localhost:6379" + }, + "AuthSettings": { + "SecretKey": "iJWHDmHLpUA283sqsfhqGbMRdRj1PVkH" + }, + "JwtIssuerOptions": { + "Issuer": "SomeIssuer", + "Audience": "http://localhost:5000" + } +} diff --git a/BlueWest.Razor.Library/BlueWest.Razor.Library.csproj b/BlueWest.Razor.Library/BlueWest.Razor.Library.csproj deleted file mode 100644 index 66942bc..0000000 --- a/BlueWest.Razor.Library/BlueWest.Razor.Library.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net6.0 - enable - enable - - - - - - - - - - - - diff --git a/BlueWest.Razor.Library/Component1.razor b/BlueWest.Razor.Library/Component1.razor deleted file mode 100644 index 51d3876..0000000 --- a/BlueWest.Razor.Library/Component1.razor +++ /dev/null @@ -1,3 +0,0 @@ -
- This component is defined in the BlueWest.Razor.Library library. -
\ No newline at end of file diff --git a/BlueWest.Razor.Library/Component1.razor.css b/BlueWest.Razor.Library/Component1.razor.css deleted file mode 100644 index c6afca4..0000000 --- a/BlueWest.Razor.Library/Component1.razor.css +++ /dev/null @@ -1,6 +0,0 @@ -.my-component { - border: 2px dashed red; - padding: 1em; - margin: 1em 0; - background-image: url('background.png'); -} diff --git a/BlueWest.Razor.Library/ExampleJsInterop.cs b/BlueWest.Razor.Library/ExampleJsInterop.cs deleted file mode 100644 index d1bac27..0000000 --- a/BlueWest.Razor.Library/ExampleJsInterop.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Microsoft.JSInterop; - -namespace BlueWest.Razor.Library; - -// This class provides an example of how JavaScript functionality can be wrapped -// in a .NET class for easy consumption. The associated JavaScript module is -// loaded on demand when first needed. -// -// This class can be registered as scoped DI service and then injected into Blazor -// components for use. - -public class ExampleJsInterop : IAsyncDisposable -{ - private readonly Lazy> moduleTask; - - public ExampleJsInterop(IJSRuntime jsRuntime) - { - moduleTask = new(() => jsRuntime.InvokeAsync( - "import", "./_content/BlueWest.Razor.Library/exampleJsInterop.js").AsTask()); - } - - public async ValueTask Prompt(string message) - { - var module = await moduleTask.Value; - return await module.InvokeAsync("showPrompt", message); - } - - public async ValueTask DisposeAsync() - { - if (moduleTask.IsValueCreated) - { - var module = await moduleTask.Value; - await module.DisposeAsync(); - } - } -} \ No newline at end of file diff --git a/BlueWest.Razor.Library/_Imports.razor b/BlueWest.Razor.Library/_Imports.razor deleted file mode 100644 index c3615ef..0000000 --- a/BlueWest.Razor.Library/_Imports.razor +++ /dev/null @@ -1 +0,0 @@ -@using Microsoft.AspNetCore.Components.Web \ No newline at end of file diff --git a/BlueWest.Razor.Library/wwwroot/background.png b/BlueWest.Razor.Library/wwwroot/background.png deleted file mode 100644 index e15a3bd..0000000 Binary files a/BlueWest.Razor.Library/wwwroot/background.png and /dev/null differ diff --git a/BlueWest.Razor.Library/wwwroot/exampleJsInterop.js b/BlueWest.Razor.Library/wwwroot/exampleJsInterop.js deleted file mode 100644 index ea8d76a..0000000 --- a/BlueWest.Razor.Library/wwwroot/exampleJsInterop.js +++ /dev/null @@ -1,6 +0,0 @@ -// This is a JavaScript module that is loaded on demand. It can export any number of -// functions, and may import other JavaScript modules if required. - -export function showPrompt(message) { - return prompt(message, 'Type anything here'); -} diff --git a/BlueWest.Views/BlueWest.Views.csproj b/BlueWest.Views/BlueWest.Views.csproj index e4a465c..fbbb546 100644 --- a/BlueWest.Views/BlueWest.Views.csproj +++ b/BlueWest.Views/BlueWest.Views.csproj @@ -11,8 +11,11 @@ - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + @@ -81,7 +84,9 @@ - + + + @@ -90,6 +95,12 @@ PreserveNewest PreserveNewest + + + Always + + + @@ -99,7 +110,7 @@ - + diff --git a/BlueWest.Views/Controllers/AccountController.cs b/BlueWest.Views/Controllers/AccountController.cs new file mode 100644 index 0000000..8e3cf97 --- /dev/null +++ b/BlueWest.Views/Controllers/AccountController.cs @@ -0,0 +1,64 @@ +using System.Diagnostics; +using System.Web.Mvc; +using BlueWest.Data.Auth.Context.Users; +using Microsoft.AspNetCore.Mvc; +using BlueWest.Views.Models; +using BlueWest.Views.Utils; +using Controller = Microsoft.AspNetCore.Mvc.Controller; + +namespace BlueWest.Views.Controllers; + +public class AccountController : UserController +{ + private readonly ILogger _logger; + + + public AccountController(ApplicationUserManager userManager, ILogger logger) : base(userManager, logger) + { + _userManager = userManager; + _logger = logger; + } + public async Task Index() + { + await OnEveryAction(); + var user = await GetLoggedInUser(); + return View(user); + } + + public override void OnInitialization() + { + SetFooterMenu(LayoutCache.AccountRouteRecord.Children); + } + + + + public async Task Curriculums() + { + await OnEveryAction(); + + return View("Curriculums/Index"); + } + + + public async Task Change() + { + await OnEveryAction(); + return View("ChangePassword"); + } + + + [Microsoft.AspNetCore.Mvc.Route("[controller]/upload")] + public async Task UploadCurriculum() + { + await OnEveryAction(); + return View("Curriculums/Upload"); + } + + + [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] + public async Task Error() + { + return View(new ErrorViewModel {RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier}); + } + +} \ No newline at end of file diff --git a/BlueWest.Views/Controllers/AuthController.cs b/BlueWest.Views/Controllers/AuthController.cs index 4bc4d27..a7a8006 100644 --- a/BlueWest.Views/Controllers/AuthController.cs +++ b/BlueWest.Views/Controllers/AuthController.cs @@ -1,18 +1,96 @@ -using BlueWest.Views.Utils; +using System.Security.Claims; +using BlueWest.Data.Auth; +using BlueWest.Data.Auth.Context.Users; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Controller = Microsoft.AspNetCore.Mvc.Controller; namespace BlueWest.Views.Controllers { - [System.Web.Mvc.Route("/login")] - - public class AuthController : Controller + public class AuthController : UserController { - + + private readonly IAuthManager _authManager; + + public AuthController(ApplicationUserManager userManager, ILogger logger, IAuthManager authManager) : base(userManager, logger) + { + _userManager = userManager; + _logger = logger; + _authManager = authManager; + } + public IActionResult Index() + { + OnEveryAction(); + return View(); + } + + [AllowAnonymous] + [Microsoft.AspNetCore.Mvc.ActionName("LoginAction")] + public async Task LoginAction(LoginRequest loginRequest) + { + var (success, sessionToken, identity) = + await _authManager.GetSessionTokenIdByLoginRequestViaCookie(loginRequest, + CookieAuthenticationDefaults.AuthenticationScheme); + + + if (!success) return Redirect(AuthLoginRoute); + + if (success) + { + await HttpContext.SignInAsync( + CookieAuthenticationDefaults.AuthenticationScheme, + new ClaimsPrincipal(identity), + new AuthenticationProperties + { + IsPersistent = true, + ExpiresUtc = DateTime.UtcNow.Add(SessionConstants.DefaultSessionMaxAge) + }); + + HttpContext.Session.SetString("hello", "world"); + + return Redirect(RootLocation); + } + + return Redirect(RootLocation); + } + + public IActionResult Login() { this.HandleGlobalization(); return View(); } - } -} + + + public async Task Logout() + { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + return Redirect("/"); + } + + + public async Task Signup() + { + await OnEveryAction(); + return View(); + } + + + [Microsoft.AspNetCore.Mvc.ActionName("SignupAction")] + public async Task SignupAction(RegisterRequest registerRequest) + { + var result = await _authManager.CreateUserAsync(registerRequest); + + if (result.Succeeded) + { + return RedirectToAction("Login"); + } + + return RedirectToAction("Signup"); + } + + } +} \ No newline at end of file diff --git a/BlueWest.Views/Controllers/Data/DataController.cs b/BlueWest.Views/Controllers/Data/DataController.cs index b1b2cc3..ea0f7f1 100644 --- a/BlueWest.Views/Controllers/Data/DataController.cs +++ b/BlueWest.Views/Controllers/Data/DataController.cs @@ -1,17 +1,66 @@ +using System.Web.Mvc; +using BlueWest.Data.Auth.Context.Users; using BlueWest.Views.Utils; +using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Mvc; +using Controller = Microsoft.AspNetCore.Mvc.Controller; +using Microsoft.AspNetCore.Http; namespace BlueWest.Views.Controllers { - - public class DataController : Controller + [Authorize] + + public class DataController : UserController { - public IActionResult Index() + + public DataController(ApplicationUserManager userManager, ILogger logger) : base(userManager, + logger) { - this.HandleGlobalization(); - ViewData[FooterMenuId] = LayoutCache.DataRoute.Children; + _userManager = userManager; + _logger = logger; + } + + public async Task Index() + { + await OnEveryAction(); return View(); } + [ChildActionOnly] + public async Task Countries() + { + await OnEveryAction(); + return View("Countries/Index"); + } + + [ChildActionOnly] + + public async Task Companies() + { + await OnEveryAction(); + return View("Companies/Index"); + } + + [ChildActionOnly] + + public async Task Banks() + { + await OnEveryAction(); + return View("Companies/Index"); + } + + [ChildActionOnly] + + public async Task Currencies() + { + await OnEveryAction(); + return View("Currencies/Index"); + } + + public override void OnInitialization() + { + SetFooterMenu(LayoutCache.DataRouteRecord.Children); + } } + } diff --git a/BlueWest.Views/Controllers/HomeController.cs b/BlueWest.Views/Controllers/HomeController.cs index 6c626bb..6abfcdb 100644 --- a/BlueWest.Views/Controllers/HomeController.cs +++ b/BlueWest.Views/Controllers/HomeController.cs @@ -1,24 +1,38 @@ -using Microsoft.AspNetCore.Mvc; +using BlueWest.Data.Auth.Context.Users; +using Microsoft.AspNetCore.Mvc; using BlueWest.Views.Utils; +using Duende.IdentityServer.Extensions; +using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Controller = Microsoft.AspNetCore.Mvc.Controller; namespace BlueWest.Views.Controllers; [System.Web.Mvc.Route("/")] -public class HomeController : Controller +[System.Web.Mvc.Authorize] +public class HomeController : UserController { - private readonly ILogger _logger; - - public HomeController(ILogger logger, IOptions options) + public HomeController(ApplicationUserManager userManager, ILogger logger) : base(userManager, logger) { + _userManager = userManager; _logger = logger; } - public IActionResult Index() + + [AllowAnonymous] + public async Task Index() { - this.HandleGlobalization(); + await OnEveryAction(); + + if (!User.IsAuthenticated()) + { + return Redirect("/auth/login"); + } + + return View(); } + + } \ No newline at end of file diff --git a/BlueWest.Views/Controllers/JobsController.cs b/BlueWest.Views/Controllers/JobsController.cs deleted file mode 100644 index f9fae66..0000000 --- a/BlueWest.Views/Controllers/JobsController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Diagnostics; -using System.Web.Mvc; -using Microsoft.AspNetCore.Mvc; -using BlueWest.Views.Models; -using BlueWest.Views.Utils; -using Controller = Microsoft.AspNetCore.Mvc.Controller; - -namespace BlueWest.Views.Controllers; - -public class JobsController : Controller -{ - private readonly ILogger _logger; - - public JobsController(ILogger logger) - { - _logger = logger; - } - - public IActionResult Index() - { - this.HandleGlobalization(); - ViewData["Title"] = "Home Page"; - - return View(); - } - - - [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] - public IActionResult Error() - { - return View(new ErrorViewModel {RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier}); - } -} \ No newline at end of file diff --git a/BlueWest.Views/Controllers/System/SystemController.cs b/BlueWest.Views/Controllers/System/SystemController.cs index 78dfafa..c055268 100644 --- a/BlueWest.Views/Controllers/System/SystemController.cs +++ b/BlueWest.Views/Controllers/System/SystemController.cs @@ -1,29 +1,49 @@ +using BlueWest.Data.Auth.Context.Users; using BlueWest.Views.Utils; using Microsoft.AspNetCore.Mvc; namespace BlueWest.Views.Controllers { - public class SystemController : Controller + public class SystemController : UserController { - private readonly ILogger _logger; - - public SystemController(ILogger logger) + public SystemController(ApplicationUserManager userManager, ILogger logger) : base(userManager, logger) { _logger = logger; + _userManager = userManager; } - - public IActionResult Index() + public async Task Index() { - this.HandleGlobalization(); - ViewData[FooterMenuId] = LayoutCache.SystemRoute.Children; + + await OnEveryAction(); + return View(); + } + + public override void OnInitialization() + { + SetFooterMenu(LayoutCache.SystemRoute.Children); + } + + public async Task Users() + { + await OnEveryAction(); return View(); } - public IActionResult Users() + public async Task Logs() { + await OnEveryAction(); return View(); } + + public async Task Roles() + { + await OnEveryAction(); + return View("Roles/Index"); + } + + + } } diff --git a/BlueWest.Views/Controllers/UserController.cs b/BlueWest.Views/Controllers/UserController.cs new file mode 100644 index 0000000..b5bdcb6 --- /dev/null +++ b/BlueWest.Views/Controllers/UserController.cs @@ -0,0 +1,112 @@ +using System.Net; +using System.Net.Sockets; +using BlueWest.Data.Application.Users; +using BlueWest.Data.Auth.Context.Users; +using BlueWest.Views.Models; +using BlueWest.Views.Utils; +using Duende.IdentityServer.Extensions; +using Microsoft.AspNetCore.Localization; +using Microsoft.AspNetCore.Mvc; + +namespace BlueWest.Views.Controllers; + +public class UserController : Controller +{ + protected ILogger _logger; + protected ApplicationUserManager _userManager; + + private List _footerMenu; + + public UserController(ApplicationUserManager userManager, ILogger logger) + { + _logger = logger; + _userManager = userManager; + _footerMenu = new List(); + } + + public async Task OnEveryAction() + { + HandleGlobalization(); + SetFooterMenuViewData(); + await SetUserProfileViewData(); + OnInitialization(); + SetFooterMenuViewData(); + } + + public virtual void OnInitialization() + { + } + + protected void SetFooterMenuViewData() + { + ViewData[FooterMenuViewDataId] = _footerMenu; + } + + public void SetFooterMenu(List routeRecords) + { + _footerMenu = routeRecords; + } + + public async Task SetUserProfileViewData() + { + if (!ViewData.ContainsKey(UserViewDataId)) + { + ViewData[UserViewDataId] = await GetLoggedInUser(); + } + } + + public async Task GetLoggedInUser() + { + if (User.IsAuthenticated()) + { + ApplicationUser? user = await _userManager.GetUserAsync(User); + return new ApplicationUserUnique(user); + } + + return null; + } + + + public IpInformation ExtractIpInformation(IPAddress? ipAddress) + { + string ipAddressString = ""; + IpType ipType = IpType.Unknown; + + if (ipAddress != null) + { + if (ipAddress.AddressFamily == AddressFamily.InterNetwork) + { + ipType = IpType.Ipv4; + ipAddressString = ipAddress.MapToIPv4().ToString(); + } + + if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) + { + ipType = IpType.Ipv6; + ipAddressString = ipAddress + .MapToIPv6() + .ToString(); + } + } + + + return new IpInformation(ipType, ipAddressString); + } + + public void HandleGlobalization() + { + var requestCultureFeature = HttpContext.Features.Get(); + string currentCultureName = DefaultCultureName; + if (requestCultureFeature != null) + { + currentCultureName = requestCultureFeature.RequestCulture.Culture.Name; + } + + ViewData[LanguageViewStorage] = currentCultureName; + IPAddress? remoteIpAddress = Request.HttpContext.Connection.RemoteIpAddress; + IpInformation ipInformation = ExtractIpInformation(Request.HttpContext.Connection.RemoteIpAddress); + + + ViewData[IpViewStorage] = ipInformation; + } +} \ No newline at end of file diff --git a/BlueWest.Views/Languages/SiteContent.cs b/BlueWest.Views/Languages/SiteContent.cs new file mode 100644 index 0000000..379aec9 --- /dev/null +++ b/BlueWest.Views/Languages/SiteContent.cs @@ -0,0 +1,138 @@ +namespace BlueWest.Views.Languages; + +public static class SiteContent +{ + internal static readonly Dictionary> RouteTitle = + new Dictionary> + { + { + RootKeyName, new Dictionary() + { + {"pt", "Inicio"}, + {"eng", "Home"}, + {"en-gb", "Home"} + } + }, + { + SystemKeyName, new Dictionary() + { + {"pt", "Sistema"}, + {"eng", "System"}, + {"en-gb", "System"}, + } + }, + { + DataKeyName, new Dictionary() + { + {"pt", "Dados"}, + {"eng", "Data"}, + {"en-gb", "Data"} + } + }, + + { + RolesKeyName, new Dictionary() + { + {"pt", "Tipos de Utilizador"}, + {"en-gb", "Roles"}, + {"eng", "Roles"} + } + }, + { + ApplicationUsersKeyName, new Dictionary() + { + {"pt", "Utilizadores da Aplicação"}, + {"en-gb", "Users"}, + {"eng", "Users"} + } + }, + { + LogsKeyName, new Dictionary() + { + {"pt", "Logs"}, + {"en-gb", "logs"}, + {"eng", "logs"} + } + }, + { + SettingsKeyName, new Dictionary() + { + {"pt", "Personalização"}, + {"eng", "Settings"}, + {"en-gb", "Settings"}, + } + }, + { + CompaniesKeyName, new Dictionary() + { + {"pt", "Empresas"}, + {"eng", "Companies"}, + {"en-gb", "Companies"}, + } + }, + + { + IndustriesKeyName, new Dictionary() + { + {"pt", "Indústrias"}, + {"en-gb", "Industries"}, + {"eng", "Industries"}, + } + }, + + { + CurrenciesKeyName, new Dictionary() + { + {"pt", "Moedas"}, + {"en-gb", "Currencies"}, + {"eng", "Currencies"}, + } + }, + { + CountriesKeyName, new Dictionary() + { + {"pt", "Países"}, + {"eng", "Countries"}, + {"en-gb", "Countries"} + } + }, + + { + BanksKeyName, new Dictionary() + { + {"pt", "Bancos"}, + {"eng", "Banks"}, + {"en-gb", "Banks"}, + } + }, + + + { + DataUsersKeyName, new Dictionary() + { + {"pt", "Utilizadores"}, + {"eng", "Users"}, + {"en-gb", "Users"}, + } + }, + + { + AccountKeyName, new Dictionary() + { + {"pt", "Perfil"}, + {"eng", "Account"}, + {"en-gb", "Account"}, + } + }, + + { + ChangePasswordKeyName, new Dictionary() + { + {"pt", "Alterar Senha"}, + {"eng", "Change Password"}, + {"en-gb", "Change Password"}, + } + }, + + }; +} \ No newline at end of file diff --git a/BlueWest.Views/Models/IpInformation.cs b/BlueWest.Views/Models/IpInformation.cs new file mode 100644 index 0000000..318f009 --- /dev/null +++ b/BlueWest.Views/Models/IpInformation.cs @@ -0,0 +1,7 @@ +namespace BlueWest.Views.Models; + +public record IpInformation +( + IpType IpType, + string Address +); diff --git a/BlueWest.Views/Models/IpType.cs b/BlueWest.Views/Models/IpType.cs new file mode 100644 index 0000000..e1adec7 --- /dev/null +++ b/BlueWest.Views/Models/IpType.cs @@ -0,0 +1,6 @@ +namespace BlueWest.Views.Models; +public enum IpType +{ + Ipv6, Ipv4, Unknown +} + diff --git a/BlueWest.Views/Program.cs b/BlueWest.Views/Program.cs index d32f983..183c582 100644 --- a/BlueWest.Views/Program.cs +++ b/BlueWest.Views/Program.cs @@ -24,7 +24,7 @@ namespace BlueWest.WebApi MainHost = CreateHostBuilder(args) .UseContentRoot(Directory.GetCurrentDirectory()) .Build(); - + MainHost.Run(); diff --git a/BlueWest.Views/Properties/launchSettings.json b/BlueWest.Views/Properties/launchSettings.json index de6123d..4dccadf 100644 --- a/BlueWest.Views/Properties/launchSettings.json +++ b/BlueWest.Views/Properties/launchSettings.json @@ -11,7 +11,7 @@ "BlueWest.Views": { "commandName": "Project", "dotnetRunMessages": true, - "launchBrowser": true, + "launchBrowser": false, "applicationUrl": "https://localhost:7022;http://localhost:5204", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/BlueWest.Views/SessionManager.cs b/BlueWest.Views/SessionManager.cs index 532c283..7aa59c2 100644 --- a/BlueWest.Views/SessionManager.cs +++ b/BlueWest.Views/SessionManager.cs @@ -42,7 +42,8 @@ public sealed class SessionManager : ISessionCache /// public async Task GetSessionTokenByIdAsync(string tokenId) { - return await _sessionTokens.Where(x => x.Id == tokenId) + return + await _sessionTokens.Where(x => x.Id == tokenId) .FirstOrDefaultAsync(); } diff --git a/BlueWest.Views/Startup.cs b/BlueWest.Views/Startup.cs index cc3ed93..bc26bc8 100644 --- a/BlueWest.Views/Startup.cs +++ b/BlueWest.Views/Startup.cs @@ -30,10 +30,6 @@ public class Startup services.AddSingleton(); // Add services to the container. - IConfigurationRoot configuration = new ConfigurationBuilder() - .AddJsonFile("config.json") - .Build(); - services.Configure(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. @@ -45,19 +41,12 @@ public class Startup { builder.AddSimpleConsole(); }); - - services.AddSession(options => - { - options.Cookie.Domain = SessionConstants.CookieDomain; - options.Cookie.HttpOnly = true; - }); + services.AddControllersWithViews(x => x.EnableEndpointRouting = false); - services.AddSession(options => options.IdleTimeout = TimeSpan.FromHours(8)); - - - services.AddAuthServerServices(_configuration, _environment, configuration); - services.PrepareMySqlDatabasePool(_configuration, _environment, configuration); + + services.AddAuthServerServices(_configuration, _environment); + services.PrepareMySqlDatabasePool(_configuration, _environment); } @@ -93,6 +82,7 @@ public class Startup app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); + app.UseMvcWithDefaultRoute(); diff --git a/BlueWest.Views/StartupExtensions.cs b/BlueWest.Views/StartupExtensions.cs index 79cbcac..89cb3c5 100644 --- a/BlueWest.Views/StartupExtensions.cs +++ b/BlueWest.Views/StartupExtensions.cs @@ -4,7 +4,7 @@ using BlueWest.Data.Application.Users; using BlueWest.Data.Auth; using BlueWest.Data.Auth.Context.Users; using BlueWest.Domain; -using BlueWest.WebApi.Configuration; +using BlueWest.Views.Utils; using BlueWest.WebApi.Context.Users; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.JwtBearer; @@ -17,142 +17,127 @@ namespace BlueWest.Views; public static class StartupExtensions { - private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) => new (new Version(major, minor, build)); + private static MySqlServerVersion GetMySqlServerVersion(int major, int minor, int build) => + new(new Version(major, minor, build)); - - private static BlueWestConnectionString GetConnectionString(this IConfigurationRoot configurationRoot) + private static string GetConnectionString(this IConfiguration configurationRoot, string db) { - // Docker / No-Docker var startupMode = configurationRoot["mode"]; - - if (startupMode == "docker") + + if (!string.IsNullOrEmpty(startupMode) && startupMode == "docker") { - var config = configurationRoot.Get(); + var config = configurationRoot.GetSection("ConnectionStringDocker")[db]; return config; } else { - var config = configurationRoot.Get(); - return config; + return configurationRoot.GetSection("ConnectionStringNoDocker")[db] ?? string.Empty; } - - return null; } - internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, IConfiguration configuration , IWebHostEnvironment environment, IConfigurationRoot configurationRoot) + + + private static bool IsDockerMode(this IConfiguration config) + { + var startupMode = config["mode"]; + return startupMode == "docker"; + } + + internal static IServiceCollection AddAuthServerServices(this IServiceCollection services, + IConfiguration configuration, IWebHostEnvironment environment) + { + var connectionString = configuration.GetConnectionString("Redis"); + + if (string.IsNullOrEmpty(connectionString)) { + throw new InvalidOperationException("Redis connection string is empty"); + } + + + services.AddSession(options => + { + options.Cookie.Domain = SessionConstants.CookieDomain; + options.Cookie.HttpOnly = true; + options.IdleTimeout = TimeSpan.FromHours(8); + }); - var connectionString = configurationRoot.GetConnectionString(); + services + .AddSingleton(new RedisConnectionProvider(connectionString)) + .AddScoped() + .AddScoped() + .AddHostedService() + .AddSingleton() + .AddScoped() + .AddScoped() + .AddScoped() + .AddScoped(); - if (connectionString == null) + // Database Context and Swagger + + + // Register the ConfigurationBuilder instance of AuthSettings + var authSettings = configuration.GetSection(nameof(AuthSettings)); + services.Configure(authSettings); + var signingKey = new SymmetricSecurityKey + (Encoding.ASCII.GetBytes(authSettings[nameof(AuthSettings.SecretKey)])); + + // jwt wire up + // Get options from app settings + var jwtAppSettingOptions = configuration + .GetSection(nameof(JwtIssuerOptions)); + + // Configure JwtIssuerOptions + services.Configure(options => + { + options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; + options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)]; + options.SigningCredentials = new SigningCredentials + (signingKey, SecurityAlgorithms.HmacSha256); + }); + + var tokenValidationParameters = new TokenValidationParameters + { + ValidateIssuer = true, + ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)], + + ValidateAudience = true, + ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)], + + ValidateIssuerSigningKey = true, + IssuerSigningKey = signingKey, + + RequireExpirationTime = false, + ValidateLifetime = true, + ClockSkew = TimeSpan.Zero + }; + + services.AddAuthentication(options => { - throw new InvalidOperationException("Redis connection string is empty"); - } - - services.AddDistributedRedisCache(options => + options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; + }) + .AddCookie(options => { - options.Configuration = connectionString.Redis; - + options.LoginPath = Routes.AuthLoginRoute; + options.LogoutPath = Routes.AuthLogoutRoute; }); - services - .AddSingleton(new RedisConnectionProvider(connectionString.Redis)) - .AddScoped() - .AddScoped() - .AddHostedService() - .AddSingleton() - .AddScoped() - .AddScoped() - .AddScoped() - .AddScoped(); - - // Database Context and Swagger + // api user claim policy + services.AddAuthorization(options => + { + options.AddPolicy(SessionConstants.ApiNamePolicy, + policy => policy.RequireClaim(Data.Auth.Context.Users.Constants.JwtClaimIdentifiers.Rol, + Data.Auth.Context.Users.Constants.JwtClaims.ApiAccess)); + }); - // Register the ConfigurationBuilder instance of AuthSettings - var authSettings = configuration.GetSection(nameof(AuthSettings)); - services.Configure(authSettings); - var signingKey = new SymmetricSecurityKey - (Encoding.ASCII.GetBytes(authSettings[nameof(AuthSettings.SecretKey)])); - - // jwt wire up - // Get options from app settings - var jwtAppSettingOptions = configuration - .GetSection(nameof(JwtIssuerOptions)); - - // Configure JwtIssuerOptions - services.Configure(options => - { - options.Issuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; - options.Audience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)]; - options.SigningCredentials = new SigningCredentials - (signingKey, SecurityAlgorithms.HmacSha256); - }); - - var tokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)], - - ValidateAudience = true, - ValidAudience = jwtAppSettingOptions[nameof(JwtIssuerOptions.Audience)], - - ValidateIssuerSigningKey = true, - IssuerSigningKey = signingKey, - - RequireExpirationTime = false, - ValidateLifetime = true, - ClockSkew = TimeSpan.Zero - }; - - services.AddAuthentication(options => - { - - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddCookie(options => - { - options.LoginPath = "/"; - options.LogoutPath = "/logout"; - }) - .AddJwtBearer(configureOptions => - { - configureOptions.ClaimsIssuer = jwtAppSettingOptions[nameof(JwtIssuerOptions.Issuer)]; - configureOptions.TokenValidationParameters = tokenValidationParameters; - configureOptions.SaveToken = true; - - configureOptions.Events = new JwtBearerEvents - { - OnAuthenticationFailed = context => - { - if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) - { - context.Response.Headers.Add("Token-Expired", "true"); - } - - return Task.CompletedTask; - }, - }; - }); - - - // api user claim policy - services.AddAuthorization(options => - { - options.AddPolicy(SessionConstants.ApiNamePolicy, - policy => policy.RequireClaim(Data.Auth.Context.Users.Constants.JwtClaimIdentifiers.Rol, - Data.Auth.Context.Users.Constants.JwtClaims.ApiAccess)); - - }); - - // add identity - var identityBuilder = services.AddIdentityCore(o => + // add identity + var identityBuilder = services.AddIdentityCore(o => { o.User.RequireUniqueEmail = true; - + // configure identity options o.Password.RequireDigit = false; o.Password.RequireLowercase = false; @@ -160,87 +145,82 @@ public static class StartupExtensions o.Password.RequireNonAlphanumeric = false; o.Password.RequiredLength = 6; }) - .AddUserManager() - .AddUserStore(); + .AddUserManager() + .AddUserStore(); - identityBuilder = new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services); - identityBuilder - .AddEntityFrameworkStores() - .AddDefaultTokenProviders(); + identityBuilder = + new IdentityBuilder(identityBuilder.UserType, typeof(ApplicationRole), identityBuilder.Services); + identityBuilder + .AddEntityFrameworkStores() + .AddDefaultTokenProviders(); - return services; + return services; + } + + + /// + /// Get MYSQL Connection String + /// + /// + /// + /// + private static DbContextOptionsBuilder GetMySqlSettings( + this DbContextOptionsBuilder optionsBuilder, + IConfiguration configuration, + IWebHostEnvironment environment) + { + var sqlVersion = GetMySqlServerVersion(8, 0, 11); + + // Docker / No-Docker + + + var mySqlConnectionString = configuration.GetConnectionString("MySQL"); + + if (mySqlConnectionString == string.Empty) + { + throw new InvalidOperationException("MySQL Connection string appears to be empty."); } - - /// - /// Get MYSQL Connection String - /// - /// - /// - /// - private static DbContextOptionsBuilder GetMySqlSettings( - this DbContextOptionsBuilder optionsBuilder, - IConfiguration configuration, - IConfigurationRoot configurationRoot, - IWebHostEnvironment environment) - { - var sqlVersion = GetMySqlServerVersion(8, 0, 11); - - // Docker / No-Docker - - string mySqlConnectionString = configurationRoot.GetConnectionString().MySql; - - if (mySqlConnectionString == string.Empty) - { - throw new InvalidOperationException("Fatal error: MySQL Connection string is empty."); - } - + optionsBuilder + .UseMySql( + mySqlConnectionString, + sqlVersion) + .UseMySql(sqlVersion, + builder => { builder.EnableRetryOnFailure(6, TimeSpan.FromSeconds(3), null); }); - optionsBuilder - .UseMySql( - mySqlConnectionString, - sqlVersion) - .UseMySql(sqlVersion, - builder => - { - builder.EnableRetryOnFailure(6, TimeSpan.FromSeconds(3), null); - }); - - // The following three options help with debugging, but should - // be changed or removed for production. - if (environment.IsDevelopment()) - { - optionsBuilder - .LogTo(Console.WriteLine, LogLevel.Information) - .EnableSensitiveDataLogging() - .EnableDetailedErrors(); - } - - return optionsBuilder; - } - - /// - /// Setup database Contexts - /// - /// - /// - /// - /// - public static IServiceCollection PrepareMySqlDatabasePool(this IServiceCollection serviceCollection, - IConfiguration configuration, IWebHostEnvironment environment, IConfigurationRoot configurationRoot) - { - return serviceCollection - .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) - .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) - .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) - .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)) - .AddDbContextPool(options => - options.GetMySqlSettings(configuration, configurationRoot, environment)); - } + // The following three options help with debugging, but should + // be changed or removed for production. + if (environment.IsDevelopment()) + { + optionsBuilder + .LogTo(Console.WriteLine, LogLevel.Information) + .EnableSensitiveDataLogging() + .EnableDetailedErrors(); + } + return optionsBuilder; + } + /// + /// Setup database Contexts + /// + /// + /// + /// + /// + public static IServiceCollection PrepareMySqlDatabasePool(this IServiceCollection serviceCollection, + IConfiguration configuration, IWebHostEnvironment environment) + { + return serviceCollection + .AddDbContextPool(options => + options.GetMySqlSettings(configuration, environment)) + .AddDbContextPool(options => + options.GetMySqlSettings(configuration, environment)) + .AddDbContextPool(options => + options.GetMySqlSettings(configuration, environment)) + .AddDbContextPool(options => + options.GetMySqlSettings(configuration, environment)) + .AddDbContextPool(options => + options.GetMySqlSettings(configuration, environment)); + } } \ No newline at end of file diff --git a/BlueWest.Views/Utils/ControllerExtensions.cs b/BlueWest.Views/Utils/ControllerExtensions.cs deleted file mode 100644 index 7ed48f8..0000000 --- a/BlueWest.Views/Utils/ControllerExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.AspNetCore.Localization; -using Microsoft.AspNetCore.Mvc; - -namespace BlueWest.Views.Utils; - -public static class ControllerExtensions -{ - public static void HandleGlobalization(this Controller controller) - { - var context = controller.HttpContext; - var requestCultureFeature = context.Features.Get(); - var currentCultureName = Routes.DefaultCultureName; - if (requestCultureFeature != null) - { - currentCultureName = requestCultureFeature.RequestCulture.Culture.Name; - } - - controller.ViewData[LanguageViewStorage] = currentCultureName; - } - - public static void HandlePageName(this Controller controller, string location) - { - - } - - -} \ No newline at end of file diff --git a/BlueWest.Views/Utils/DataUtil.cs b/BlueWest.Views/Utils/DataUtil.cs new file mode 100644 index 0000000..56c0097 --- /dev/null +++ b/BlueWest.Views/Utils/DataUtil.cs @@ -0,0 +1,34 @@ +using BlueWest.Data.Application.Users; +using BlueWest.Data.Auth; +using BlueWest.Views.Models; +using Microsoft.AspNetCore.Mvc.ViewFeatures; + +namespace BlueWest.Views.Utils; + +public static class DataUtil +{ + public static ApplicationUserUnique GetUserViewData(this ViewDataDictionary viewData) + { + if (viewData[UserViewDataId] is ApplicationUserUnique user) + { + return user; + } + + return null!; + } + + public static IpInformation GetIpInformation(this ViewDataDictionary viewData) + { + if (viewData[IpViewStorage] is IpInformation ipInformation) + { + return ipInformation; + } + + return null!; + } + + public static string GetRootUrl(this ViewDataDictionary viewData) + { + return SessionConstants.CookieDomain; + } +} \ No newline at end of file diff --git a/BlueWest.Views/Utils/LayoutCache.cs b/BlueWest.Views/Utils/LayoutCache.cs index 32ad35a..8cf0b4b 100644 --- a/BlueWest.Views/Utils/LayoutCache.cs +++ b/BlueWest.Views/Utils/LayoutCache.cs @@ -1,5 +1,7 @@ +using System.Diagnostics; using BlueWest.Views.Controllers; using BlueWest.Views.Controllers.Data; +using BlueWest.Views.Languages; using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace BlueWest.Views.Utils; @@ -8,6 +10,12 @@ internal class LayoutCache { #region Route Tree + private static readonly RouteRecord NonLoggedInRoot = new RouteRecord( + AuthLoginRoute, + AuthLoginKeyName, + nameof(AuthController), new List()); + + private static readonly RouteRecord Root = new RouteRecord( RootKeyName, RootLocation, @@ -82,11 +90,14 @@ internal class LayoutCache ViewType.System ), new RouteRecord( - JobsKeyName, - JobsRouteLocation, - nameof(JobsController), - new List(), - ViewType.Jobs + AccountKeyName, + AccountRouteLocation, + nameof(AccountController), + new List() + { + new RouteRecord(ChangePasswordKeyName, ChangePasswordRouteLocation, nameof(AccountController), new List()) + }, + ViewType.Account ), }, ViewType.Root); @@ -97,14 +108,11 @@ internal class LayoutCache internal static readonly RouteRecord SystemRoute = Root.Children.FirstOrDefault(x => x.ViewType == ViewType.System)!; - internal static readonly RouteRecord DataRoute = + internal static readonly RouteRecord DataRouteRecord = Root.Children.FirstOrDefault(x => x.ViewType == ViewType.Data)!; - internal static readonly RouteRecord JobRoute = - Root.Children.FirstOrDefault(x => x.ViewType == ViewType.Jobs)!; - - internal static readonly RouteRecord ProfileRoute = - Root.Children.FirstOrDefault(x => x.ViewType == ViewType.Profile)!; + internal static readonly RouteRecord AccountRouteRecord = + Root.Children.FirstOrDefault(x => x.ViewType == ViewType.Account)!; #endregion Routing Utils @@ -112,13 +120,13 @@ internal class LayoutCache internal static List GetDefaultFooterMenu(ViewDataDictionary dictionary) { - var location = GetLocation(dictionary); + var location = GetUserLanguage(dictionary); var menu = LayoutCache .Root .Children; - if (dictionary[FooterMenuId] is List footerMenu) + if (dictionary[FooterMenuViewDataId] is List footerMenu) { menu = footerMenu; } @@ -126,12 +134,12 @@ internal class LayoutCache return menu .Select(x => { - if (Translation[x.routeKey].ContainsKey(location)) + if (SiteContent.RouteTitle[x.routeKey].ContainsKey(location)) { - return new RouteView(Translation[x.routeKey][location], + return new RouteView(SiteContent.RouteTitle[x.routeKey][location], location); } - return new RouteView(Translation[x.routeKey][DefaultCultureName], + return new RouteView(SiteContent.RouteTitle[x.routeKey][DefaultCultureName], x.location); }) @@ -140,9 +148,16 @@ internal class LayoutCache } - internal static List GetDefaultHeaderMenu(ViewDataDictionary dictionary) + internal static List GetDefaultHeaderMenu(ViewDataDictionary dictionary, bool userAuthenticated = false) { - var location = GetLocation(dictionary); + if (!userAuthenticated) + { + var menuToShow = new List(); + menuToShow.Add(new RouteView("Blue West", "/")); + return menuToShow; + } + + var location = GetUserLanguage(dictionary); var menu = LayoutCache .Root @@ -156,20 +171,27 @@ internal class LayoutCache return menu .Select(x => { - if (Translation[x.routeKey].ContainsKey(location)) + if (SiteContent.RouteTitle[x.routeKey].ContainsKey(location)) { - return new RouteView(Translation[x.routeKey][location], + return new RouteView(SiteContent.RouteTitle[x.routeKey][location], x.Location); } - return new RouteView(Translation[x.routeKey][DefaultCultureName], + return new RouteView(SiteContent.RouteTitle[x.routeKey][DefaultCultureName], x.location); }) .ToList(); } - - internal static string GetLocation(ViewDataDictionary dictionary) + + + [Conditional("DEBUG")] + internal static void IsDevMode(ref bool isDebug) + { + isDebug = true; + } + + internal static string GetUserLanguage(ViewDataDictionary dictionary) { return (dictionary[LanguageViewStorage] as string)!; } diff --git a/BlueWest.Views/Utils/Routes.cs b/BlueWest.Views/Utils/Routes.cs index 5bcbe8d..211ec24 100644 --- a/BlueWest.Views/Utils/Routes.cs +++ b/BlueWest.Views/Utils/Routes.cs @@ -6,185 +6,87 @@ namespace BlueWest.Views.Utils { public const string DefaultCultureName = "en-gb"; - #region Layout Keys + #region View Data Keys - internal const string FooterMenuId = "m1"; + internal const string FooterMenuViewDataId = "m1"; + internal const string UserViewDataId = "uvd"; internal const string HeaderMenuId = "m2"; - internal const string LanguageViewStorage = "i80"; + internal const string LanguageViewStorage = "i81"; + internal const string IpViewStorage = "ip"; + internal const string AgentViewStorage = "ag2"; - #endregion Layout Keys + + #endregion View Data Keys - #region Route Keys - - internal const string DataKeyName = "data"; + internal const string RootKeyName = "root"; internal const string RootLocation = "/"; - internal const string SystemKeyName = "system"; + + + internal const string RootAuthRoute = "/auth"; + internal const string RootAuthKeyName = "auth"; + + internal const string AuthLoginRoute = $"{RootAuthRoute}/login"; + internal const string AuthLoginKeyName = "login"; + + internal const string AuthSignupRoute = $"{RootAuthRoute}/signup"; + internal const string AuthSignupKeyName = "signup"; + + + internal const string RolesLocation = $"{SystemRouteLocation}/roles"; internal const string RolesKeyName = "roles"; - internal const string CompaniesKeyName = "companies"; - internal const string CountriesKeyName = "countries"; - internal const string CurrenciesKeyName = "currencies"; - internal const string IndustriesKeyName = "industries"; - internal const string DataUsersKeyName = "users"; - internal const string BanksKeyName = "banks"; - internal const string JobsKeyName = "jobs"; - internal const string SettingsKeyName = "settings"; - internal const string LogsKeyName = "logs"; + + internal const string ApplicationUsersLocation = $"{SystemRouteLocation}/users"; internal const string ApplicationUsersKeyName = "app_users"; - #endregion Route Keys - // Translation Database Keys - - #region Routes Data - - // Routes - internal const string RolesLocation = $"{SystemRouteLocation}/roles"; - internal const string ApplicationUsersLocation = $"{SystemRouteLocation}/users"; internal const string LogsLocation = $"{SystemRouteLocation}/logs"; + internal const string LogsKeyName = "logs"; + internal const string SettingsRouteLocation = $"{SystemRouteLocation}/settings"; + internal const string SettingsKeyName = "settings"; + internal const string DataLocation = $"/data"; + internal const string DataKeyName = "data"; - // Banks - - // Data users internal const string DataUsersLocation = "/data/users"; - internal const string JobsRouteLocation = "/jobs"; + internal const string DataUsersKeyName = "users"; + internal const string SystemRouteLocation = $"/system"; + internal const string SystemKeyName = "system"; + + internal const string BanksKeyName = "banks"; internal const string BanksLocation = $"{DataLocation}/banks"; + internal const string CountriesLocation = $"{DataLocation}/countries"; + internal const string CountriesKeyName = "countries"; + internal const string CurrenciesLocation = $"{DataLocation}/currencies"; + internal const string CurrenciesKeyName = "currencies"; - internal const string CompaniesLocation = $"{DataLocation}/companies"; + internal const string IndustriesKeyName = "industries"; internal const string IndustriesLocation = $"{DataLocation}/industries"; + + internal const string CompaniesLocation = $"{DataLocation}/companies"; + internal const string CompaniesKeyName = "companies"; + + // Jobs + internal const string Curriculums = "curriculums"; + internal const string Proposals = "proposals"; + internal const string Offers = "offers"; + internal const string Processes = "processes"; + internal const string AuthLogoutRoute = "/auth/logout"; + + // Account + internal const string AccountRouteLocation = "/account"; + internal const string AccountKeyName = "profile"; + internal const string ChangePasswordKeyName = "changepwd"; + internal const string ChangePasswordRouteLocation = $"{AccountRouteLocation}/change"; - #endregion Routes Data - - internal static Dictionary> Translation = - new Dictionary> - { - { - RootKeyName, new Dictionary() - { - {"pt", "Inicio"}, - {"eng", "Home"}, - {"en-gb", "Home"} - } - }, - { - SystemKeyName, new Dictionary() - { - {"pt", "Sistema"}, - {"eng", "System"}, - {"en-gb", "System"}, - } - }, - { - DataKeyName, new Dictionary() - { - {"pt", "Dados"}, - {"eng", "Data"}, - {"en-gb", "Data"} - } - }, - - { - RolesKeyName, new Dictionary() - { - {"pt", "Tipos de Utilizador"}, - {"en-gb", "Roles"}, - {"eng", "Roles"} - } - }, - { - ApplicationUsersKeyName, new Dictionary() - { - {"pt", "Utilizadores da Aplicação"}, - {"en-gb", "Users"}, - {"eng", "Users"} - } - }, - { - LogsKeyName, new Dictionary() - { - {"pt", "Logs"}, - {"en-gb", "logs"}, - {"eng", "logs"} - } - }, - { - SettingsKeyName, new Dictionary() - { - {"pt", "Personalização"}, - {"eng", "Settings"}, - {"en-gb", "Settings"}, - } - }, - { - CompaniesKeyName, new Dictionary() - { - {"pt", "Empresas"}, - {"eng", "Companies"}, - {"en-gb", "Companies"}, - } - }, - - { - IndustriesKeyName, new Dictionary() - { - {"pt", "Indústrias"}, - {"en-gb", "Industries"}, - {"eng", "Industries"}, - } - }, - - { - CurrenciesKeyName, new Dictionary() - { - {"pt", "Moedas"}, - {"en-gb", "Currencies"}, - {"eng", "Currencies"}, - } - }, - { - CountriesKeyName, new Dictionary() - { - {"pt", "Países"}, - {"eng", "Countries"}, - {"en-gb", "Countries"} - } - }, - - { - BanksKeyName, new Dictionary() - { - {"pt", "Bancos"}, - {"eng", "Banks"}, - {"en-gb", "Banks"}, - } - }, - - - { - DataUsersKeyName, new Dictionary() - { - {"pt", "Utilizadores"}, - {"eng", "Users"}, - {"en-gb", "Users"}, - } - }, - - { - JobsKeyName, new Dictionary() - { - {"pt", "Anúncios de trabalho"}, - {"eng", "Jobs"}, - {"en-gb", "Jobs"}, - } - }, - }; + + } } \ No newline at end of file diff --git a/BlueWest.Views/Utils/ViewType.cs b/BlueWest.Views/Utils/ViewType.cs index 9792d33..41eb16e 100644 --- a/BlueWest.Views/Utils/ViewType.cs +++ b/BlueWest.Views/Utils/ViewType.cs @@ -6,8 +6,7 @@ namespace BlueWest.Views { System, Data, - Jobs, - Profile, + Account, Root, Undefined diff --git a/BlueWest.Views/Views/Account/ChangePassword.cshtml b/BlueWest.Views/Views/Account/ChangePassword.cshtml new file mode 100644 index 0000000..f445275 --- /dev/null +++ b/BlueWest.Views/Views/Account/ChangePassword.cshtml @@ -0,0 +1,111 @@ +@using BlueWest.Views.Utils +@model BlueWest.Data.Application.Users.ApplicationUserUnique +@{ + var user = @Model; +} + +
+
+ + + + + + +
+ + +
+
+
+ + +@await Html.PartialAsync("_FooterMenu") \ No newline at end of file diff --git a/BlueWest.Views/Views/Account/Curriculums/Index.cshtml b/BlueWest.Views/Views/Account/Curriculums/Index.cshtml new file mode 100644 index 0000000..ab78453 --- /dev/null +++ b/BlueWest.Views/Views/Account/Curriculums/Index.cshtml @@ -0,0 +1,10 @@ +@{ + ViewData["Title"] = "Home Page"; +} + +
+

Curriculums Module

+
+ + +@Html.Partial("_FooterMenu"); \ No newline at end of file diff --git a/BlueWest.Views/Views/Account/Curriculums/Upload.cshtml b/BlueWest.Views/Views/Account/Curriculums/Upload.cshtml new file mode 100644 index 0000000..e69de29 diff --git a/BlueWest.Views/Views/Account/Index.cshtml b/BlueWest.Views/Views/Account/Index.cshtml new file mode 100644 index 0000000..f445275 --- /dev/null +++ b/BlueWest.Views/Views/Account/Index.cshtml @@ -0,0 +1,111 @@ +@using BlueWest.Views.Utils +@model BlueWest.Data.Application.Users.ApplicationUserUnique +@{ + var user = @Model; +} + +
+
+ + + + + + +
+ + +
+
+
+ + +@await Html.PartialAsync("_FooterMenu") \ No newline at end of file diff --git a/BlueWest.Views/Views/Auth/Index.cshtml b/BlueWest.Views/Views/Auth/Index.cshtml index 1ef105b..7bdba35 100644 --- a/BlueWest.Views/Views/Auth/Index.cshtml +++ b/BlueWest.Views/Views/Auth/Index.cshtml @@ -2,5 +2,4 @@ @using (Html.BeginForm()){ @Html.LabelFor(x => x.Password, "Password") @Html.PasswordFor(x => x.Password); - @Html.NameFor(x => x.Email); } \ No newline at end of file diff --git a/BlueWest.Views/Views/Auth/Login.cshtml b/BlueWest.Views/Views/Auth/Login.cshtml new file mode 100644 index 0000000..538fa55 --- /dev/null +++ b/BlueWest.Views/Views/Auth/Login.cshtml @@ -0,0 +1,68 @@ +
+
+
+
+
+ +
/
+
+ Login +
+
+
+
+
+
+
+
+ + +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/BlueWest.Views/Views/Auth/Signup.cshtml b/BlueWest.Views/Views/Auth/Signup.cshtml new file mode 100644 index 0000000..88ad010 --- /dev/null +++ b/BlueWest.Views/Views/Auth/Signup.cshtml @@ -0,0 +1,117 @@ +
+
+
+
+
+ +
/
+
+ Login +
+
+
+
+
+
+
+
+ + + + + + + + + +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/BlueWest.Views/Views/Data/Banks/Index.cshtml b/BlueWest.Views/Views/Data/Banks/Index.cshtml new file mode 100644 index 0000000..3c450c5 --- /dev/null +++ b/BlueWest.Views/Views/Data/Banks/Index.cshtml @@ -0,0 +1,6 @@ +
+

Banks

+
+ + +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/Data/Companies/Index.cshtml b/BlueWest.Views/Views/Data/Companies/Index.cshtml index 7ab5168..c22fd68 100644 --- a/BlueWest.Views/Views/Data/Companies/Index.cshtml +++ b/BlueWest.Views/Views/Data/Companies/Index.cshtml @@ -1,11 +1,6 @@ -@using BlueWest.Views.Utils -@{ - ViewData["Title"] = "Home Page"; -} -

Companies Module

-@Html.Partial("_FooterMenu"); \ No newline at end of file +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/Data/Countries/Index.cshtml b/BlueWest.Views/Views/Data/Countries/Index.cshtml index 9cadfef..1ab7024 100644 --- a/BlueWest.Views/Views/Data/Countries/Index.cshtml +++ b/BlueWest.Views/Views/Data/Countries/Index.cshtml @@ -1,11 +1,6 @@ -@using BlueWest.Views.Utils -@{ - ViewData["Title"] = "Home Page"; -} -

Data Module

-@Html.Partial("_FooterMenu"); \ No newline at end of file +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/Data/Currencies/Index.cshtml b/BlueWest.Views/Views/Data/Currencies/Index.cshtml new file mode 100644 index 0000000..eccaef4 --- /dev/null +++ b/BlueWest.Views/Views/Data/Currencies/Index.cshtml @@ -0,0 +1,11 @@ +@using BlueWest.Views.Utils +@{ + ViewData["Title"] = "Home Page"; +} + +
+

Currencies Module

+
+ + +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/Data/Index.cshtml b/BlueWest.Views/Views/Data/Index.cshtml index 9cadfef..464cc68 100644 --- a/BlueWest.Views/Views/Data/Index.cshtml +++ b/BlueWest.Views/Views/Data/Index.cshtml @@ -1,11 +1,7 @@ -@using BlueWest.Views.Utils -@{ - ViewData["Title"] = "Home Page"; -}

Data Module

-@Html.Partial("_FooterMenu"); \ No newline at end of file +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/Home/Index.cshtml b/BlueWest.Views/Views/Home/Index.cshtml index 9ff16ec..d8ed2b8 100644 --- a/BlueWest.Views/Views/Home/Index.cshtml +++ b/BlueWest.Views/Views/Home/Index.cshtml @@ -1,14 +1,5 @@ -@using Microsoft.AspNetCore.Localization -@{ - ViewData["Title"] = "Home Page"; - -} - - -
+

Welcome

-

Learn about building Web apps with ASP.NET Core.

- diff --git a/BlueWest.Views/Views/Home/Login.cshtml b/BlueWest.Views/Views/Home/Login.cshtml new file mode 100644 index 0000000..aa356e2 --- /dev/null +++ b/BlueWest.Views/Views/Home/Login.cshtml @@ -0,0 +1,11 @@ +@using BlueWest.Views.Utils +@{ + ViewData["Title"] = "Home Page"; +} + +
+

Login Module

+
+ + +@Html.Partial("_FooterMenu"); \ No newline at end of file diff --git a/BlueWest.Views/Views/Jobs/Index.cshtml b/BlueWest.Views/Views/Jobs/Index.cshtml deleted file mode 100644 index 479cee9..0000000 --- a/BlueWest.Views/Views/Jobs/Index.cshtml +++ /dev/null @@ -1,10 +0,0 @@ -@{ - ViewData["Title"] = "Home Page"; -} - -
-

Jobs Module

-
- - -@Html.Partial("_FooterMenu"); \ No newline at end of file diff --git a/BlueWest.Views/Views/Shared/UsersMenu.cshtml b/BlueWest.Views/Views/Shared/UsersMenu.cshtml deleted file mode 100644 index d223537..0000000 --- a/BlueWest.Views/Views/Shared/UsersMenu.cshtml +++ /dev/null @@ -1,59 +0,0 @@ - \ No newline at end of file diff --git a/BlueWest.Views/Views/Shared/_FooterMenu.cshtml b/BlueWest.Views/Views/Shared/_FooterMenu.cshtml index 38340e1..87efe33 100644 --- a/BlueWest.Views/Views/Shared/_FooterMenu.cshtml +++ b/BlueWest.Views/Views/Shared/_FooterMenu.cshtml @@ -4,28 +4,33 @@ var menu = LayoutCache.GetDefaultFooterMenu(ViewData); } - \ No newline at end of file + +} + diff --git a/BlueWest.Views/Views/Shared/_HeaderMenu.cshtml b/BlueWest.Views/Views/Shared/_HeaderMenu.cshtml index e3da6c8..3e3b69a 100644 --- a/BlueWest.Views/Views/Shared/_HeaderMenu.cshtml +++ b/BlueWest.Views/Views/Shared/_HeaderMenu.cshtml @@ -1,7 +1,13 @@ @using BlueWest.Views.Utils +@using Duende.IdentityServer.Extensions +@using BlueWest.Data.Auth @{ Layout = null; - var menu = LayoutCache.GetDefaultHeaderMenu(ViewData); + var userAuthenticated = User.IsAuthenticated(); + var menu = LayoutCache.GetDefaultHeaderMenu(ViewData, userAuthenticated); + var user = ViewData.GetUserViewData(); + var rootUrl = SessionConstants.CookieDomain; + }
@@ -16,8 +22,21 @@
- } + } + } + @if (userAuthenticated && user != null) + { +
+
+
+
+ +
+
@user.Email +
+
} + \ No newline at end of file diff --git a/BlueWest.Views/Views/Shared/_Layout.cshtml b/BlueWest.Views/Views/Shared/_Layout.cshtml index 11d3916..198e7d6 100644 --- a/BlueWest.Views/Views/Shared/_Layout.cshtml +++ b/BlueWest.Views/Views/Shared/_Layout.cshtml @@ -1,33 +1,36 @@ - +@using BlueWest.Views.Utils +@using BlueWest.Data.Auth +@{ + var applicationUser = ViewData.GetUserViewData(); + var rootUrl = SessionConstants.CookieDomain; +} +@ViewData["Title"] - BlueWest.Views - + @* *@ - - + +
- @RenderBody() -
-
- @await Html.PartialAsync("_HeaderMenu") + @await Html.PartialAsync("_HeaderMenu", applicationUser)
diff --git a/BlueWest.Views/Views/System/Index.cshtml b/BlueWest.Views/Views/System/Index.cshtml index bf4c02d..284927c 100644 --- a/BlueWest.Views/Views/System/Index.cshtml +++ b/BlueWest.Views/Views/System/Index.cshtml @@ -1,8 +1,3 @@ -@using BlueWest.Views.Utils -@{ - ViewData["Title"] = "Home Page"; -} -

System Module

diff --git a/BlueWest.Views/Views/System/Logs.cshtml b/BlueWest.Views/Views/System/Logs.cshtml new file mode 100644 index 0000000..0f36fec --- /dev/null +++ b/BlueWest.Views/Views/System/Logs.cshtml @@ -0,0 +1,5 @@ +
+

Users

+
+ +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/Views/System/Roles/Index.cshtml b/BlueWest.Views/Views/System/Roles/Index.cshtml index e69de29..2288d36 100644 --- a/BlueWest.Views/Views/System/Roles/Index.cshtml +++ b/BlueWest.Views/Views/System/Roles/Index.cshtml @@ -0,0 +1,6 @@ +
+

Roles Module

+
+ + +@await Html.PartialAsync("_FooterMenu"); \ No newline at end of file diff --git a/BlueWest.Views/Views/System/Users.cshtml b/BlueWest.Views/Views/System/Users.cshtml index 3ddff00..dbc9982 100644 --- a/BlueWest.Views/Views/System/Users.cshtml +++ b/BlueWest.Views/Views/System/Users.cshtml @@ -1,10 +1,7 @@ -@{ - ViewData["Title"] = "Home Page"; -} -@Html.Partial("~/Views/Shared/UsersMenu.cshtml"); + +@await Html.PartialAsync("_FooterMenu"); diff --git a/BlueWest.Views/appsettings.json b/BlueWest.Views/appsettings.json index 0a4a6fc..849eca1 100644 --- a/BlueWest.Views/appsettings.json +++ b/BlueWest.Views/appsettings.json @@ -5,14 +5,15 @@ "Microsoft.AspNetCore": "Warning" } }, + "mode": "no-docker", "AllowedHosts": "*", "ConnectionStringDocker": { - "MySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;", - "Redis": "redis://redisinstance:6379" + "Redis": "redis://redisinstance:6379", + "MySQL": "server=db;user=blueuser;password=dXjw127124dJ;database=bluedb;" }, "ConnectionStringNoDocker": { - "MySQL": "server=localhost;user=blueuser;password=dXjw127124dJ;database=bluedb;", - "Redis": "redis://localhost:6379" + "Redis": "redis://localhost:6379", + "MySQL": "server=localhost;user=blueuser;password=dXjw127124dJ;database=bluedb;" }, "AuthSettings": { "SecretKey": "iJWHDmHLpUA283sqsfhqGbMRdRj1PVkH" diff --git a/BlueWest.Views/config.json b/BlueWest.Views/config.json deleted file mode 100644 index 4cf70fd..0000000 --- a/BlueWest.Views/config.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "mode": "no-docker", - "database": "mysql" -} \ No newline at end of file diff --git a/BlueWest.Views/wwwroot/static/profile/boy-avatar.png b/BlueWest.Views/wwwroot/static/profile/boy-avatar.png new file mode 100644 index 0000000..b1711f6 Binary files /dev/null and b/BlueWest.Views/wwwroot/static/profile/boy-avatar.png differ diff --git a/BlueWest.sln b/BlueWest.sln index 3ff5e0b..7b8caff 100644 --- a/BlueWest.sln +++ b/BlueWest.sln @@ -41,8 +41,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Views", "BlueWest. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Domain", "BlueWest.Domain\BlueWest.Domain.csproj", "{1085FF6E-E568-441E-9A2D-23F50AB613AF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Razor.Library", "BlueWest.Razor.Library\BlueWest.Razor.Library.csproj", "{CA6DF60F-B33E-4688-A4ED-4427B446E852}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlueWest.Data.Auth", "BlueWest.Data.Auth\BlueWest.Data.Auth.csproj", "{2998FE17-18AD-4888-A696-7F6340F8A543}" EndProject Global @@ -95,10 +93,6 @@ Global {1085FF6E-E568-441E-9A2D-23F50AB613AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {1085FF6E-E568-441E-9A2D-23F50AB613AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {1085FF6E-E568-441E-9A2D-23F50AB613AF}.Release|Any CPU.Build.0 = Release|Any CPU - {CA6DF60F-B33E-4688-A4ED-4427B446E852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CA6DF60F-B33E-4688-A4ED-4427B446E852}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CA6DF60F-B33E-4688-A4ED-4427B446E852}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CA6DF60F-B33E-4688-A4ED-4427B446E852}.Release|Any CPU.Build.0 = Release|Any CPU {2998FE17-18AD-4888-A696-7F6340F8A543}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2998FE17-18AD-4888-A696-7F6340F8A543}.Debug|Any CPU.Build.0 = Debug|Any CPU {2998FE17-18AD-4888-A696-7F6340F8A543}.Release|Any CPU.ActiveCfg = Release|Any CPU diff --git a/docker-compose.db.only.yml b/docker-compose.db.only.yml index ab740ff..e11e6dd 100644 --- a/docker-compose.db.only.yml +++ b/docker-compose.db.only.yml @@ -4,8 +4,8 @@ services: container_name: BW1_MYSQL image: mysql/mysql-server:8.0 environment: - MYSQL_ROOT_HOST: localhost - MYSQL_USER_HOST: localhost + MYSQL_ROOT_HOST: '172.19.0.1' + MYSQL_USER_HOST: '172.19.0.1' MYSQL_ROOT_PASSWORD: dXjw127124dJ MYSQL_USER: blueuser MYSQL_PASSWORD: dXjw127124dJ @@ -14,14 +14,6 @@ services: - "3306:3306" volumes: - ./docker-entrypoint-initdb.d/:/docker-entrypoint-initdb.d/ - phpmyadmin: - container_name: BW_PHPMYADMIN - image: phpmyadmin/phpmyadmin - ports: - - 80:80 - environment: - MYSQL_USERNAME: 'blueuser' - MYSQL_ROOT_PASSWORD: 'dXjw127124dJ' redis-instance: image: "redislabs/redismod" ports:
Date