This commit is contained in:
Adam 2024-08-13 09:54:43 +02:00
commit 2c0e3fd443
13 changed files with 213 additions and 164 deletions

View File

@ -1,5 +1,9 @@
namespace TIAM.Services.Interfaces;
using AyCode.Core.Consts;
namespace TIAM.Services.Interfaces;
public interface IUserApiControllerClient : IUserApiControllerCommon
{
public Task<AcErrorCode> UserChangePassword(Guid userId, string oldPassword, string newPassword);
public Task<AcErrorCode> UserForgotPassword(string email, string newPassword);
}

View File

@ -1,4 +1,5 @@
using TIAM.Entities.Users;
using AyCode.Core.Consts;
using TIAM.Entities.Users;
using TIAM.Models.Dtos.Users;
namespace TIAM.Services.Interfaces;
@ -7,4 +8,7 @@ public interface IUserApiControllerCommon
{
public Task<User?> UpdateUser(User user);
public Task<UserModelDtoDetail?> UpdateUserModelDtoDetail(UserModelDtoDetail userModelDtoDetail);
public Task<AcErrorCode> UserChangePassword(ChangePasswordDto changePasswordDto);
public Task<AcErrorCode> UserForgotPassword(ForgotPasswordDto forgotPasswordDto);
}

View File

@ -1,4 +1,5 @@
@using BlazorAnimation
@using AyCode.Core.Consts
@using BlazorAnimation
@using TIAM.Core.Enums
@using TIAM.Entities.Transfers
@using TIAM.Entities.Users
@ -65,7 +66,7 @@
CssClass="form-field" />
</div>
<div class="col-3 col-md-2">
<DxButton CssClass="btn btn-primary" Click="SetPassword" Enabled="@isSaveActive"> Save</DxButton>
<DxButton CssClass="btn btn-primary" Click="SetPassword" Enabled="@_isSaveActive"> Save</DxButton>
</div>
<p>@msg</p>
@ -88,11 +89,10 @@
get => _newPassword;
set
{
if (_newPassword != value)
{
_newPassword = value;
OnPasswordSet(value);
}
if (_newPassword == value) return;
_newPassword = value;
OnPasswordSet(value);
}
}
@ -104,21 +104,21 @@
get => _confirmNewPassword;
set
{
if (value != null && _confirmNewPassword != value)
{
_confirmNewPassword = value;
OnPasswordConfirmed(value);
}
if (value == null || _confirmNewPassword == value) return;
_confirmNewPassword = value;
OnPasswordConfirmed(value);
}
}
string msg;
private bool isSaveActive = false;
private bool _isSaveActive = false;
void OnPasswordSet(string password)
{
msg = $"Password to set: {NewPassword}";
PasswordNotSet = false;
StateHasChanged();
}
@ -127,69 +127,38 @@
if (NewPassword == ConfirmNewPassword)
{
PasswordNotConfirmed = false;
isSaveActive = true;
_isSaveActive = true;
}
else
{
isSaveActive = false;
_isSaveActive = false;
msg = "Password and confirmation not matching!";
}
}
protected async Task SetPassword()
{
bool isSuccess = false;
if (!IsForgotten)
{
isSaveActive = false;
_isSaveActive = false;
var changePasswordDto = new ChangePasswordDto(Context.Id, OldPassword, NewPassword);
//var changePasswordDto = new ChangePasswordDto(Context.Id, "Asdasd123456", NewPassword);
var result = await AdminSignalRClient.PostDataAsync(SignalRTags.UserChangePassword, changePasswordDto);
var errorCode = IsForgotten ?
await AdminSignalRClient.UserForgotPassword(Context.UserDto.EmailAddress, NewPassword) :
await AdminSignalRClient.UserChangePassword(Context.Id, OldPassword, NewPassword);
if (result != null)
{
msg = $"Password saved";
StateHasChanged();
}
else
{
msg = "Some error occured during saving, please try again later";
}
}
else
{
isSaveActive = false;
var forgotPasswordDto = new ForgotPasswordDto(Context.UserDto.EmailAddress, NewPassword);
//var changePasswordDto = new ChangePasswordDto(Context.Id, "Asdasd123456", NewPassword);
var result = await AdminSignalRClient.PostDataAsync(SignalRTags.UserForgotPassword, forgotPasswordDto);
var isSucces = errorCode == AcErrorCode.Unset;
if (result != null)
{
isSuccess = true;
msg = $"Password saved";
StateHasChanged();
}
else
{
isSuccess = false;
msg = "Some error occured during saving, please try again later";
}
}
await DataChanged.InvokeAsync(isSuccess);
msg = isSucces ? "Password saved" : $"Some error occured during saving, please try again later! [{errorCode}]";
StateHasChanged();
await DataChanged.InvokeAsync(isSucces);
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
}
protected override async Task OnParametersSetAsync()
{
await base.OnParametersSetAsync();
}

View File

@ -12,35 +12,30 @@ using AyCode.Core.Loggers;
using TIAM.Database.DataLayers.Users;
using TIAM.Entities.Users;
using TIAM.Models.Dtos.Users;
using TIAM.Entities.Profiles;
using TIAM.Entities.Addresses;
using TIAM.Services.Server.Logins;
using ILogger = TIAM.Core.Loggers.ILogger;
using AyCode.Core.Helpers;
using AyCode.Entities;
using AyCode.Services.SignalRs;
using TIAM.Models.Server.Logins;
using TIAM.Services;
using TIAM.Services.Interfaces;
using TIAMWebApp.Shared.Application.Services;
using GoogleApi.Entities.Search.Video.Common;
using TIAM.Database.DataLayers.Admins;
using TIAM.Entities.Emails;
using TIAMWebApp.Shared.Application.Models.ClientSide.Messages;
using TIAMWebApp.Shared.Application.Models.ClientSide;
using System.Net;
using TIAM.Services.Server;
using TIAM.Services.Server.Logins;
using TIAMWebApp.Server.Services;
namespace TIAMWebApp.Server.Controllers
{
[Authorize]
[ApiController]
[Route("api/v1/[controller]")]
public class UserAPIController(IConfiguration configuration, AdminDal adminDal, UserDal userDal, IMessageSenderService messageSenderService, IEnumerable<IAcLogWriterBase> logWriters) : ControllerBase, IUserApiControllerCommon
public class UserAPIController(IConfiguration configuration, AdminDal adminDal, UserDal userDal, IMessageSenderService messageSenderService, SessionService sessionService, IEnumerable<IAcLogWriterBase> logWriters) : ControllerBase, IUserApiControllerCommon
{
private readonly TIAM.Core.Loggers.Logger<UserAPIController> _logger = new(logWriters.ToArray());
private LoginService _loginService = new LoginService(userDal, configuration);
private readonly LoginService _loginService = new(userDal, configuration);
//private readonly IWebHostEnvironment _webHostEnvironment;
//readonly PasswordHasher _hasher = new();
@ -348,32 +343,30 @@ namespace TIAMWebApp.Server.Controllers
[NonAction]
[SignalR(SignalRTags.UserChangePassword)]
public async Task<UserModelDtoDetail?> UserChangePassword([FromBody] ChangePasswordDto changePasswordDto)
public async Task<AcErrorCode> UserChangePassword([FromBody] ChangePasswordDto changePasswordDto)
{
_logger.Info("ChangeUserPassword called");
var errorCode = await _loginService.ChangePasswordAsync(changePasswordDto.UserId, changePasswordDto.OldPassword, changePasswordDto.NewPassword);
if (errorCode == AcErrorCode.Unset)
return await userDal.GetUserModelDtoByIdAsync<UserModelDtoDetail>(changePasswordDto.UserId, true);
if (errorCode != AcErrorCode.Unset)
_logger.Error($"ErrorCode: {errorCode}; userId: {changePasswordDto.UserId}");
_logger.Error($"ErrorCode: {errorCode}; userId: {changePasswordDto.UserId}");
return null;
return errorCode;
}
[NonAction]
[SignalR(SignalRTags.UserForgotPassword)]
public async Task<UserModelDtoDetail?> UserForgotPassword([FromBody] ForgotPasswordDto forgotPasswordDto)
public async Task<AcErrorCode> UserForgotPassword([FromBody] ForgotPasswordDto forgotPasswordDto)
{
_logger.Info("UserForgotPassword called");
var errorCode = await _loginService.ForgotPasswordAsync(forgotPasswordDto.Email, forgotPasswordDto.NewPassword);
if (errorCode == AcErrorCode.Unset)
return await userDal.GetUserModelDtoByEmailAsync<UserModelDtoDetail>(forgotPasswordDto.Email, true);
if (errorCode != AcErrorCode.Unset)
_logger.Error($"ErrorCode: {errorCode}; email: {forgotPasswordDto.Email}");
_logger.Error($"ErrorCode: {errorCode}; email: {forgotPasswordDto.Email}");
return null;
return errorCode;
}
[NonAction]

View File

@ -35,6 +35,7 @@ builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<LoggerToLoggerApiController>();
builder.Services.AddSingleton<IAcLogWriterBase, ConsoleLogWriter>();
builder.Services.AddSingleton<IAcLogWriterBase, DbLogItemWriter>();
builder.Services.AddSingleton<SessionService>();
builder.Services.AddScoped<UserDal>();
builder.Services.AddScoped<AdminDal>();

View File

@ -1,6 +1,4 @@
using System.Collections.Concurrent;
using System.Reflection;
using AyCode.Core.Extensions;
using AyCode.Core.Extensions;
using AyCode.Core.Loggers;
using AyCode.Services.SignalRs;
using Microsoft.AspNetCore.SignalR;
@ -9,107 +7,46 @@ using MessagePack.Resolvers;
using AyCode.Services.Server.SignalRs;
using TIAM.Services;
using TIAMWebApp.Server.Controllers;
using TIAM.Entities.ServiceProviders;
using System.Runtime.CompilerServices;
using MessagePack;
using TIAM.Entities.Addresses;
using Microsoft.AspNetCore.Hosting;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq.Expressions;
using AutoMapper;
using AyCode.Core.Helpers;
using DevExpress.Pdf.Native.BouncyCastle.Security;
using TIAM.Entities.Emails;
using TIAM.Services.Server;
using Profile = TIAM.Entities.Profiles.Profile;
using Serialize.Linq.Serializers;
using System.Security.Claims;
using AyCode.Core;
using AyCode.Blazor.Components.Services;
using TIAM.Database.DataLayers.Users;
using TIAM.Services.Server.Logins;
using TIAMWebApp.Shared.Application.Interfaces;
namespace TIAMWebApp.Server.Services;
public static class ExtensionMethods
{
public static object? InvokeMethod(this MethodInfo methodInfo, object obj, params object[]? parameters)
{
if (methodInfo.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) is AsyncStateMachineAttribute isAsyncTask)
{
dynamic awaitable = methodInfo.Invoke(obj, parameters)!;
return awaitable.GetAwaiter().GetResult();
}
return methodInfo.Invoke(obj, parameters);
}
}
public class MethodInfoModel<TAttribute> where TAttribute : TagAttribute
{
public ParameterInfo[]? ParamInfos { get; init; } = null;
public TAttribute Attribute { get; init; }
public MethodInfo MethodInfo { get; init; }
public MethodInfoModel(TAttribute attribute, MethodInfo methodInfo)
{
Attribute = attribute;
MethodInfo = methodInfo;
var parameters = methodInfo.GetParameters();
//if (parameters.Length > 1)
// throw new Exception("MethodInfoModel; parameters.Length > 1");
ParamInfos = parameters;
}
}
public class DynamicMethodCallModel<TAttribute> where TAttribute : TagAttribute
{
public object InstanceObject { get; init; }
public ConcurrentDictionary<int, MethodInfoModel<TAttribute>> MethodsByMessageTag { get; init; } = new();
public DynamicMethodCallModel(Type instanceObjectType) : this(instanceObjectType, null!)
{
}
public DynamicMethodCallModel(Type instanceObjectType, params object[] constructorParams) : this(Activator.CreateInstance(instanceObjectType, constructorParams)!)
{
}
public DynamicMethodCallModel(object instanceObject)
{
InstanceObject = instanceObject;
foreach (var methodInfo in instanceObject.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(TAttribute)) is not TAttribute attribute) continue;
if (MethodsByMessageTag.ContainsKey(attribute.MessageTag))
throw new Exception($"Multiple SignaRMessageTag! messageTag: {attribute.MessageTag}; methodName: {methodInfo.Name}");
MethodsByMessageTag[attribute.MessageTag] = new MethodInfoModel<TAttribute>(attribute, methodInfo!);
}
}
}
public class DevAdminSignalRHub : Hub<ISignalRHubItemServer>, IAcSignalRHubServer
{
private readonly List<DynamicMethodCallModel<SignalRAttribute>> _dynamicMethodCallModels = [];
private readonly TIAM.Core.Loggers.Logger<DevAdminSignalRHub> _logger;
private SessionService _sessionService;
private IConfiguration _configuration;
private readonly AdminDal _adminDal;
private readonly UserDal _userDal;
//private readonly ServiceProviderAPIController _serviceProviderApiController;
//private readonly TransferDataAPIController _transferDataApiController;
public DevAdminSignalRHub(AdminDal adminDal, UserAPIController userApiController, ServiceProviderAPIController serviceProviderApiController, TransferDataAPIController transferDataApiController, MessageAPIController messageApiController, ProfileAPIController profileApiController, LoggerApiController loggerApiController, IEnumerable<IAcLogWriterBase> logWriters)
public DevAdminSignalRHub(IConfiguration configuration, AdminDal adminDal, UserDal userDal, UserAPIController userApiController, ServiceProviderAPIController serviceProviderApiController, TransferDataAPIController transferDataApiController, MessageAPIController messageApiController, ProfileAPIController profileApiController, LoggerApiController loggerApiController, SessionService sessionService, IEnumerable<IAcLogWriterBase> logWriters)
{
_adminDal = adminDal;
_userDal = userDal;
_configuration = configuration;
//_serviceProviderApiController = serviceProviderApiController;
//_transferDataApiController = transferDataApiController;
_logger = new(logWriters.ToArray());
_sessionService = sessionService;
_dynamicMethodCallModels.Add(new DynamicMethodCallModel<SignalRAttribute>(userApiController));
_dynamicMethodCallModels.Add(new DynamicMethodCallModel<SignalRAttribute>(serviceProviderApiController));
@ -128,6 +65,9 @@ public class DevAdminSignalRHub : Hub<ISignalRHubItemServer>, IAcSignalRHubServe
LogContextUserNameAndId();
_sessionService.Sessions.TryAdd(Context.ConnectionId, new SessionItem(Context.ConnectionId, new LoginService(_userDal, _configuration)));
_logger.Info($"_sessionService.Sessions count: {_sessionService.Sessions.Count}");
////insert or updatde them into database.
//var CId = _context.UserIdToCId.Find(userId);
//CId.ConnectionId = connectionid;
@ -151,6 +91,9 @@ public class DevAdminSignalRHub : Hub<ISignalRHubItemServer>, IAcSignalRHubServe
LogContextUserNameAndId();
if (_sessionService.Sessions.TryRemove(Context.ConnectionId, out var sessionItem)) sessionItem.LoginService.Logout();
_logger.Info($"_sessionService.Sessions count: {_sessionService.Sessions.Count}");
//await Groups.RemoveFromGroupAsync(Context.ConnectionId, "SignalR Users");
await base.OnDisconnectedAsync(exception);
}

View File

@ -0,0 +1,35 @@
using System.Collections.Concurrent;
using System.Reflection;
using AyCode.Services.SignalRs;
namespace TIAMWebApp.Server.Services;
public class DynamicMethodCallModel<TAttribute> where TAttribute : TagAttribute
{
public object InstanceObject { get; init; }
public ConcurrentDictionary<int, MethodInfoModel<TAttribute>> MethodsByMessageTag { get; init; } = new();
public DynamicMethodCallModel(Type instanceObjectType) : this(instanceObjectType, null!)
{
}
public DynamicMethodCallModel(Type instanceObjectType, params object[] constructorParams) : this(Activator.CreateInstance(instanceObjectType, constructorParams)!)
{
}
public DynamicMethodCallModel(object instanceObject)
{
InstanceObject = instanceObject;
foreach (var methodInfo in instanceObject.GetType().GetMethods())
{
if (methodInfo.GetCustomAttribute(typeof(TAttribute)) is not TAttribute attribute) continue;
if (MethodsByMessageTag.ContainsKey(attribute.MessageTag))
throw new Exception($"Multiple SignaRMessageTag! messageTag: {attribute.MessageTag}; methodName: {methodInfo.Name}");
MethodsByMessageTag[attribute.MessageTag] = new MethodInfoModel<TAttribute>(attribute, methodInfo!);
}
}
}

View File

@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
namespace TIAMWebApp.Server.Services;
public static class ExtensionMethods
{
public static object? InvokeMethod(this MethodInfo methodInfo, object obj, params object[]? parameters)
{
if (methodInfo.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) is AsyncStateMachineAttribute isAsyncTask)
{
dynamic awaitable = methodInfo.Invoke(obj, parameters)!;
return awaitable.GetAwaiter().GetResult();
}
return methodInfo.Invoke(obj, parameters);
}
}

View File

@ -0,0 +1,24 @@
using System.Reflection;
using AyCode.Services.SignalRs;
namespace TIAMWebApp.Server.Services;
public class MethodInfoModel<TAttribute> where TAttribute : TagAttribute
{
public ParameterInfo[]? ParamInfos { get; init; } = null;
public TAttribute Attribute { get; init; }
public MethodInfo MethodInfo { get; init; }
public MethodInfoModel(TAttribute attribute, MethodInfo methodInfo)
{
Attribute = attribute;
MethodInfo = methodInfo;
var parameters = methodInfo.GetParameters();
//if (parameters.Length > 1)
// throw new Exception("MethodInfoModel; parameters.Length > 1");
ParamInfos = parameters;
}
}

View File

@ -0,0 +1,16 @@
using AyCode.Blazor.Components.Services;
using TIAM.Services.Server.Logins;
namespace TIAMWebApp.Server.Services;
public class SessionItem : IAcSessionItem<string>
{
public string SessionId { get; set; }
public LoginService LoginService { get; set; }
public SessionItem(string sessionId, LoginService loginService)
{
SessionId = sessionId;
LoginService = loginService;
}
}

View File

@ -0,0 +1,8 @@
using AyCode.Blazor.Components.Services;
namespace TIAMWebApp.Server.Services;
public class SessionService : AcSessionService<SessionItem, string>
{
}

View File

@ -1,15 +1,8 @@
using System.Collections.Concurrent;
using AyCode.Blazor.Components.Services;
using AyCode.Core;
using AyCode.Core.Extensions;
using AyCode.Blazor.Components.Services;
using AyCode.Core.Consts;
using AyCode.Core.Helpers;
using AyCode.Core.Interfaces;
using AyCode.Interfaces.Entities;
using AyCode.Services.Loggers;
using AyCode.Services.SignalRs;
using MessagePack.Resolvers;
using Microsoft.AspNetCore.SignalR.Client;
using TIAM.Core.Consts;
using TIAM.Entities.Drivers;
using TIAM.Entities.Transfers;
using TIAM.Entities.Users;
@ -34,6 +27,13 @@ namespace TIAMWebApp.Shared.Application.Services
public async Task<UserModelDtoDetail?> UpdateUserModelDtoDetail(UserModelDtoDetail userModelDtoDetail)
=> await PostDataAsync(SignalRTags.UpdateUserModelDtoDetail, userModelDtoDetail);
public Task<AcErrorCode> UserChangePassword(Guid userId, string oldPassword, string newPassword) => UserChangePassword(new ChangePasswordDto(userId, oldPassword, newPassword));
public Task<AcErrorCode> UserChangePassword(ChangePasswordDto changePasswordDto) => PostDataAsync<ChangePasswordDto, AcErrorCode>(SignalRTags.UserChangePassword, changePasswordDto);
public Task<AcErrorCode> UserForgotPassword(string email, string newPassword) => UserForgotPassword(new ForgotPasswordDto(email, newPassword));
public Task<AcErrorCode> UserForgotPassword(ForgotPasswordDto forgotPasswordDto) => PostDataAsync<ForgotPasswordDto, AcErrorCode>(SignalRTags.UserForgotPassword, forgotPasswordDto);
#endregion IUserApiController
#region ICompanyApiController

View File

@ -1,3 +1,4 @@
using AyCode.Core.Consts;
using AyCode.Core.Enums;
using AyCode.Core.Helpers;
using AyCode.Core.Loggers;
@ -7,6 +8,8 @@ using Azure;
using DevExpress.Data.Filtering;
using DevExpress.Data.Linq;
using DevExpress.Data.Linq.Helpers;
using Newtonsoft.Json;
using SkiaSharp;
using TIAM.Core.Consts;
using TIAM.Core.Enums;
using TIAM.Core.Loggers;
@ -15,6 +18,7 @@ using TIAM.Entities.Drivers;
using TIAM.Entities.ServiceProviders;
using TIAM.Entities.Transfers;
using TIAM.Entities.Users;
using TIAM.Models.Dtos.Users;
using TIAM.Services;
using TIAMWebApp.Shared.Application.Services;
using TIAMWebApp.Shared.Application.Utility;
@ -254,6 +258,36 @@ namespace Tiam.Services.Client.Tests
Assert.IsTrue(transfers.All(x => x.UserId == userId));
}
[TestMethod]
[DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
public async Task ChangePasswordTest_ReturnErrorCode_WhenErrorCodeIsUnset(string userIdString)
{
var userId = Guid.Parse(userIdString);
var errorCode = await _signalRClient.UserChangePassword(userId, "Asdasd123456", "Asdasd123456");
Assert.IsTrue(errorCode == AcErrorCode.Unset, errorCode.ToString());
}
[TestMethod]
[DataRow("540271F6-C604-4C16-8160-D5A7CAFEDF00")]
public async Task ChangePasswordTest_ReturnErrorCode_WhenErrorCodeIsNotUnset(string userIdString)
{
var userId = Guid.Parse(userIdString);
var changePasswordDto = new ChangePasswordDto(userId, "ffdsdergtyf22A", "Asdasd123456");
var errorCode = await _signalRClient.UserChangePassword(changePasswordDto);
Assert.IsTrue(errorCode == AcErrorCode.WrongLoginData, errorCode.ToString());
changePasswordDto.UserId = Guid.Parse("110271F6-C604-4C16-8160-D5A7CAFEDF11");
errorCode = await _signalRClient.UserChangePassword(changePasswordDto);
Assert.IsTrue(errorCode == AcErrorCode.EntityIsNull, errorCode.ToString());
changePasswordDto.NewPassword = "a";
errorCode = await _signalRClient.UserChangePassword(changePasswordDto);
Assert.IsTrue(errorCode == AcErrorCode.PasswordIsTooShort, errorCode.ToString());
}
[TestMethod]
[DataRow("")]
public async Task GetAllCarsAndDriversByProductIdAsyncTest_ReturnCarsAndDrivers_WhenHasCarsAndDrivers(string productIdString)