Login and registeruser api calls and api controller

This commit is contained in:
Adam 2023-11-22 11:02:22 +01:00
parent a61ff9967e
commit 515904e6bd
24 changed files with 902 additions and 126 deletions

View File

@ -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<ITransferDataService, TransferDataService>();
builder.Services.AddScoped<IPopulationStructureDataProvider, PopulationStructureDataProvider>();
builder.Services.AddScoped<ISupplierService, SupplierService>();
//builder.Services.AddSingleton<WeatherForecastService>();
builder.Services.AddSingleton<IUserDataService, UserDataService>();
return builder.Build();
}

View File

@ -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<int, string> userRoleTypes { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public UserDataService(HttpClient http)
{
this.http = http;
}
public List<RoleType> roleTypes = new List<RoleType>
{
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<User> 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<User> 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<string> 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<string> 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<Dictionary<int, string>> 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);
}
}
}

View File

@ -0,0 +1,63 @@
@using TIAMWebApp.Shared.Application.Models.PageModels;
<EditForm Model="@loginModel" OnValidSubmit="GoToNextStep">
<DataAnnotationsValidator />
<div class="form-field d-flex align-items-center">
<DxMaskedInput @bind-Value="@loginModel.Email"
Id="Email"
CssClass="cw-320"
Mask="@EmailMask"
MaskMode="MaskMode.RegEx">
<DxRegExMaskProperties MaskAutoCompleteMode="@((MaskAutoCompleteMode)AutoCompleteMode)"
Placeholder="Placeholder"
PlaceholdersVisible="PlaceholderVisible" />
</DxMaskedInput>
</div>
<ValidationMessage For="@(() => loginModel.Email)" />
<button class="btn btn-primary mt-3" type="submit">
<span class="@spinnerClass"></span>
Next
</button>
</EditForm>
@code {
[Parameter]
public LoginModel loginModel { get; set; }
//[Parameter]
//public string Email { get; set; }
[Parameter]
public EventCallback<string> onLoginNext { get; set; }
[Parameter]
public EventCallback<LoginModel> LoginModelChanged { get; set; }
IEnumerable<char> PredefinedPlaceholders { get; set; } = new List<char>() { '_', '#' };
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();
}
}

View File

@ -0,0 +1,62 @@
@using TIAMWebApp.Shared.Application.Models.PageModels;
<h3>Step 3: Password</h3>
<EditForm Model="@loginModel" OnValidSubmit="SubmitLogin">
<DataAnnotationsValidator />
<div class="form-field d-flex align-items-center">
<DxTextBox @bind-Text="@loginModel.Password"
Id="Password"
Password="true"
CssClass="cw-320" />
</div>
<ValidationMessage For="@(() => loginModel.Password)" />
<a class="btn btn-primary mt-3" @onclick="GoToPreviousStep">Previous</a>
<button class="btn btn-primary mt-3" type="submit">
<span class="@spinnerClass"></span>
Next
</button>
</EditForm>
@code {
[Parameter]
public LoginModel loginModel { get; set; }
[Parameter]
public EventCallback<LoginModel> LoginModelChanged { get; set; }
[Parameter]
public EventCallback<LoginModel> 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();
}
}

View File

@ -1,46 +1,62 @@
<form class="p-3 mt-3">
@using TIAMWebApp.Shared.Application.Models.PageModels;
<EditForm Model="@regModel" OnValidSubmit="GoToNextStep">
<DataAnnotationsValidator />
<div class="form-field d-flex align-items-center">
<DxMaskedInput @bind-Value="@Email"
CssClass="cw-320"
<DxMaskedInput @bind-Value="@regModel.Email"
Id="Email"
CssClass="cw-320"
Mask="@EmailMask"
MaskMode="MaskMode.RegEx">
<DxRegExMaskProperties MaskAutoCompleteMode="@((MaskAutoCompleteMode)AutoCompleteMode)"
Placeholder="Placeholder"
PlaceholdersVisible="PlaceholderVisible" />
</DxMaskedInput>
</div>
<a class="btn btn-primary mt-3" @onclick="GoToNextStep">Next</a>
</form>
<ValidationMessage For="@(() => regModel.Email)" />
<button class="btn btn-primary mt-3" type="submit">
<span class="@spinnerClass"></span>
Next
</button>
</EditForm>
@code {
[Parameter]
public string Email { get; set; }
public RegistrationModel regModel { get; set; }
//[Parameter]
//public string Email { get; set; }
[Parameter]
public EventCallback<string> onNext { get; set; }
[Parameter]
public EventCallback<string> EmailChanged { get; set; }
public EventCallback<RegistrationModel> RegModelChanged { get; set; }
IEnumerable<char> PredefinedPlaceholders { get; set; } = new List<char>() { '_', '#' };
string EmailMask { get; set; } = @"(\w|[.-])+@(\w|-)+\.(\w|-){2,4}";
MaskAutoCompleteMode AutoCompleteMode { get; set; } = MaskAutoCompleteMode.Strong;
char Placeholder { get; set; } = '_';
bool PlaceholderVisible { get; set; } = true;
bool PlaceholderVisible { get; set; } = false;
private string spinnerClass = "";
private async Task GoToNextStep()
{
await EmailChanged.InvokeAsync(Email);
spinnerClass = "spinner-border spinner-border-sm";
await Task.Delay(500);
spinnerClass = "";
await RegModelChanged.InvokeAsync(regModel);
await onNext.InvokeAsync();
}

View File

@ -1,39 +1,68 @@
<div>
<h3>Step 2: Phone Number</h3>
<div class="form-field d-flex align-items-center">
<DxMaskedInput @bind-Value="PhoneNumber"
Mask="\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*(\d{1,2})"
MaskMode="@MaskMode.RegEx">
<DxRegExMaskProperties Placeholder="Placeholder" />
</DxMaskedInput>
<!--input @bind="Email" type="email" name="email" id="email" placeholder="Email"-->
</div>
@using TIAMWebApp.Shared.Application.Models.PageModels;
<h3>Step 2: Phone Number</h3>
<EditForm Model="@regModel" OnValidSubmit="GoToNextStep">
<!--input @bind="PhoneNumber" placeholder="Enter your phone number" /-->
<a class="btn btn-primary mt-3" @onclick="GoToNextStep">Next</a>
</div>
<DataAnnotationsValidator />
<div class="form-field d-flex align-items-center">
<DxMaskedInput @bind-Value="regModel.PhoneNumber"
Id="PhoneNumber"
Mask="\+(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*\d\W*(\d{1,2})"
MaskMode="@MaskMode.RegEx">
<DxRegExMaskProperties Placeholder="Placeholder"
PlaceholdersVisible=false/>
</DxMaskedInput>
</div>
<ValidationMessage For="@(() => regModel.PhoneNumber)" />
<a class="btn btn-primary mt-3" @onclick="GoToPreviousStep">Previous</a>
<button class="btn btn-primary mt-3" type="submit">
<span class="@spinnerClass"></span>
Next
</button>
</EditForm>
@code {
[Parameter]
public string PhoneNumber { get; set; }
public RegistrationModel regModel { get; set; }
[Parameter]
public EventCallback<string> onNext { get; set; }
public EventCallback<RegistrationModel> onNext { get; set; }
[Parameter]
public EventCallback<string> PhoneNumberChanged { get; set; }
public EventCallback<RegistrationModel> onPrev { get; set; }
[Parameter]
public EventCallback<RegistrationModel> RegModelChanged { get; set; }
char Placeholder = '_';
private string spinnerClass = "";
private async Task GoToNextStep()
{
await PhoneNumberChanged.InvokeAsync(PhoneNumber);
await onNext.InvokeAsync(PhoneNumber);
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();
}
}

View File

@ -1,35 +1,64 @@
<div>
<h3>Step 3: Password</h3>
@using TIAMWebApp.Shared.Application.Models.PageModels;
<h3>Step 3: Password</h3>
<EditForm Model="@regModel" OnValidSubmit="SubmitRegistration">
<DataAnnotationsValidator />
<div class="form-field d-flex align-items-center">
<DxTextBox @bind-Text="@Password"
<DxTextBox @bind-Text="@regModel.Password"
Id="Password"
Password="true"
CssClass="cw-320" />
<!--input @bind="Email" type="email" name="email" id="email" placeholder="Email"-->
</div>
<!--input @bind="Password" type="password" placeholder="Enter your password" /-->
<a class="btn btn-primary mt-3" @onclick="SubmitRegistration">Next</a>
</div>
</div>
<ValidationMessage For="@(() => regModel.Password)" />
<a class="btn btn-primary mt-3" @onclick="GoToPreviousStep">Previous</a>
<button class="btn btn-primary mt-3" type="submit">
<span class="@spinnerClass"></span>
Next
</button>
</EditForm>
@code {
[Parameter]
public string Password { get; set; }
public RegistrationModel regModel { get; set; }
[Parameter]
public EventCallback<string> PasswordChanged { get; set; }
public EventCallback<RegistrationModel> RegModelChanged { get; set; }
[Parameter]
public EventCallback<RegistrationModel> onPrev { get; set; }
[Parameter]
public EventCallback onSubmit { get; set; }
private string spinnerClass = "";
public async Task SubmitRegistration()
{
await PasswordChanged.InvokeAsync(Password);
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();
}
}

View File

@ -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
<PageTitle>Login</PageTitle>
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
Let's get you inside!
</div>
<form class="p-3 mt-3">
<div>
@switch (currentStep)
{
case 1:
<LoginStep1 @bind-LoginModel="loginModel" onLoginNext="GoToNextStep" />
;
break;
case 2:
<LoginStep3 @bind-LoginModel="loginModel" onSubmit="SubmitLogin" onPrev="GoToPreviousStep" />
;
break;
}
</div>
</form>
<p>@currentStep</p>
@{
if (!loggedIn)
{
<div>
<p>@loginModel.Email</p>
<p>@loginModel.Password</p>
</div>
}
}
<div class="text-center fs-6">
Already have an account? <a href="login">Sign in here!</a>
</div>
</div>
@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);
}
}

View File

@ -0,0 +1,3 @@
.wrapper {
max-width: 400px;
}

View File

@ -1,36 +1,42 @@
@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
<PageTitle>Register</PageTitle>
<div class="wrapper">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
Let's create your account!
</div>
<form class="p-3 mt-3">
<div class="my-logo">
<img src="_content/TIAMSharedUI/images/png-logo-0.png" alt="">
</div>
<div class="text-center mt-4 name">
Let's create your account!
</div>
<form class="p-3 mt-3">
<div>
@switch (currentStep)
{
case 1:
<Step1 @bind-Email="regModel.Email" onNext="GoToNextStep" />;
<Step1 @bind-RegModel="regModel" onNext="GoToNextStep" />
;
break;
case 2:
<Step2 @bind-PhoneNumber="regModel.PhoneNumber" onNext="GoToNextStep" />;
<Step2 @bind-RegModel="regModel" onNext="GoToNextStep" onPrev="GoToPreviousStep" />
;
break;
case 3:
<Step3 @bind-Password="regModel.Password" onSubmit="SubmitRegistration" />;
<Step3 @bind-RegModel="regModel" onSubmit="SubmitRegistration" onPrev="GoToPreviousStep" />
;
break;
}
</div>
</form>
</form>
@{
if(!registered)
if (!registered)
{
<div>
@ -39,47 +45,80 @@
<p>@regModel.Password</p>
</div>
}
}
<div class="text-center fs-6">
Already have an account? <a href="login">Sign in here!</a>
</div>
}
<div class="text-center fs-6">
Already have an account? <a href="login">Sign in here!</a>
</div>
</div>
@code {
RegistrationModel regModel = new();
/*IEnumerable<char> PredefinedPlaceholders = new List<char>() { '_', '#' };
string Telephone { get; set; } = "5625595830";
char Placeholder { get; set; } = '_';
bool SaveLiterals { get; set; } = true;*/
private void next()
{
navManager.NavigateTo("register2");
}
RegistrationModel regModel = new();
/*IEnumerable<char> PredefinedPlaceholders = new List<char>() { '_', '#' };
string Telephone { get; set; } = "5625595830";
char Placeholder { get; set; } = '_';
bool SaveLiterals { get; set; } = true;*/
private void next()
{
navManager.NavigateTo("register2");
}
private int currentStep = 1;
private string Email { get; set; }
private string PhoneNumber { get; set; }
private string Password { get; set; }
bool registered = false;
private void GoToNextStep(string someString)
private void GoToNextStep()
{
currentStep++;
}
private void SubmitRegistration()
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);
}

View File

@ -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;
<TiamGrid Data="Forecasts" Settings="InputAttributes">
<TiamDxGridBase Data="Forecasts" Settings="InputAttributes">
<DxGridCommandColumn Width="150px" />
<DxGridDataColumn FieldName="@nameof(WeatherForecast.Date)"></DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(WeatherForecast.TemperatureC)"></DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(WeatherForecast.TemperatureF)"></DxGridDataColumn>
<DxGridDataColumn FieldName="@nameof(WeatherForecast.Summary)"></DxGridDataColumn>
</TiamGrid>
</TiamDxGridBase>
@code {

View File

@ -13,15 +13,15 @@ namespace TIAMSharedUI.Shared.Components
public class TiamDxGridBase<T> : AcDxGridBase<T>
{
[Parameter]
public IEnumerable<T> Data { get; set; }
public new IEnumerable<T>? Data { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
public RenderFragment? ChildContent { get; set; }
[Parameter]
public Dictionary<string, object> Settings { get; set; }
public Dictionary<string, object>? Settings { get; set; }
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenComponent<DxGrid>(0);
builder.AddAttribute(1, "Data", (object)Data);
builder.AddAttribute(1, "Data", Data);
builder.AddAttribute(2, "Columns", ChildContent);
if (Settings != null)
{

View File

@ -15,7 +15,7 @@ namespace TIAMWebApp.Client.Services
public Task<PopulationAgeStructureItem[]?> QueryData()
{
return http.GetFromJsonAsync<PopulationAgeStructureItem[]>("PopulationStructureAPI");
return http.GetFromJsonAsync<PopulationAgeStructureItem[]>(APIUrls.PopulationStructure);
}

View File

@ -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<int, string> 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<User> 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<string> 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<string> 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<Dictionary<int, string>> GetUserRolesAsync(User user)
{

View File

@ -14,7 +14,7 @@ namespace TIAMWebApp.Client.Services
}
public Task<WeatherForecast[]?> GetWeatherForecastAsync()
{
return http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecastAPI");
return http.GetFromJsonAsync<WeatherForecast[]>(APIUrls.WeatherForecast);
}
}
}

View File

@ -1,6 +1,14 @@
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
{
@ -8,32 +16,12 @@ namespace TIAMWebApp.Server.Controllers
[Route("[controller]")]
public class UserAPIController : ControllerBase
{
private static readonly Supplier[] suppliers = new Supplier[]
PasswordHasher hasher = new PasswordHasher();
private User[] users = new User[]
{
new Supplier(1, "Upgen Ltd.", "Sándor Kovács", "Mr", "Váci street 132", "Budapest", "Budapest", "1136", "Hungary", "+36701234567", "+3611234567", "https://www.upgen.hu"),
new Supplier(2, "Kiraly Ltd.", "Elemér Kiraly", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
//generate 9 new suppliers with different homepage url, companyname, contactname, city, address and postalcode
new Supplier(3, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(4, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(5, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(6, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(7, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(8, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(9, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(10, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
new Supplier(11, "Király Ltd.", "Elemér Király", "Mr", "Andrássy street 37", "Budapest", "Budapest", "1066", "Hungary", "+36701234567", "+3611234567", "https://www.kiraly.hu"),
};
private Product[] GetMockUsers(int SupplierId)
{
throw new NotImplementedException();
}
private static readonly User[] users = new User[]
{
new User{Id=1, Email="test@tiam.hu", IsLoggedIn = true},
new User("test@tiam.hu", "+36701234567", "asd123")
};
@ -44,10 +32,100 @@ namespace TIAMWebApp.Server.Controllers
_logger = logger;
}
[HttpPost]
[Route("Auth")]
public async Task<IActionResult> 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<LoginModel>();
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<IActionResult> CreateUser([FromBody] JsonElement SerializedRegistrationModel)
{
if (string.IsNullOrEmpty(SerializedRegistrationModel.GetRawText()))
{
return BadRequest("SerializedLoginModel is required");
}
else
{
var user = JObject.Parse(SerializedRegistrationModel.GetRawText()).ToObject<RegistrationModel>();
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<IActionResult> TestEndpoint([FromBody] int testParam)
{
return Ok(testParam.ToString());
}
[HttpGet]
[Route("Test2")]
public string TestEndpoint2(int testParam)
{
return testParam.ToString();
}
[HttpGet]
[Route("GetUsers")]
public IEnumerable<Supplier> 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;
}
}
}

View File

@ -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<User> IsLoggedInAsync();
//mock method for now
public Task<User> AuthorizeUserAsync(int userType);
public Task<string> AuthenticateUser(LoginModel loginModel);
public Task<(bool isSuccess, string ErrorMessage)> CreateUser(RegistrationModel regModel);
public Task<string> TestUserApi(int Param);
public Task<Dictionary<int, string>> GetUserRolesAsync(User user);
}
}

View File

@ -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";
}
}

View File

@ -8,11 +8,10 @@ using System.Threading.Tasks;
namespace TIAMWebApp.Shared.Application.Models.PageModels
{
public class LoginModel
{
[Required]
public string? Password { get; set; }
[Required]
{
public string? Email { get; set; }
public string? Password { get; set; }
}
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -8,8 +9,11 @@ namespace TIAMWebApp.Shared.Application.Models.PageModels
{
public class RegistrationModel
{
public string? Email { get; set; }
public string? Password { get; set; }
public string? PhoneNumber { get; set; }
}

View File

@ -8,7 +8,7 @@ namespace TIAMWebApp.Shared.Application.Models
{
public class User
{
public int Id { get; set; }
public Guid Id { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
public string? PhoneNumber { get; set; }
@ -17,6 +17,15 @@ namespace TIAMWebApp.Shared.Application.Models
public int UserRoles { get; set; }
public Dictionary<int, string> UserRolesDictionary { get; set; }
public User(string email, string phonenumber, string password)
{
Id = new Guid();
Email = email;
Password = password;
PhoneNumber = phonenumber;
UserRolesDictionary = new Dictionary<int, string>();
}
}
public enum UserType

View File

@ -14,6 +14,11 @@
<Folder Include="Models\DTO\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="8.0.0" />
<PackageReference Include="Microsoft.JSInterop" Version="7.0.10" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\TIAM.Database\TIAM.Database.csproj" />
<ProjectReference Include="..\..\TIAM.Entities.Server\TIAM.Entities.Server.csproj" />

View File

@ -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);
}
}
}

View File

@ -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;
}
}