Knocks/BackEnd/Knoks.Core/Logic/Managers/UserManager.cs

219 lines
8.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Knoks.Core.Data.Interfaces;
using Knoks.Core.Entities;
using Knoks.Core.Entities.Args;
using Knoks.Core.Logic.Interfaces;
using Knoks.Framework.Cryptography;
using Knoks.Framework.Security;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using System;
using Knoks.Framework.Services;
using System.Security.Cryptography;
using System.Net;
namespace Knoks.Core.Logic.Managers
{
public class UserManager : IUserManager
{
#region Fields
private readonly ILogger<UserManager> _logger;
private readonly IUserDao _userDao;
private readonly IPasswordStrength _passwordStrength;
private readonly IPasswordProcess _passwordProcess;
private readonly IEventManager _eventManager;
private readonly IUserImageManager _userImageManager;
private readonly IAccountDao _accountDao;
private readonly IAccountTransactionsSettings _settings;
private readonly IEmailService _emailService;
private readonly IGeneralManager _generalManager;
public User PlatformUser { get; private set; }
public Account PlatformUserAccount { get; private set; }
#endregion
/// <summary>
/// ctor
/// </summary>
/// <param name="logger"></param>
/// <param name="userDao"></param>
/// <param name="passwordStrength"></param>
/// <param name="passwordProcess"></param>
/// <param name="eventManager"></param>
/// <param name="userImageManager"></param>
/// <param name="accountDao"></param>
/// <param name="settings"></param>
public UserManager(
ILogger<UserManager> logger,
IUserDao userDao,
IPasswordStrength passwordStrength,
IPasswordProcess passwordProcess,
IEventManager eventManager,
IUserImageManager userImageManager,
IAccountDao accountDao,
IGeneralManager generalManager,
IAccountTransactionsSettings settings)
{
_logger = logger;
_userDao = userDao;
_passwordStrength = passwordStrength;
_passwordProcess = passwordProcess;
_eventManager = eventManager;
this._userImageManager = userImageManager;
this._generalManager = generalManager;
_accountDao = accountDao ?? throw new ArgumentNullException(nameof(accountDao));
if (settings != null) _settings = settings;
}
public async Task<User> CreateUser(CreateUserArgs args)
{
var userInfo = await _userDao.CreateUser(args, _passwordProcess.Generate(args.Password).ToFlatString(), _settings == null ? 0 : _settings.NewUserFreeCreditAmount);
await _eventManager.FireЕvent(this, EventAction.UserCreated, userInfo.user);
return userInfo.user;
}
public async Task<bool> UserExists(string userName)
{
return await _userDao.UserNameExists(userName, null);
}
public async Task<User> UpdateUserSucsess(long userId)
{
return await _userDao.UpdateUserSucsess(userId);
}
public async Task<bool> UserEmailExists(string email)
{
return await _userDao.UserEmailExists(email);
}
public async Task<bool> UserNameExists(string userName, long? userId)
{
return await _userDao.UserNameExists(userName, userId);
}
public async Task<IEnumerable<User>> GetUsers(long? userId = null, UserType? userType = null)
{
return await _userDao.GetUsers(userId, (byte?)userType);
}
public async Task<User> GetUser(long userId)
{
return await _userDao.GetUser(userId);
}
public async Task<User> GetUserByEmail(string email)
{
return await _userDao.GetUserByEmail(email);
}
public async Task<User> AuthenticateUser(int apiConsumerId, string email, string password)
{
_logger.LogDebug($"AuthenticateUser: email='{email}'");
var obj = await _userDao.GetUserCredential(apiConsumerId, email);
if (obj == null) return null; //User is not exists
var savedPasswordResult = new PasswordResult(obj.Password);
var userPasswordResult = _passwordProcess.Generate(password, savedPasswordResult.Salt);
return userPasswordResult.IsIdentical(savedPasswordResult) ? obj.User : null;
}
public async Task<User> UpdateUser(UpdateUserArgs args)
{
_logger.LogDebug($"Update user: apiConsumerId={args.ApiConsumerId}, email='{args.Email}'");
//if (await AuthenticateUser(args.ApiConsumerId, args.Email, args.Password) == null)
//{
// throw new InvalidOperationException("Invalid password for confirm");
//}
System.IO.Stream stream = args.Content != null && args.Content.Length > 0 ? new System.IO.MemoryStream(args.Content) :
!string.IsNullOrEmpty(args.ContentBase64) ? Framework.Extentions.FileInfoExtentions.ParseImage(args.ContentBase64) : null;
args.HasAvatar = args.HasAvatar || stream != null;
var user = await _userDao.UpdateUser(args);
if (stream != null)
{
try
{
await _userImageManager.SaveAvatar(user.UserId, stream);
}
catch {
args.HasAvatar = false;
user = await _userDao.UpdateUser(args);
}
}
if (user.HasAvatar.HasValue && user.HasAvatar.Value)
{
user.AvatarUrl = _generalManager.GetAvatarUrl(user.UserId);
}
return user;
}
public FileResponse GetAvatarFile(int userId)
{
DateTimeOffset modified;
var stream = _userImageManager.LoadAvatar((long)userId, out modified);
return new FileResponse() { File = stream, FileDownloadName = "avatar.png", LastModified = modified };
}
public async Task<UserAccounts> GetUserInfo(string accountWalletAddress)
{
_logger.LogDebug($"Get User Info for wallet address: {accountWalletAddress}");
if (accountWalletAddress == PlatformUserAccount.WalletAddress)
{
return new UserAccounts
{
Accounts = new List<Account>() {PlatformUserAccount},
User = PlatformUser
};
}
return await _userDao.GetUserInfo(accountWalletAddress);
}
public async Task Initialize()
{
var platformUserList = await _userDao.GetUsers(userType: (byte)UserType.Platform);
if (platformUserList.Count() != 1)
throw new InvalidOperationException($"Wrong number of platform users: {platformUserList.Count()}");
PlatformUser = platformUserList.First();
var platformUserAccount = await _accountDao.GetUserAccounts(PlatformUser.UserId);
if (!platformUserAccount.Accounts.Any())
throw new InvalidOperationException("Platform user must have at least one account");
PlatformUserAccount = platformUserAccount.Accounts.First();
}
public async Task<bool> CheckPasswordResetToken(string token)
{
return await _userDao.CheckPasswordResetToken(token);
}
public async Task SendPasswordResetLink(string email, string link)
{
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
byte[] bytes = new byte[8];
rng.GetBytes(bytes);
string token = Convert.ToBase64String(bytes);
await _userDao.SendPasswordResetLink(email, token);
await _eventManager.FireЕvent(this, EventAction.ResetPassword, new UserPasswordReset() { Email = email, Link = $"{link}/{WebUtility.UrlEncode(token)}"});
await Task.CompletedTask;
}
}
public async Task<bool> PasswordReset(string token, string newPassword)
{
return await _userDao.PasswordReset(token, _passwordProcess.Generate(newPassword).ToFlatString());
}
}
}