diff --git a/TIAMMobileApp/MauiProgram.cs b/TIAMMobileApp/MauiProgram.cs index 6814ad48..ccf085c1 100644 --- a/TIAMMobileApp/MauiProgram.cs +++ b/TIAMMobileApp/MauiProgram.cs @@ -2,6 +2,7 @@ using TIAMMobileApp.Services; using TIAMWebApp.Shared.Application.Interfaces; using DevExpress.Blazor; +using TIAMMobilApp.Services; namespace TIAMMobileApp { @@ -42,7 +43,7 @@ namespace TIAMMobileApp builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); - //builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder.Build(); } diff --git a/TIAMMobileApp/Services/UserDataService.cs b/TIAMMobileApp/Services/UserDataService.cs new file mode 100644 index 00000000..650ed94d --- /dev/null +++ b/TIAMMobileApp/Services/UserDataService.cs @@ -0,0 +1,147 @@ +using Microsoft.EntityFrameworkCore.Infrastructure; +using Newtonsoft.Json; +using System.Net.Http.Json; +using System.Text; +using TIAMWebApp.Shared.Application.Interfaces; +using TIAMWebApp.Shared.Application.Models; +using TIAMWebApp.Shared.Application.Models.PageModels; + + +namespace TIAMMobilApp.Services +{ + public class UserDataService : IUserDataService + { + private readonly HttpClient http; + public User? User { get; set; } = new User("","",""); + public Dictionary userRoleTypes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public UserDataService(HttpClient http) + { + this.http = http; + } + + + public List roleTypes = new List + { + new RoleType { Id = 1, RoleName = "Login" }, + new RoleType { Id = 2, RoleName = "Member" }, + new RoleType { Id = 4, RoleName = "Vip" }, + new RoleType { Id = 8, RoleName = "Uvip" }, + new RoleType { Id = 16, RoleName = "Volunteer" }, + new RoleType { Id = 32, RoleName = "Guide" }, + new RoleType { Id = 64, RoleName = "Protector" }, + new RoleType { Id = 128, RoleName = "Admin" }, + new RoleType { Id = 256, RoleName = "SuperAdmin" }, + new RoleType { Id = 512, RoleName = "God" } + }; + + + public async Task IsLoggedInAsync() + { + if (User == null) + { + User = new User("","",""); + User.IsLoggedIn = false; + User.UserType = UserType.User; + return User; + } + + else + { + return User; + } + + } + + //Mock method for now + public async Task AuthorizeUserAsync(int userType) + { + if (User == null) + { + User = new User("", "", ""); + } + //simply return true for now + User.IsLoggedIn = true; + User.UserType = (UserType)userType; + return User; + } + + public async Task TestUserApi(int Param) { + var url = APIUrls.UserTest; + var response = await http.PostAsJsonAsync(url, Param); + var result = await response.Content.ReadAsStringAsync(); + return result; + } + + public async Task AuthenticateUser(LoginModel loginModel) + { + + + + string result = string.Empty; + var url = APIUrls.AuthenticateUser; + + var response = await http.PostAsJsonAsync(url, loginModel); + + if(response.IsSuccessStatusCode) + { + result = await response.Content.ReadAsStringAsync(); + } + else + { + result = await response.Content.ReadAsStringAsync(); + } + + //result = await response.Content.ReadAsStringAsync(); + return result; + + + } + + public async Task<(bool isSuccess, string ErrorMessage)> CreateUser(RegistrationModel regModel) + { + + bool isSuccess = true; + string result = string.Empty; + var url = APIUrls.CreateUser; + + var response = await http.PostAsJsonAsync(url, regModel); + result = await response.Content.ReadAsStringAsync(); + /*if (response.IsSuccessStatusCode) + { + isSuccess = true; + result = await response.Content.ReadAsStringAsync(); + } + else + { + isSuccess = false; + result = await response.Content.ReadAsStringAsync(); + }*/ + + + return (isSuccess, result); + } + + + public Task> GetUserRolesAsync(User user) + { + + //get the user's roles + int role = User.UserRoles; + + foreach (var roleType in roleTypes) + { + if ((role & roleType.Id) == roleType.Id) + { + + //add the role to the dictionary + userRoleTypes.Add(roleType.Id, roleType.RoleName); + + } + } + return Task.FromResult(userRoleTypes); + + } + } +} + diff --git a/TIAMSharedUI/Pages/Components/LoginStep1.razor b/TIAMSharedUI/Pages/Components/LoginStep1.razor new file mode 100644 index 00000000..9e550886 --- /dev/null +++ b/TIAMSharedUI/Pages/Components/LoginStep1.razor @@ -0,0 +1,63 @@ +@using TIAMWebApp.Shared.Application.Models.PageModels; + + + + +
+ + + + + + + +
+ + + + +
+ + + +@code { + [Parameter] + public LoginModel loginModel { get; set; } + + //[Parameter] + //public string Email { get; set; } + + [Parameter] + public EventCallback onLoginNext { get; set; } + + [Parameter] + public EventCallback LoginModelChanged { get; set; } + + IEnumerable PredefinedPlaceholders { get; set; } = new List() { '_', '#' }; + + string EmailMask { get; set; } = @"(\w|[.-])+@(\w|-)+\.(\w|-){2,4}"; + MaskAutoCompleteMode AutoCompleteMode { get; set; } = MaskAutoCompleteMode.Strong; + char Placeholder { get; set; } = '_'; + bool PlaceholderVisible { get; set; } = false; + + private string spinnerClass = ""; + + private async Task GoToNextStep() + { + spinnerClass = "spinner-border spinner-border-sm"; + await Task.Delay(500); + spinnerClass = ""; + await LoginModelChanged.InvokeAsync(loginModel); + await onLoginNext.InvokeAsync(); + } + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/Components/LoginStep3.razor b/TIAMSharedUI/Pages/Components/LoginStep3.razor new file mode 100644 index 00000000..509f4cd6 --- /dev/null +++ b/TIAMSharedUI/Pages/Components/LoginStep3.razor @@ -0,0 +1,62 @@ +@using TIAMWebApp.Shared.Application.Models.PageModels; +

Step 3: Password

+ + + + + + + +
+ + + + +
+ + + Previous + + +
+ + +@code { + [Parameter] + public LoginModel loginModel { get; set; } + + [Parameter] + public EventCallback LoginModelChanged { get; set; } + + [Parameter] + public EventCallback onPrev { get; set; } + + [Parameter] + public EventCallback onSubmit { get; set; } + + private string spinnerClass = ""; + + public async Task SubmitLogin() + { + + spinnerClass = "spinner-border spinner-border-sm"; + await Task.Delay(500); + spinnerClass = ""; + + await LoginModelChanged.InvokeAsync(loginModel); + await onSubmit.InvokeAsync(); + } + + private async Task GoToPreviousStep() + { + + await onPrev.InvokeAsync(); + } +} + diff --git a/TIAMSharedUI/Pages/Components/Step1.razor b/TIAMSharedUI/Pages/Components/Step1.razor new file mode 100644 index 00000000..063b22aa --- /dev/null +++ b/TIAMSharedUI/Pages/Components/Step1.razor @@ -0,0 +1,63 @@ +@using TIAMWebApp.Shared.Application.Models.PageModels; + + + + +
+ + + + + + + +
+ + + + +
+ + + +@code { + [Parameter] + public RegistrationModel regModel { get; set; } + + //[Parameter] + //public string Email { get; set; } + + [Parameter] + public EventCallback onNext { get; set; } + + [Parameter] + public EventCallback RegModelChanged { get; set; } + + IEnumerable PredefinedPlaceholders { get; set; } = new List() { '_', '#' }; + + string EmailMask { get; set; } = @"(\w|[.-])+@(\w|-)+\.(\w|-){2,4}"; + MaskAutoCompleteMode AutoCompleteMode { get; set; } = MaskAutoCompleteMode.Strong; + char Placeholder { get; set; } = '_'; + bool PlaceholderVisible { get; set; } = false; + + private string spinnerClass = ""; + + private async Task GoToNextStep() + { + spinnerClass = "spinner-border spinner-border-sm"; + await Task.Delay(500); + spinnerClass = ""; + await RegModelChanged.InvokeAsync(regModel); + await onNext.InvokeAsync(); + } + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/Components/Step2.razor b/TIAMSharedUI/Pages/Components/Step2.razor new file mode 100644 index 00000000..36381ffd --- /dev/null +++ b/TIAMSharedUI/Pages/Components/Step2.razor @@ -0,0 +1,68 @@ +@using TIAMWebApp.Shared.Application.Models.PageModels; +

Step 2: Phone Number

+ + + + + + + +
+ + + + + + + + +
+ + + Previous + + +
+ + + +@code { + [Parameter] + public RegistrationModel regModel { get; set; } + + [Parameter] + public EventCallback onNext { get; set; } + + [Parameter] + public EventCallback onPrev { get; set; } + + [Parameter] + public EventCallback RegModelChanged { get; set; } + + char Placeholder = '_'; + + private string spinnerClass = ""; + + private async Task GoToNextStep() + { + spinnerClass = "spinner-border spinner-border-sm"; + await Task.Delay(500); + spinnerClass = ""; + await RegModelChanged.InvokeAsync(regModel); + await onNext.InvokeAsync(); + } + + private async Task GoToPreviousStep() + { + + await onPrev.InvokeAsync(); + } + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/Components/Step3.razor b/TIAMSharedUI/Pages/Components/Step3.razor new file mode 100644 index 00000000..04ea487c --- /dev/null +++ b/TIAMSharedUI/Pages/Components/Step3.razor @@ -0,0 +1,64 @@ +@using TIAMWebApp.Shared.Application.Models.PageModels; +

Step 3: Password

+ + + + + + + +
+ + + + + + +
+ + + Previous + + +
+ + +@code { + [Parameter] + public RegistrationModel regModel { get; set; } + + [Parameter] + public EventCallback RegModelChanged { get; set; } + + [Parameter] + public EventCallback onPrev { get; set; } + + [Parameter] + public EventCallback onSubmit { get; set; } + + private string spinnerClass = ""; + + public async Task SubmitRegistration() + { + + spinnerClass = "spinner-border spinner-border-sm"; + await Task.Delay(500); + spinnerClass = ""; + + await RegModelChanged.InvokeAsync(regModel); + await onSubmit.InvokeAsync(); + } + + private async Task GoToPreviousStep() + { + + await onPrev.InvokeAsync(); + } +} + diff --git a/TIAMSharedUI/Pages/Login.razor b/TIAMSharedUI/Pages/Login.razor index 06efd79b..379ff910 100644 --- a/TIAMSharedUI/Pages/Login.razor +++ b/TIAMSharedUI/Pages/Login.razor @@ -1,6 +1,7 @@ @page "/login" @using TIAMWebApp.Shared.Application.Interfaces; @using TIAMWebApp.Shared.Application.Models; +@using TIAMWebApp.Shared.Application.Models.PageModels; @inject NavigationManager navManager @inject IUserDataService userDataService Login @@ -12,14 +13,19 @@
Tour I Am
-
+ + + +
- + +
- + +
@@ -34,8 +40,10 @@
- Login - + + +
+

@isUserLoggedIn

@CurrentValue

Forget password? or Sign up @@ -43,6 +51,7 @@
@code { + LoginModel loginModel = new(); bool isUserLoggedIn; int CurrentValue = 0; @@ -54,6 +63,11 @@ isUserLoggedIn = user.IsLoggedIn; user.UserType = (UserType)CurrentValue; navManager.NavigateTo("home"); - + + } + + public void Submit() + { + } } diff --git a/TIAMSharedUI/Pages/Login2.razor b/TIAMSharedUI/Pages/Login2.razor new file mode 100644 index 00000000..04aff409 --- /dev/null +++ b/TIAMSharedUI/Pages/Login2.razor @@ -0,0 +1,130 @@ +@page "/login2" +@using TIAMWebApp.Shared.Application.Interfaces; +@using TIAMWebApp.Shared.Application.Models.PageModels; +@using TIAMSharedUI.Pages.Components; +@inject NavigationManager navManager +@inject IUserDataService UserDataservice +@inject IJSRuntime jsRuntime + +Login + +
+ +
+ Let's get you inside! +
+
+
+ @switch (currentStep) + { + case 1: + + ; + break; + + case 2: + + ; + break; + } +
+ + +
+

@currentStep

+ @{ + if (!loggedIn) + { + +
+ +

@loginModel.Email

+ +

@loginModel.Password

+
+ } + } +
+ Already have an account? Sign in here! +
+
+ +@code { + + LoginModel loginModel = new(); + + private int currentStep = 1; + + bool loggedIn = false; + + + private void GoToNextStep() + { + currentStep++; + } + + private void GoToPreviousStep() + { + currentStep--; + } + + private async void SubmitLogin() + { + + // Implement your registration logic here + // You can use Email, PhoneNumber, and Password variables + // Reset currentStep after successful registration + loggedIn = true; + currentStep = 1; + LogToBrowserConsole("Login started: " + "Email: " + loginModel.Email + ", Password: " + loginModel.Password); + var response = await UserDataservice.AuthenticateUser(loginModel); + //var response = await UserDataservice.TestUserApi(30); + LogToBrowserConsole("Login started"); + + if (!string.IsNullOrEmpty(response)) + { + LogToBrowserConsole(response); + if (response == "no") + { + //await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok"); + //display error message via jsinterop + LogToBrowserConsole("Invalid credentials"); + navManager.NavigateTo("login2"); + } + else if(response == "yes") + { + //await App.Current.MainPage.DisplayAlert("Success", "Successful login", "Ok"); + //display success message via jsinterop + LogToBrowserConsole("Successful login"); + navManager.NavigateTo("home"); + } + else + { + //await App.Current.MainPage.DisplayAlert("Error", "An error occured while trying to login", "Ok"); + //display error message via jsinterop + LogToBrowserConsole("An error occured while trying to login"); + navManager.NavigateTo("login2"); + } + + } + else + { + //api error + //await App.Current.MainPage.DisplayAlert("Error", "An error occured while trying to login", "Ok"); + //display error message via jsinterop + LogToBrowserConsole("An error occured while trying to login"); + navManager.NavigateTo("login2"); + } + + } + + public void LogToBrowserConsole(string message) + { + jsRuntime.InvokeVoidAsync("console.log", message); + } + + + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/Login2.razor.css b/TIAMSharedUI/Pages/Login2.razor.css new file mode 100644 index 00000000..8f676d9d --- /dev/null +++ b/TIAMSharedUI/Pages/Login2.razor.css @@ -0,0 +1,3 @@ +.wrapper { + max-width: 400px; +} diff --git a/TIAMSharedUI/Pages/Register.razor b/TIAMSharedUI/Pages/Register.razor index c958eef8..7466ddaa 100644 --- a/TIAMSharedUI/Pages/Register.razor +++ b/TIAMSharedUI/Pages/Register.razor @@ -1,38 +1,59 @@ @page "/register" +@using TIAMWebApp.Shared.Application.Interfaces; +@using TIAMWebApp.Shared.Application.Models.PageModels; +@using TIAMSharedUI.Pages.Components; @inject NavigationManager navManager +@inject IUserDataService UserDataservice +@inject IJSRuntime jsRuntime Register
- -
- Let's create your account! -
-
- - -
- - -
- - Next -
- - - -
- Already have an account? Sign in here! -
+ +
+ Let's create your account! +
+
+
+ @switch (currentStep) + { + case 1: + + ; + break; + case 2: + + ; + break; + case 3: + + ; + break; + } +
+ + +
+ @{ + if (!registered) + { + +
+

@regModel.Email

+

@regModel.PhoneNumber

+

@regModel.Password

+
+ } + } +
+ Already have an account? Sign in here! +
+
@code { + RegistrationModel regModel = new(); /*IEnumerable PredefinedPlaceholders = new List() { '_', '#' }; string Telephone { get; set; } = "5625595830"; char Placeholder { get; set; } = '_'; @@ -42,7 +63,63 @@ { navManager.NavigateTo("register2"); } - -} + + private int currentStep = 1; + + bool registered = false; + + private void GoToNextStep() + { + currentStep++; + } + + private void GoToPreviousStep() + { + currentStep--; + } + + private async Task SubmitRegistration() + { + + // Implement your registration logic here + // You can use Email, PhoneNumber, and Password variables + // Reset currentStep after successful registration + registered = true; + currentStep = 1; + var response = await UserDataservice.CreateUser(regModel); + + LogToBrowserConsole("Registration started: " + "Email: " + regModel.Email + "PhoneNumber: " + regModel.PhoneNumber + "Password: " + regModel.Password); + + + if (response.isSuccess) + { + //await App.Current.MainPage.DisplayAlert("Error", "Invalid credentials", "Ok"); + //display error message via jsinterop + LogToBrowserConsole(response.ErrorMessage); + + } + else if (!response.isSuccess) + { + //await App.Current.MainPage.DisplayAlert("Success", "Successful login", "Ok"); + //display success message via jsinterop + LogToBrowserConsole(response.ErrorMessage); + + } + else + { + //await App.Current.MainPage.DisplayAlert("Error", "An error occured while trying to login", "Ok"); + //display error message via jsinterop + LogToBrowserConsole(response.ErrorMessage); + + } + } + + public void LogToBrowserConsole(string message) + { + jsRuntime.InvokeVoidAsync("console.log", message); + } + + +} \ No newline at end of file diff --git a/TIAMSharedUI/Pages/Registerold.razor b/TIAMSharedUI/Pages/Registerold.razor new file mode 100644 index 00000000..1114bf1f --- /dev/null +++ b/TIAMSharedUI/Pages/Registerold.razor @@ -0,0 +1,48 @@ +@page "/registerOld" +@inject NavigationManager navManager +Register + +
+ +
+ Let's create your account! +
+
+ + +
+ + +
+ + Next +
+ + + +
+ Already have an account? Sign in here! +
+
+ +@code { + + /*IEnumerable PredefinedPlaceholders = new List() { '_', '#' }; + string Telephone { get; set; } = "5625595830"; + char Placeholder { get; set; } = '_'; + bool SaveLiterals { get; set; } = true;*/ + + private void next() + { + navManager.NavigateTo("register2"); + } + +} + + diff --git a/TIAMSharedUI/Pages/Registerold.razor.css b/TIAMSharedUI/Pages/Registerold.razor.css new file mode 100644 index 00000000..8f676d9d --- /dev/null +++ b/TIAMSharedUI/Pages/Registerold.razor.css @@ -0,0 +1,3 @@ +.wrapper { + max-width: 400px; +} diff --git a/TIAMSharedUI/Shared/Components/TIAMGridExample.razor b/TIAMSharedUI/Shared/Components/TIAMGridExample.razor index f8336ab5..4b2773eb 100644 --- a/TIAMSharedUI/Shared/Components/TIAMGridExample.razor +++ b/TIAMSharedUI/Shared/Components/TIAMGridExample.razor @@ -2,15 +2,18 @@ @using TIAMWebApp.Shared.Application.Interfaces; @using TIAMWebApp.Shared.Application.Models; +@using TIAMSharedUI.Shared.Components; +@using TIAMSharedUI.Shared.AcComponents; + @inject IWeatherForecastService WeatherForecastService; - + - + @code { diff --git a/TIAMSharedUI/Shared/Components/TIAMGrid.cs b/TIAMSharedUI/Shared/Components/TiamDxGridBase.cs similarity index 81% rename from TIAMSharedUI/Shared/Components/TIAMGrid.cs rename to TIAMSharedUI/Shared/Components/TiamDxGridBase.cs index 0272b4d0..bc60724d 100644 --- a/TIAMSharedUI/Shared/Components/TIAMGrid.cs +++ b/TIAMSharedUI/Shared/Components/TiamDxGridBase.cs @@ -13,15 +13,15 @@ namespace TIAMSharedUI.Shared.Components public class TiamDxGridBase : AcDxGridBase { [Parameter] - public IEnumerable Data { get; set; } + public new IEnumerable? Data { get; set; } [Parameter] - public RenderFragment ChildContent { get; set; } + public RenderFragment? ChildContent { get; set; } [Parameter] - public Dictionary Settings { get; set; } + public Dictionary? Settings { get; set; } protected override void BuildRenderTree(RenderTreeBuilder builder) { builder.OpenComponent(0); - builder.AddAttribute(1, "Data", (object)Data); + builder.AddAttribute(1, "Data", Data); builder.AddAttribute(2, "Columns", ChildContent); if (Settings != null) { diff --git a/TIAMWebApp/Client/Services/PopulationStructureDataProvider.cs b/TIAMWebApp/Client/Services/PopulationStructureDataProvider.cs index 390b709f..c9c4eead 100644 --- a/TIAMWebApp/Client/Services/PopulationStructureDataProvider.cs +++ b/TIAMWebApp/Client/Services/PopulationStructureDataProvider.cs @@ -15,7 +15,7 @@ namespace TIAMWebApp.Client.Services public Task QueryData() { - return http.GetFromJsonAsync("PopulationStructureAPI"); + return http.GetFromJsonAsync(APIUrls.PopulationStructure); } diff --git a/TIAMWebApp/Client/Services/UserDataService.cs b/TIAMWebApp/Client/Services/UserDataService.cs index 839dc6f4..1a4e8139 100644 --- a/TIAMWebApp/Client/Services/UserDataService.cs +++ b/TIAMWebApp/Client/Services/UserDataService.cs @@ -1,14 +1,18 @@ -using System.Net.Http.Json; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Newtonsoft.Json; +using System.Net.Http.Json; +using System.Text; using TIAMWebApp.Shared.Application.Interfaces; using TIAMWebApp.Shared.Application.Models; -using static TIAMSharedUI.Shared.MainLayout; +using TIAMWebApp.Shared.Application.Models.PageModels; + namespace TIAMWebApp.Client.Services { public class UserDataService : IUserDataService { private readonly HttpClient http; - public User? User { get; set; } = new User(); + public User? User { get; set; } = new User("","",""); public Dictionary userRoleTypes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public UserDataService(HttpClient http) @@ -36,7 +40,7 @@ namespace TIAMWebApp.Client.Services { if (User == null) { - User = new User(); + User = new User("","",""); User.IsLoggedIn = false; User.UserType = UserType.User; return User; @@ -49,11 +53,12 @@ namespace TIAMWebApp.Client.Services } + //Mock method for now public async Task AuthorizeUserAsync(int userType) { if (User == null) { - User = new User(); + User = new User("", "", ""); } //simply return true for now User.IsLoggedIn = true; @@ -61,6 +66,63 @@ namespace TIAMWebApp.Client.Services return User; } + public async Task TestUserApi(int Param) { + var url = APIUrls.UserTest; + var response = await http.PostAsJsonAsync(url, Param); + var result = await response.Content.ReadAsStringAsync(); + return result; + } + + public async Task AuthenticateUser(LoginModel loginModel) + { + + + + string result = string.Empty; + var url = APIUrls.AuthenticateUser; + + var response = await http.PostAsJsonAsync(url, loginModel); + + if(response.IsSuccessStatusCode) + { + result = await response.Content.ReadAsStringAsync(); + } + else + { + result = await response.Content.ReadAsStringAsync(); + } + + //result = await response.Content.ReadAsStringAsync(); + return result; + + + } + + public async Task<(bool isSuccess, string ErrorMessage)> CreateUser(RegistrationModel regModel) + { + + bool isSuccess = true; + string result = string.Empty; + var url = APIUrls.CreateUser; + + var response = await http.PostAsJsonAsync(url, regModel); + result = await response.Content.ReadAsStringAsync(); + /*if (response.IsSuccessStatusCode) + { + isSuccess = true; + result = await response.Content.ReadAsStringAsync(); + } + else + { + isSuccess = false; + result = await response.Content.ReadAsStringAsync(); + }*/ + + + return (isSuccess, result); + } + + public Task> GetUserRolesAsync(User user) { diff --git a/TIAMWebApp/Client/Services/WeatherForecastService.cs b/TIAMWebApp/Client/Services/WeatherForecastService.cs index 21d2ff53..9ce98121 100644 --- a/TIAMWebApp/Client/Services/WeatherForecastService.cs +++ b/TIAMWebApp/Client/Services/WeatherForecastService.cs @@ -14,7 +14,7 @@ namespace TIAMWebApp.Client.Services } public Task GetWeatherForecastAsync() { - return http.GetFromJsonAsync("WeatherForecastAPI"); + return http.GetFromJsonAsync(APIUrls.WeatherForecast); } } } diff --git a/TIAMWebApp/Server/Controllers/UserAPIController.cs b/TIAMWebApp/Server/Controllers/UserAPIController.cs new file mode 100644 index 00000000..89c8d6c4 --- /dev/null +++ b/TIAMWebApp/Server/Controllers/UserAPIController.cs @@ -0,0 +1,131 @@ +using DevExpress.Office.Crypto; +using DevExpress.Xpo.DB; +using DevExpress.XtraPrinting; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json.Linq; +using System.Reflection.Metadata; +using System.Text.Json; +using TIAMWebApp.Shared.Application.Models; +using TIAMWebApp.Shared.Application.Models.PageModels; + +namespace TIAMWebApp.Server.Controllers +{ + [ApiController] + [Route("[controller]")] + public class UserAPIController : ControllerBase + { + PasswordHasher hasher = new PasswordHasher(); + + + private User[] users = new User[] + { + new User("test@tiam.hu", "+36701234567", "asd123") + + }; + + private readonly ILogger _logger; + + public UserAPIController(ILogger logger) + { + _logger = logger; + } + + + [HttpPost] + [Route("Auth")] + public async Task AuthenticateUser([FromBody] JsonElement SerializedLoginModel) + { + Console.WriteLine("Auth called"); + Console.WriteLine(SerializedLoginModel.GetRawText()); + if (string.IsNullOrEmpty(SerializedLoginModel.GetRawText())) + { + return BadRequest("SerializedLoginModel is required"); + } + else + { + var user = JObject.Parse(SerializedLoginModel.GetRawText()).ToObject(); + + Console.WriteLine(user.Email); + Console.WriteLine(user.Password); + + if (user.Email == "test@tiam.hu" && user.Password == "asd123") + { + Console.WriteLine("User authenticated"); + return Ok("yes"); + } + else + { + Console.WriteLine("User NOT authenticated"); + return Ok("no"); + } + } + + } + + [HttpPost] + [Route("CreateUser")] + public async Task CreateUser([FromBody] JsonElement SerializedRegistrationModel) + { + if (string.IsNullOrEmpty(SerializedRegistrationModel.GetRawText())) + { + return BadRequest("SerializedLoginModel is required"); + } + else + { + var user = JObject.Parse(SerializedRegistrationModel.GetRawText()).ToObject(); + + if (users != null) + { + //add user to users array + Array.Resize(ref users, users.Length + 1); + users[users.Length - 1] = new User(user.Email, user.PhoneNumber, user.Password); + return Ok("yes"); + } + else + { + return Ok("no"); + } + + } + + + } + + [HttpPost] + [Route("Test1")] + public async Task TestEndpoint([FromBody] int testParam) + { + return Ok(testParam.ToString()); + + } + [HttpGet] + [Route("Test2")] + public string TestEndpoint2(int testParam) + { + return testParam.ToString(); + + } + + + [HttpGet] + [Route("GetUsers")] + public IEnumerable GetUsers() + { + throw new NotImplementedException(); + } + + private bool VerifyPassword(string password, string hashedPassword) + { + bool isPasswordValid = hasher.VerifyPassword(password, hashedPassword); + return isPasswordValid; + } + + private string HashPassword(string password) + { + var hashedPassword = hasher.HashPassword(password); + return hashedPassword; + } + } +} \ No newline at end of file diff --git a/TIAMWebApp/Shared/Interfaces/IUserDataService.cs b/TIAMWebApp/Shared/Interfaces/IUserDataService.cs index a871d6e1..5ae643c3 100644 --- a/TIAMWebApp/Shared/Interfaces/IUserDataService.cs +++ b/TIAMWebApp/Shared/Interfaces/IUserDataService.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using TIAMWebApp.Shared.Application.Models; +using TIAMWebApp.Shared.Application.Models.PageModels; namespace TIAMWebApp.Shared.Application.Interfaces { @@ -14,8 +15,13 @@ namespace TIAMWebApp.Shared.Application.Interfaces public Task IsLoggedInAsync(); + //mock method for now public Task AuthorizeUserAsync(int userType); + public Task AuthenticateUser(LoginModel loginModel); + public Task<(bool isSuccess, string ErrorMessage)> CreateUser(RegistrationModel regModel); + public Task TestUserApi(int Param); + public Task> GetUserRolesAsync(User user); } } \ No newline at end of file diff --git a/TIAMWebApp/Shared/Models/APIUrls.cs b/TIAMWebApp/Shared/Models/APIUrls.cs new file mode 100644 index 00000000..ab3bb3b2 --- /dev/null +++ b/TIAMWebApp/Shared/Models/APIUrls.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TIAMWebApp.Shared.Application.Models +{ + public class APIUrls + { + public const string UserTest = "UserAPI/test1"; + public const string AuthenticateUser = "UserAPI/Auth"; + public const string CreateUser = "UserAPI/CreateUser"; + public const string WeatherForecast = "WeatherForecastAPI"; + public const string PopulationStructure = "PopulationStructureAPI"; + } +} diff --git a/TIAMWebApp/Shared/Models/PageModels/LoginModel.cs b/TIAMWebApp/Shared/Models/PageModels/LoginModel.cs new file mode 100644 index 00000000..bcb23106 --- /dev/null +++ b/TIAMWebApp/Shared/Models/PageModels/LoginModel.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TIAMWebApp.Shared.Application.Models.PageModels +{ + public class LoginModel + { + public string? Email { get; set; } + + public string? Password { get; set; } + + } +} diff --git a/TIAMWebApp/Shared/Models/PageModels/RegistrationModel.cs b/TIAMWebApp/Shared/Models/PageModels/RegistrationModel.cs new file mode 100644 index 00000000..255dd946 --- /dev/null +++ b/TIAMWebApp/Shared/Models/PageModels/RegistrationModel.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TIAMWebApp.Shared.Application.Models.PageModels +{ + public class RegistrationModel + { + + public string? Email { get; set; } + + public string? Password { get; set; } + + public string? PhoneNumber { get; set; } + + } +} diff --git a/TIAMWebApp/Shared/Models/User.cs b/TIAMWebApp/Shared/Models/User.cs index 7a562a0c..6d378bf8 100644 --- a/TIAMWebApp/Shared/Models/User.cs +++ b/TIAMWebApp/Shared/Models/User.cs @@ -8,11 +8,24 @@ namespace TIAMWebApp.Shared.Application.Models { public class User { + public Guid Id { get; set; } + public string? Email { get; set; } + public string? Password { get; set; } + public string? PhoneNumber { get; set; } public bool IsLoggedIn { get; set; } public UserType UserType { get; set; } public int UserRoles { get; set; } public Dictionary UserRolesDictionary { get; set; } + public User(string email, string phonenumber, string password) + { + Id = new Guid(); + Email = email; + Password = password; + PhoneNumber = phonenumber; + UserRolesDictionary = new Dictionary(); + } + } public enum UserType diff --git a/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj b/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj index 118af6d5..25a181bc 100644 --- a/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj +++ b/TIAMWebApp/Shared/TIAMWebApp.Shared.Application.csproj @@ -14,6 +14,11 @@ + + + + + diff --git a/TIAMWebApp/Shared/Utility/LogToBrowserConsole.cs b/TIAMWebApp/Shared/Utility/LogToBrowserConsole.cs new file mode 100644 index 00000000..2e88f529 --- /dev/null +++ b/TIAMWebApp/Shared/Utility/LogToBrowserConsole.cs @@ -0,0 +1,26 @@ +using Microsoft.JSInterop; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TIAMWebApp.Shared.Application.Models; + +namespace TIAMWebApp.Shared.Application.Utility +{ + internal class LogToBrowserConsole + { + private readonly JSRuntime jsRuntime; + + public LogToBrowserConsole(JSRuntime jSRuntime) + { + this.jsRuntime = jsRuntime; + } + + public void LogToBC(string message) + { + jsRuntime.InvokeVoidAsync("console.log", message); + } + + } +} diff --git a/TIAMWebApp/Shared/Utility/PasswordHasher.cs b/TIAMWebApp/Shared/Utility/PasswordHasher.cs new file mode 100644 index 00000000..ba99b1d2 --- /dev/null +++ b/TIAMWebApp/Shared/Utility/PasswordHasher.cs @@ -0,0 +1,48 @@ +using Microsoft.AspNetCore.Cryptography.KeyDerivation; +using System.Security.Cryptography; + +public class PasswordHasher +{ + public string HashPassword(string password) + { + // Generate a random salt + byte[] salt = new byte[16]; + using (var rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(salt); + } + + // Hash the password with the salt + string hashedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password, + salt: salt, + prf: KeyDerivationPrf.HMACSHA512, + iterationCount: 10000, + numBytesRequested: 32)); + + // Combine the salt and hashed password + string combinedHash = $"$bcrypt$v=1$salt={Convert.ToBase64String(salt)}$hash={hashedPassword}"; + + return combinedHash; + } + + public bool VerifyPassword(string password, string hashedPassword) + { + // Extract the salt and hashed password from the combined hash + string[] parts = hashedPassword.Split('$'); + byte[] salt = Convert.FromBase64String(parts[3]); + string storedHash = parts[5]; + + // Hash the provided password with the extracted salt + string hashedProvidedPassword = Convert.ToBase64String(KeyDerivation.Pbkdf2( + password: password, + salt: salt, + prf: KeyDerivationPrf.HMACSHA512, + iterationCount: 10000, + numBytesRequested: 32)); + + // Compare the hashed passwords + return storedHash == hashedProvidedPassword; + } +} +