chore: deleted all the stuff we don't need here
This commit is contained in:
@@ -1,486 +0,0 @@
|
||||
using GamificationService.Models.BasicResponses;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Services.JWT;
|
||||
using GamificationService.Services.NotificationService;
|
||||
using GamificationService.Utils;
|
||||
using GamificationService.Utils.Factory;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class AuthController : ControllerBase
|
||||
{
|
||||
#region Services
|
||||
|
||||
private readonly ILogger<AuthController> _logger;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
private readonly IJwtService _jwtService;
|
||||
private readonly INotificationService _notificationService;
|
||||
private readonly MailNotificationsFactory _mailNotificationsFactory;
|
||||
private readonly PushNotificationsFactory _pushNotificationsFactory;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public AuthController(ILogger<AuthController> logger, UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IJwtService jwtService, INotificationService notificationService, MailNotificationsFactory mailNotificationsFactory, PushNotificationsFactory pushNotificationsFactory)
|
||||
{
|
||||
_logger = logger;
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
_jwtService = jwtService;
|
||||
_notificationService = notificationService;
|
||||
_mailNotificationsFactory = mailNotificationsFactory;
|
||||
_pushNotificationsFactory = pushNotificationsFactory;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
#region Auth
|
||||
|
||||
/// <summary>
|
||||
/// Handles user registration.
|
||||
/// </summary>
|
||||
/// <param name="model">The registration model.</param>
|
||||
/// <returns>A response indicating the result of the registration.</returns>
|
||||
[HttpPost("register")]
|
||||
public async Task<IActionResult> Register([FromBody] AuthDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = new ApplicationUser()
|
||||
{
|
||||
UserName = model.Username,
|
||||
Email = model.Email,
|
||||
TwoFactorEnabled = false,
|
||||
TwoFactorProviders = new List<TwoFactorProvider>() { TwoFactorProvider.NONE }
|
||||
};
|
||||
|
||||
var result = await _userManager.CreateAsync(user, model.Password);
|
||||
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
_logger.LogError("User registration failed: {Errors}", result.Errors);
|
||||
return BadRequest(new BasicResponse
|
||||
{
|
||||
Code = 400,
|
||||
Message = "User registration failed"
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogInformation("User registered successfully: {Username}", model.Username);
|
||||
return Ok(new BasicResponse
|
||||
{
|
||||
Code = 200,
|
||||
Message = "User created successfully"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred during user registration: {Message}", ex.Message);
|
||||
return StatusCode(500, new BasicResponse
|
||||
{
|
||||
Code = 500,
|
||||
Message = "An error occurred during user registration"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles user login.
|
||||
/// </summary>
|
||||
/// <param name="model">The login model.</param>
|
||||
/// <returns>A response indicating the result of the login.</returns>
|
||||
[HttpPost("login")]
|
||||
public async Task<IActionResult> Login([FromBody] AuthDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(model.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogError("Invalid username or password");
|
||||
return NotFound(new BasicResponse
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Invalid username or password"
|
||||
});
|
||||
}
|
||||
var result = await _signInManager.PasswordSignInAsync( user, model.Password, false, model.RememberMe);
|
||||
|
||||
if (result.Succeeded & !result.RequiresTwoFactor)
|
||||
{
|
||||
var refreshToken = await _jwtService.GenerateRefreshTokenAsync(user);
|
||||
var accessToken = _jwtService.GenerateAccessToken(user);
|
||||
_logger.LogInformation("User logged in successfully: {Username}", model.Username);
|
||||
|
||||
return Ok(new LoginResultResponse()
|
||||
{
|
||||
RequiresTwoFactorAuth = false,
|
||||
Success = true,
|
||||
Token = new RefreshTokenDTO()
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
RefreshToken = refreshToken.Token
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(result.RequiresTwoFactor)
|
||||
{
|
||||
var providerWithMaxWeight = user.TwoFactorProviders
|
||||
.OrderByDescending(p => (int)p)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (providerWithMaxWeight == TwoFactorProvider.NONE)
|
||||
{
|
||||
_logger.LogInformation("User {Username} does not have any two-factor authentication enabled", model.Username);
|
||||
return StatusCode(418, new LoginResultResponse()
|
||||
{
|
||||
RequiresTwoFactorAuth = false,
|
||||
Success = true,
|
||||
TwoFactorProvider = (int)providerWithMaxWeight
|
||||
});
|
||||
}
|
||||
|
||||
var code = await _userManager.GenerateTwoFactorTokenAsync(user, providerWithMaxWeight.ToString());
|
||||
await SendNotificationAsync(user, "Two-factor authentication code", code, NotificationInformationType.AUTH,providerWithMaxWeight);
|
||||
_logger.LogInformation("Two-factor authentication required for user {Username}", model.Username);
|
||||
return Ok(new LoginResultResponse()
|
||||
{
|
||||
RequiresTwoFactorAuth = true,
|
||||
Success = true
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogError("Invalid username or password");
|
||||
return BadRequest(new BasicResponse
|
||||
{
|
||||
Code = 400,
|
||||
Message = "Invalid username or password"
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred during user login: {Message}", ex.Message);
|
||||
return StatusCode(500, new BasicResponse
|
||||
{
|
||||
Code = 500,
|
||||
Message = "An error occurred during user login"
|
||||
});
|
||||
}
|
||||
}
|
||||
[HttpPost("logout")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> Logout()
|
||||
{
|
||||
await _signInManager.SignOutAsync();
|
||||
return Ok("Logged out successfully");
|
||||
}
|
||||
|
||||
[HttpPost("revoke-token")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> RevokeToken()
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound("User not found");
|
||||
}
|
||||
|
||||
await _jwtService.RevokeRefreshTokenAsync(user.Id, HttpContext.Request.Cookies["refresh_token"],GetRemoteIpAddress());
|
||||
return Ok("Token revoked successfully");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Email
|
||||
|
||||
[HttpGet("{username}/init-email-verification")]
|
||||
public async Task<IActionResult> VerifyEmail(string username)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(username);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogError("Invalid username or password");
|
||||
return NotFound(new BasicResponse
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Invalid username or password"
|
||||
});
|
||||
}
|
||||
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
await SendNotificationAsync(user, "Email verification code", code, NotificationInformationType.AUTH, TwoFactorProvider.EMAIL);
|
||||
_logger.LogInformation("Email verification code sent to user {Username}", username);
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Email verification code sent"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "An error occurred during email verification: {Message}", e.Message);
|
||||
return StatusCode(500, new BasicResponse
|
||||
{
|
||||
Code = 500,
|
||||
Message = "An error occurred during email verification"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{username}/verify-email/{code}")]
|
||||
public async Task<IActionResult> VerifyEmail(string username, string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(username);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogError("Invalid username or password");
|
||||
return NotFound(new BasicResponse
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Invalid username or password"
|
||||
});
|
||||
}
|
||||
|
||||
var result = await _userManager.ConfirmEmailAsync(user,code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
_logger.LogInformation("Email verified for user {Username}", username);
|
||||
user.EmailConfirmed = true;
|
||||
await _userManager.UpdateAsync(user);
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Email verified"
|
||||
});
|
||||
}
|
||||
return BadRequest(new BasicResponse()
|
||||
{
|
||||
Code = 400,
|
||||
Message = "Email verification failed"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "An error occurred during email verification: {Message}", e.Message);
|
||||
return StatusCode(500, new BasicResponse
|
||||
{
|
||||
Code = 500,
|
||||
Message = "An error occurred during email verification"
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 2FA
|
||||
|
||||
[HttpPost("get-2fa-code")]
|
||||
public async Task<IActionResult> GetTwoFactorCode([FromBody] GetTwoFactorDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(model.Username);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogError("Invalid username or password");
|
||||
return NotFound(new BasicResponse
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Invalid username or password"
|
||||
});
|
||||
}
|
||||
|
||||
var providerWithRequiredWeight = user.TwoFactorProviders
|
||||
.FirstOrDefault(p => (int)p == model.TwoFactorProvider);
|
||||
var code = await _userManager.GenerateTwoFactorTokenAsync(user, providerWithRequiredWeight.ToString());
|
||||
await SendNotificationAsync(user, "Two-factor authentication code", code, NotificationInformationType.AUTH,providerWithRequiredWeight);
|
||||
_logger.LogInformation("Two-factor authentication code sent to user {Username}", model.Username);
|
||||
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Code sent successfully"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to send code"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("verify-2fa")]
|
||||
public async Task<IActionResult> VerifyTwoFactorCode([FromBody] TwoFactorDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (model.Username != null)
|
||||
{
|
||||
var user = await _userManager.FindByNameAsync(model.Username);
|
||||
var providerWithRequiredWeight = user.TwoFactorProviders
|
||||
.FirstOrDefault(p => (int)p == model.TwoFactorProvider);
|
||||
var signInResult = _signInManager.TwoFactorSignInAsync(providerWithRequiredWeight.ToString(),
|
||||
model.Code, false, model.RememberMe);
|
||||
|
||||
|
||||
if (!signInResult.Result.Succeeded)
|
||||
{
|
||||
return BadRequest(new BasicResponse()
|
||||
{
|
||||
Code = 400,
|
||||
Message = "Invalid code"
|
||||
});
|
||||
}
|
||||
|
||||
var token = _jwtService.GenerateAccessToken(user);
|
||||
var refreshToken = await _jwtService.GenerateRefreshTokenAsync(user);
|
||||
|
||||
_logger.LogInformation("User logged in successfully: {Username}", model.Username);
|
||||
await SendNotificationAsync(user, "Login successful", "You have successfully logged in", NotificationInformationType.WARNING,TwoFactorProvider.EMAIL);
|
||||
|
||||
return Ok( new LoginResultResponse()
|
||||
{
|
||||
RequiresTwoFactorAuth = false,
|
||||
Success = true,
|
||||
Token = new RefreshTokenDTO()
|
||||
{
|
||||
AccessToken = token,
|
||||
RefreshToken = refreshToken.Token
|
||||
}
|
||||
});
|
||||
}
|
||||
_logger.LogError("Username can't be empty");
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Username can't be empty"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred during user verification: {Message}", ex.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "An error occurred during user verification"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("enable-2fa")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> EnableTwoFactor([FromBody]EnableTwoFactorDTO model)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "User not found"
|
||||
});
|
||||
}
|
||||
|
||||
user.TwoFactorProviders.Add((TwoFactorProvider)model.TwoFactorProvider);
|
||||
user.TwoFactorEnabled = true;
|
||||
await _userManager.UpdateAsync(user);
|
||||
var secretKey = await _userManager.GenerateTwoFactorTokenAsync(user, TwoFactorProvider.AUTHENTICATOR.ToString());
|
||||
_logger.LogInformation("User logged in successfully: {Username}", User);
|
||||
await SendNotificationAsync(user, "Login successful", "You have successfully logged in", NotificationInformationType.WARNING,(TwoFactorProvider)model.TwoFactorProvider);
|
||||
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Two-factor authentication enabled successfully"
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("disable-2fa")]
|
||||
[Authorize]
|
||||
public async Task<IActionResult> DisableTwoFactor([FromBody] DisableTwoFactorDTO model)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound("User not found");
|
||||
}
|
||||
|
||||
if (!await _userManager.VerifyTwoFactorTokenAsync(user,model.TwoFactorProvider.ToString(),model.Code))
|
||||
{
|
||||
return BadRequest("Invalid verification code");
|
||||
}
|
||||
|
||||
user.TwoFactorEnabled = false;
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
return Ok("Two-factor authentication disabled");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
|
||||
private async Task SendNotificationAsync(ApplicationUser user,
|
||||
string title,
|
||||
string message,
|
||||
NotificationInformationType notificationInformationType,
|
||||
TwoFactorProvider provider)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (provider)
|
||||
{
|
||||
case TwoFactorProvider.EMAIL:
|
||||
await _notificationService.SendMailNotificationAsync(user, _mailNotificationsFactory.CreateNotification(notificationInformationType, title, message));
|
||||
break;
|
||||
case TwoFactorProvider.PHONE:
|
||||
throw new NotImplementedException();
|
||||
break;
|
||||
case TwoFactorProvider.PUSH:
|
||||
await _notificationService.SendPushNotificationAsync(user, _pushNotificationsFactory.CreateNotification(notificationInformationType, title, message));
|
||||
break;
|
||||
case TwoFactorProvider.AUTHENTICATOR:
|
||||
throw new NotImplementedException();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred during notification: {Message}", ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetRemoteIpAddress()
|
||||
{
|
||||
if (HttpContext.Connection.RemoteIpAddress != null)
|
||||
{
|
||||
return HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
using GamificationService.Models.BasicResponses;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Services.Rights;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public class RightsController : ControllerBase
|
||||
{
|
||||
#region Services
|
||||
|
||||
private readonly IRightsService _rightsService;
|
||||
private readonly ILogger<RightsController> _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RightsController(IRightsService rightsService, ILogger<RightsController> logger)
|
||||
{
|
||||
_rightsService = rightsService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAllRightsAsync([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rights, totalCount) = await _rightsService.GetAllRightsAsync(pageNumber, pageSize);
|
||||
|
||||
_logger.LogInformation($"Retrieved {rights.Count} rights");
|
||||
|
||||
var response = new GetAllRightsResponse()
|
||||
{
|
||||
Rights = rights,
|
||||
TotalCount = totalCount,
|
||||
PageNumber = pageNumber,
|
||||
PageSize = pageSize
|
||||
};
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to get rights.",
|
||||
});
|
||||
}
|
||||
}
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetRightByIdAsync(long id)
|
||||
{
|
||||
var right = await _rightsService.GetRightByIdAsync(id);
|
||||
_logger.LogInformation($"Retrieved right with id: {id}");
|
||||
if (right == null)
|
||||
{
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
|
||||
Code = 404,
|
||||
Message = "Right not found"
|
||||
|
||||
});
|
||||
}
|
||||
return Ok(right);
|
||||
}
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateRightAsync([FromBody] RightDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
var right = await _rightsService.CreateRightAsync(model.Name, model.Description);
|
||||
|
||||
_logger.LogInformation($"Created right: {right}");
|
||||
|
||||
return CreatedAtAction(nameof(CreateRightAsync), new { id = right.Id }, right);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to create right.",
|
||||
});
|
||||
}
|
||||
}
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdateRightAsync(long id, [FromBody] RightDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (await _rightsService.UpdateRightAsync(id, model.Name, model.Description))
|
||||
{
|
||||
_logger.LogInformation($"Updated right: {id}");
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Rights updated",
|
||||
});
|
||||
}
|
||||
_logger.LogError($"Unknown with right updating, {id}");
|
||||
return StatusCode(418,
|
||||
new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Failed to update right."
|
||||
});
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
_logger.LogError($"Right not found, {id} ");
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Right not found"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to update right"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> DeleteRightAsync(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
if( await _rightsService.DeleteRightAsync(id))
|
||||
{
|
||||
_logger.LogInformation($"Deleted right: {id}");
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Rights deleted",
|
||||
});
|
||||
}
|
||||
_logger.LogError($"Unknown error with right deleting, {id} ");
|
||||
return StatusCode(418, new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Failed to delete right"
|
||||
});
|
||||
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
_logger.LogError($"Role not found, {id} ");
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Right not found"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to delete right"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
using GamificationService.Models.BasicResponses;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Services.Roles;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http.HttpResults;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public class RoleController : ControllerBase
|
||||
{
|
||||
#region Services
|
||||
|
||||
private readonly IRolesService _rolesService;
|
||||
private readonly ILogger<RoleController> _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RoleController(ILogger<RoleController> logger, IRolesService rolesService)
|
||||
{
|
||||
_logger = logger;
|
||||
_rolesService = rolesService;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ControllerMethods
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAllRolesAsync([FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 10)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (roles, totalCount) = await _rolesService.GetAllRolesAsync(pageNumber, pageSize);
|
||||
_logger.LogInformation($"Roles found successfully, {roles.Count}");
|
||||
var response = new GetAllRolesResponse()
|
||||
{
|
||||
Roles = roles,
|
||||
TotalCount = totalCount,
|
||||
PageNumber = pageNumber,
|
||||
PageSize = pageSize
|
||||
};
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex,ex.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to get roles"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> GetRoleByIdAsync(long id)
|
||||
{
|
||||
var role = await _rolesService.GetRoleByIdAsync(id);
|
||||
_logger.LogInformation($"Role found successfully, {role.Id}");
|
||||
if (role == null)
|
||||
{
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
|
||||
Code = 404,
|
||||
Message = "Role not found"
|
||||
|
||||
});
|
||||
}
|
||||
return Ok(role);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> CreateRoleAsync([FromBody] RoleDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var role = await _rolesService.CreateRoleAsync(model.Name, model.Description);
|
||||
_logger.LogInformation($"Role created successfully, {role.Id}");
|
||||
return CreatedAtAction(nameof(CreateRoleAsync), new { id = role.Id }, role);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to create role"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> UpdateRoleAsync(long id, [FromBody] RoleDTO model)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (await _rolesService.UpdateRoleAsync(id, model.Name, model.Description))
|
||||
{
|
||||
_logger.LogInformation($"Role updated successfully, {id}");
|
||||
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Role updated successfully"
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogCritical($"Unknown error with role updating, {id}");
|
||||
return StatusCode(418,new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Role not found"
|
||||
});
|
||||
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
_logger.LogError($"Role not found, {id} ");
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Role not found"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to update role"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<IActionResult> DeleteRoleAsync(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (await _rolesService.DeleteRoleAsync(id))
|
||||
{
|
||||
|
||||
_logger.LogInformation($"Role updated successfully, {id}");
|
||||
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Role updated successfully"
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogCritical($"Unknown error with role deleting, RoleId {id}");
|
||||
return StatusCode(418,new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Role not found"
|
||||
});
|
||||
}
|
||||
catch (KeyNotFoundException)
|
||||
{
|
||||
_logger.LogError($"Role not found, {id} ");
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Role not found"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to delete role"
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("{roleId}/rights/{rightId}")]
|
||||
public async Task<IActionResult> AddRightToRoleAsync(long roleId, long rightId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (await _rolesService.AddRightToRoleAsync(roleId, rightId))
|
||||
{
|
||||
_logger.LogInformation($"Right added to role successfully, RoleId: {roleId}, RightId: {rightId}");
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Right added to role successfully"
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogCritical($"Unknown error with adding right to role, RoleId: {roleId}, RightId: {rightId}");
|
||||
return StatusCode(418,new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Right not found for role"
|
||||
});
|
||||
}
|
||||
catch(KeyNotFoundException e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Right not found for role"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to add right to role"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete("{roleId}/rights/{rightId}")]
|
||||
public async Task<IActionResult> RemoveRightFromRoleAsync(long roleId, long rightId)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
if (await _rolesService.RemoveRightFromRoleAsync(roleId, rightId))
|
||||
{
|
||||
_logger.LogInformation($"Right removed from role successfully, RoleId: {roleId}, RightId: {rightId}");
|
||||
|
||||
return Ok(new BasicResponse()
|
||||
{
|
||||
Code = 200,
|
||||
Message = "Right removed from role successfully"
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogCritical($"Unknown error with removing right from role, RoleId: {roleId}, RightId: {rightId}");
|
||||
return StatusCode(418, new BasicResponse()
|
||||
{
|
||||
Code = 418,
|
||||
Message = "Right not found right for role"
|
||||
});
|
||||
|
||||
}
|
||||
catch (KeyNotFoundException e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return NotFound(new BasicResponse()
|
||||
{
|
||||
Code = 404,
|
||||
Message = "Right not found for role"
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
return StatusCode(500, new BasicResponse()
|
||||
{
|
||||
Code = 500,
|
||||
Message = "Failed to remove right from role"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Exceptions.Services.ProfileService;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using GamificationService.Services.UsersProfile;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace GamificationService.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Authorize(Policy = "User")]
|
||||
[Route("api/[controller]")]
|
||||
public class UserProfileController : ControllerBase
|
||||
{
|
||||
private readonly IUserProfileService _userProfilesService;
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly ILogger<UserProfileController> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public UserProfileController(IUserProfileService userProfilesService, UserManager<ApplicationUser> userManager, ILogger<UserProfileController> logger, IMapper mapper)
|
||||
{
|
||||
_userProfilesService = userProfilesService;
|
||||
_userManager = userManager;
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user profile by its ID.
|
||||
/// </summary>
|
||||
/// <param name="username">The username of the user profile's owner.</param>
|
||||
/// <returns>An <see cref="UserProfileDTO"/> containing the user profile DTO if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the user profile DTO</response>
|
||||
/// <response code="404">If the user profile is not found</response>
|
||||
[HttpGet("user/{username}")]
|
||||
public async Task<IActionResult> GetUserProfileByUsername(string username)
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = (await _userManager.FindByNameAsync(username));
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var userProfile = _userProfilesService.GetUserProfileByUserId(user.Id);
|
||||
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user profile by its ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the user profile.</param>
|
||||
/// <returns>An <see cref="UserProfileDTO"/> containing the user profile DTO if found, or a 404 Not Found if not found.</returns>
|
||||
/// <response code="200">Returns the user profile DTO</response>
|
||||
/// <response code="404">If the user profile is not found</response>
|
||||
[HttpGet("{id}")]
|
||||
public IActionResult GetUserProfileById(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userProfile = _userProfilesService.GetUserProfileById(id);
|
||||
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new user profile.
|
||||
/// </summary>
|
||||
/// <param name="username">The username of the user.</param>
|
||||
/// <param name="model">The user profile model.</param>
|
||||
/// <returns>A <see cref="UserProfileDTO"/> containing the created user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||
/// <response code="200">Returns the created user profile</response>
|
||||
/// <response code="404">If the user is not found</response>
|
||||
[HttpPost("user/{username}")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public async Task<IActionResult> AddUserProfile(string username, [FromBody] UserProfileCreateDTO model)
|
||||
{
|
||||
var user = (await _userManager.FindByNameAsync(username));
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var userProfile = await _userProfilesService.AddUserProfile(user.Id, model);
|
||||
return Ok(_mapper.Map<UserProfileDTO>(userProfile));
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update user profile for the logged in user.
|
||||
/// </summary>
|
||||
/// <param name="model">The user profile model.</param>
|
||||
/// <returns>A <see cref="UserProfileDTO"/> containing the updated user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||
/// <response code="200">Returns the updated user profile</response>
|
||||
/// <response code="404">If the user profile is not found</response>
|
||||
[HttpPut]
|
||||
public async Task<IActionResult> UpdateUserProfile([FromBody] UserProfileCreateDTO model)
|
||||
{
|
||||
string username = User.Claims.First(c => c.Type == "username").Value;
|
||||
long userId = (await _userManager.FindByNameAsync(username))!.Id;
|
||||
|
||||
try
|
||||
{
|
||||
bool result = await _userProfilesService.UpdateUserProfileByUserId(userId, model);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates an existing user profile.
|
||||
/// </summary>
|
||||
/// <param name="username">The username of the user.</param>
|
||||
/// <param name="model">The user profile model.</param>
|
||||
/// <returns>A <see cref="UserProfileDTO"/> containing the updated user profile if successful, or a 500 Internal Server Error if not successful.</returns>
|
||||
/// <response code="200">Returns the updated user profile</response>
|
||||
/// <response code="404">If the user profile is not found</response>
|
||||
[HttpPut]
|
||||
[Authorize(Policy = "Admin")]
|
||||
[Route("user/{userId}")]
|
||||
public async Task<IActionResult> UpdateUserProfileByUsername(string username, [FromBody] UserProfileCreateDTO model)
|
||||
{
|
||||
var user = (await _userManager.FindByNameAsync(username));
|
||||
if (user == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool result = await _userProfilesService.UpdateUserProfileByUserId(user.Id, model);
|
||||
return Ok(result);
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes an existing user profile.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the user profile to delete.</param>
|
||||
/// <returns>A <see cref="bool"/></returns>
|
||||
/// <response code="200">Returns true.</response>
|
||||
/// <response code="404">If the user profile is not found</response>
|
||||
[HttpDelete("{id}")]
|
||||
[Authorize(Policy = "Admin")]
|
||||
public IActionResult DeleteUserProfile(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
_userProfilesService.DeleteUserProfile(id);
|
||||
return Ok();
|
||||
}
|
||||
catch (ProfileNotFoundException)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,32 +1,16 @@
|
||||
using GamificationService.Models.Database;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GamificationService.Database;
|
||||
|
||||
|
||||
public class ApplicationContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
|
||||
public class ApplicationContext : DbContext
|
||||
{
|
||||
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public DbSet<Right> Rights { get; set; }
|
||||
public DbSet<RefreshToken> RefreshTokens { get; set; }
|
||||
public DbSet<ApplicationUser> Users { get; set; }
|
||||
public DbSet<ApplicationRole> Roles { get; set; }
|
||||
public DbSet<UserRole> UserRoles { get; set; }
|
||||
public DbSet<RoleRight> RoleRights { get; set; }
|
||||
public DbSet<UserProfile> UserProfiles { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
modelBuilder.Entity<UserRole>()
|
||||
.HasKey(ur => new { ur.UserId, ur.RoleId });
|
||||
|
||||
modelBuilder.Entity<RoleRight>()
|
||||
.HasKey(rr => new { rr.RoleId, rr.RightId });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,5 @@
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Services.CurrentUsers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
|
||||
namespace GamificationService.Database.Extensions;
|
||||
|
||||
public static class ChangeTrackerExtensions
|
||||
{
|
||||
public static void SetAuditProperties(this ChangeTracker changeTracker, ICurrentUserService currentUserService)
|
||||
{
|
||||
changeTracker.DetectChanges();
|
||||
IEnumerable<EntityEntry> entities =
|
||||
changeTracker
|
||||
.Entries()
|
||||
.Where(t => t.Entity is AuditableEntity &&
|
||||
(
|
||||
t.State == EntityState.Deleted
|
||||
|| t.State == EntityState.Added
|
||||
|| t.State == EntityState.Modified
|
||||
));
|
||||
|
||||
if (entities.Any())
|
||||
{
|
||||
DateTimeOffset timestamp = DateTimeOffset.UtcNow;
|
||||
|
||||
string user = currentUserService.GetCurrentUser().Login ?? "Unknown";
|
||||
|
||||
foreach (EntityEntry entry in entities)
|
||||
{
|
||||
AuditableEntity entity = (AuditableEntity)entry.Entity;
|
||||
|
||||
switch (entry.State)
|
||||
{
|
||||
case EntityState.Added:
|
||||
entity.CreatedOn = timestamp;
|
||||
entity.CreatedBy = user;
|
||||
entity.UpdatedOn = timestamp;
|
||||
entity.UpdatedBy = user;
|
||||
break;
|
||||
case EntityState.Modified:
|
||||
entity.UpdatedOn = timestamp;
|
||||
entity.UpdatedBy = user;
|
||||
break;
|
||||
case EntityState.Deleted:
|
||||
entity.UpdatedOn = timestamp;
|
||||
entity.UpdatedBy = user;
|
||||
entry.State = EntityState.Deleted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using GamificationService.Models.Database;
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
|
||||
namespace GamificationService.Database.Repositories;
|
||||
@@ -8,12 +7,6 @@ public class UnitOfWork : IDisposable
|
||||
#region fields
|
||||
|
||||
private ApplicationContext _context;
|
||||
private GenericRepository<UserProfile> _userProfileRepository;
|
||||
private GenericRepository<ApplicationRole> _roleRepository;
|
||||
private GenericRepository<Right?> _rightRepository;
|
||||
private GenericRepository<RefreshToken> _refreshTokenRepository;
|
||||
private GenericRepository<RoleRight> _roleRightRepository;
|
||||
private GenericRepository<UserRole> _userRoleRepository;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -28,78 +21,6 @@ public class UnitOfWork : IDisposable
|
||||
|
||||
#region Properties
|
||||
|
||||
public GenericRepository<UserProfile> UserProfileRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._userProfileRepository == null)
|
||||
{
|
||||
this._userProfileRepository = new GenericRepository<UserProfile>(_context);
|
||||
}
|
||||
return _userProfileRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<ApplicationRole> RoleRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._roleRepository == null)
|
||||
{
|
||||
this._roleRepository = new GenericRepository<ApplicationRole>(_context);
|
||||
}
|
||||
return _roleRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<Right?> RightRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._rightRepository == null)
|
||||
{
|
||||
this._rightRepository = new GenericRepository<Right?>(_context);
|
||||
}
|
||||
return _rightRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<RefreshToken> RefreshTokenRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._refreshTokenRepository == null)
|
||||
{
|
||||
this._refreshTokenRepository = new GenericRepository<RefreshToken>(_context);
|
||||
}
|
||||
return _refreshTokenRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<RoleRight> RoleRightRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._roleRightRepository == null)
|
||||
{
|
||||
this._roleRightRepository = new GenericRepository<RoleRight>(_context);
|
||||
}
|
||||
return _roleRightRepository;
|
||||
}
|
||||
}
|
||||
|
||||
public GenericRepository<UserRole> UserRoleRepository
|
||||
{
|
||||
get
|
||||
{
|
||||
if (this._userRoleRepository == null)
|
||||
{
|
||||
this._userRoleRepository = new GenericRepository<UserRole>(_context);
|
||||
}
|
||||
return _userRoleRepository;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool Save()
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.AuthService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception related to authentication service operations.
|
||||
/// </summary>
|
||||
public class AuthServiceException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthServiceException"/> class.
|
||||
/// </summary>
|
||||
public AuthServiceException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthServiceException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public AuthServiceException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AuthServiceException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public AuthServiceException(string message, Exception innerException) : base(message, innerException) { }
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.JwtService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception related to jwt token service operations.
|
||||
/// </summary>
|
||||
public class GenerateRefreshTokenException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="enerateRefreshTokenException"/> class.
|
||||
/// </summary>
|
||||
public GenerateRefreshTokenException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenerateRefreshTokenException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public GenerateRefreshTokenException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GenerateRefreshTokenException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public GenerateRefreshTokenException(string message, Exception innerException) : base(message, innerException) { }
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.JwtService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception related to jwt token service operations.
|
||||
/// </summary>
|
||||
public class JwtServiceException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JwtServiceException"/> class.
|
||||
/// </summary>
|
||||
public JwtServiceException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JwtServiceException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public JwtServiceException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="JwtServiceException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public JwtServiceException(string message, Exception innerException) : base(message, innerException) { }
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs during profile creation operations.
|
||||
/// </summary>
|
||||
public class ProfileCreationException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class.
|
||||
/// </summary>
|
||||
public ProfileCreationException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public ProfileCreationException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileCreationException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public ProfileCreationException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs during profile deletion operations.
|
||||
/// </summary>
|
||||
public class ProfileDeletionException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class.
|
||||
/// </summary>
|
||||
public ProfileDeletionException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public ProfileDeletionException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileDeletionException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public ProfileDeletionException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs when a profile already exists.
|
||||
/// </summary>
|
||||
public class ProfileExistsException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class.
|
||||
/// </summary>
|
||||
public ProfileExistsException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public ProfileExistsException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileExistsException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public ProfileExistsException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs when a profile is not found.
|
||||
/// </summary>
|
||||
public class ProfileNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class.
|
||||
/// </summary>
|
||||
public ProfileNotFoundException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public ProfileNotFoundException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileNotFoundException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public ProfileNotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
namespace GamificationService.Exceptions.Services.ProfileService;
|
||||
|
||||
/// <summary>
|
||||
/// Represents an exception that occurs during profile update operations.
|
||||
/// </summary>
|
||||
public class ProfileUpdateException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class.
|
||||
/// </summary>
|
||||
public ProfileUpdateException() : base() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class with a specified error message.
|
||||
/// </summary>
|
||||
/// <param name="message">The message that describes the error.</param>
|
||||
public ProfileUpdateException(string message) : base(message) { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileUpdateException"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.
|
||||
/// </summary>
|
||||
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference if no inner exception is specified.</param>
|
||||
public ProfileUpdateException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
|
||||
@@ -6,14 +6,6 @@ using GamificationService.Database;
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Logs;
|
||||
using GamificationService.Mapper;
|
||||
using GamificationService.Services.Cookies;
|
||||
using GamificationService.Services.CurrentUsers;
|
||||
using GamificationService.Services.JWT;
|
||||
using GamificationService.Services.NotificationService;
|
||||
using GamificationService.Services.Rights;
|
||||
using GamificationService.Services.Roles;
|
||||
using GamificationService.Utils;
|
||||
using GamificationService.Utils.Factory;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
@@ -135,56 +127,6 @@ public static class UtilServicesExtensions
|
||||
{
|
||||
public static IServiceCollection AddUtilServices(this IServiceCollection services)
|
||||
{
|
||||
services.AddScoped<IJwtService, JwtService>();
|
||||
services.AddScoped<ICookieService, CookieService>();
|
||||
services.AddScoped<INotificationService,NotificationService>();
|
||||
services.AddScoped<IRightsService,RightsService>();
|
||||
services.AddScoped<IRolesService, RolesService>();
|
||||
services.AddScoped<ICurrentUserService, CurrentUserService>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NotificationSettings
|
||||
{
|
||||
public static IServiceCollection AddPushNotifications(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var notificationSettings = configuration.GetSection("NotificationSettings");
|
||||
var apiKey = notificationSettings["ApiKey"];
|
||||
var token = notificationSettings["Token"];
|
||||
var baseUrl = notificationSettings["Url"];
|
||||
var projectId = notificationSettings["ProjectId"];
|
||||
|
||||
HttpClient client = new HttpClient();
|
||||
client.BaseAddress = new Uri(baseUrl);
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
|
||||
|
||||
services.AddSingleton(provider =>
|
||||
{
|
||||
var logger = provider.GetRequiredService<ILogger<PushNotificationsClient>>();
|
||||
return new PushNotificationsClient(client, logger, token, projectId);
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
public static class EmailExtensions
|
||||
{
|
||||
public static IServiceCollection AddEmail(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var smtpSettings = configuration.GetSection("EmailSettings");
|
||||
var host = smtpSettings["Host"] ?? "localhost";
|
||||
var port = Convert.ToInt32(smtpSettings["Port"] ?? "25");
|
||||
var username = smtpSettings["Username"] ?? "username";
|
||||
var password = smtpSettings["Password"] ?? "password";
|
||||
var email = smtpSettings["EmailFrom"] ?? "email";
|
||||
services.AddScoped<SmtpClient>(sp => new SmtpClient(host)
|
||||
{
|
||||
Port = port,
|
||||
Credentials = new NetworkCredential(username, password),
|
||||
EnableSsl = true,
|
||||
});
|
||||
|
||||
services.AddSingleton<EmailClient>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -193,8 +135,6 @@ public static class FactoryExtensions
|
||||
{
|
||||
public static IServiceCollection AddFactories(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<MailNotificationsFactory>();
|
||||
services.AddSingleton<PushNotificationsFactory>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Mapper;
|
||||
|
||||
|
||||
@@ -9,43 +6,5 @@ public class MappingProfile : Profile
|
||||
{
|
||||
public MappingProfile()
|
||||
{
|
||||
#region UserProfileMapping
|
||||
|
||||
CreateMap<UserProfile, UserProfileDTO>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||
|
||||
CreateMap<UserProfileDTO, UserProfile>()
|
||||
.ForMember(x => x.Id, opt => opt.MapFrom(src => src.Id))
|
||||
.ForMember(x => x.UserId, opt => opt.MapFrom(src => src.UserId))
|
||||
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||
|
||||
CreateMap<UserProfileCreateDTO, UserProfile>()
|
||||
.ForMember(x => x.Name, opt => opt.MapFrom(src => src.Name))
|
||||
.ForMember(x => x.Surname, opt => opt.MapFrom(src => src.Surname))
|
||||
.ForMember(x => x.Patronymic, opt => opt.MapFrom(src => src.Patronymic))
|
||||
.ForMember(x => x.Birthdate, opt => opt.MapFrom(src => src.Birthdate))
|
||||
.ForMember(x => x.Gender, opt => opt.MapFrom(src => src.Gender))
|
||||
.ForMember(x => x.ContactEmail, opt => opt.MapFrom(src => src.ContactEmail))
|
||||
.ForMember(x => x.ContactPhone, opt => opt.MapFrom(src => src.ContactPhone))
|
||||
.ForMember(x => x.ProfilePicture, opt => opt.MapFrom(src => src.ProfilePicture));
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class AuthDTO
|
||||
{
|
||||
[Required]
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||
public string Username { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[EmailAddress(ErrorMessage = "Invalid email address")]
|
||||
public string Email { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[StringLength(100, MinimumLength = 8, ErrorMessage = "Password must be between 8 and 100 characters")]
|
||||
public string Password { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class DisableTwoFactorDTO
|
||||
{
|
||||
public int TwoFactorProvider { get; set; }
|
||||
public string Code { get; set; }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class EnableTwoFactorDTO
|
||||
{
|
||||
public int TwoFactorProvider { get; set; }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class GetAllRightsResponse
|
||||
{
|
||||
public List<Right> Rights { get; set; }
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class GetAllRolesResponse
|
||||
{
|
||||
public List<ApplicationRole> Roles { get; set; }
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class GetTwoFactorDTO
|
||||
{
|
||||
[Required]
|
||||
public int TwoFactorProvider { get; set; }
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||
public string? Username { get; set; } = null!;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class LoginResultResponse
|
||||
{
|
||||
public bool? RequiresTwoFactorAuth { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public RefreshTokenDTO? Token { get; set; }
|
||||
public int? TwoFactorProvider { get; set; }
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class RefreshTokenDTO
|
||||
{
|
||||
public string AccessToken { get; set; } = null!;
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class RightDTO
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class RoleDTO
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class TwoFactorDTO
|
||||
{
|
||||
[Required]
|
||||
public int TwoFactorProvider { get; set; }
|
||||
[StringLength(50, MinimumLength = 3, ErrorMessage = "Username must be between 3 and 50 characters")]
|
||||
public string? Username { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[StringLength(6, MinimumLength = 6, ErrorMessage = "Code must be 6 characters long")]
|
||||
public string Code { get; set; } = null!;
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class UserProfileCreateDTO
|
||||
{
|
||||
[Required(ErrorMessage = "Name is required")]
|
||||
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Surname is required")]
|
||||
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||
public string Surname { get; set; } = null!;
|
||||
|
||||
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||
public string? Patronymic { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Birthdate is required")]
|
||||
public DateTime Birthdate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Gender is required")]
|
||||
public Gender Gender { get; set; }
|
||||
|
||||
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||
public string? ContactEmail { get; set; }
|
||||
|
||||
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||
public string? ContactPhone { get; set; }
|
||||
|
||||
[Url(ErrorMessage = "Invalid avatar url")]
|
||||
public string? ProfilePicture { get; set; }
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.DTO;
|
||||
|
||||
public class UserProfileDTO
|
||||
{
|
||||
public long? Id { get; set; }
|
||||
|
||||
public long? UserId { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Name is required")]
|
||||
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Surname is required")]
|
||||
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||
public string Surname { get; set; } = null!;
|
||||
|
||||
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||
public string? Patronymic { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Birthdate is required")]
|
||||
public DateTime Birthdate { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Gender is required")]
|
||||
public Gender Gender { get; set; }
|
||||
|
||||
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||
public string? ContactEmail { get; set; }
|
||||
|
||||
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||
public string? ContactPhone { get; set; }
|
||||
|
||||
[Url(ErrorMessage = "Invalid avatar url")]
|
||||
public string? ProfilePicture { get; set; }
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
|
||||
public class ApplicationRole : IdentityRole<long>
|
||||
{
|
||||
public ApplicationRole() : base() { }
|
||||
public ApplicationRole(string roleName) : base(roleName) { }
|
||||
public string? Description { get; set; }
|
||||
|
||||
public List<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||
public List<RoleRight> RoleRights { get; set; } = new List<RoleRight>();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class ApplicationUser : IdentityUser<long>
|
||||
{
|
||||
[Required(ErrorMessage = "Username is required")]
|
||||
[StringLength(50, ErrorMessage = "Username must be less than 50 characters")]
|
||||
public string Username { get; set; } = null!;
|
||||
public bool TwoFactorEnabled { get; set; }
|
||||
public string? TwoFactorSecret { get; set; }
|
||||
public bool EmailConfirmed { get; set; }
|
||||
public List<TwoFactorProvider> TwoFactorProviders { get; set; } = new List<TwoFactorProvider>();
|
||||
public List<RefreshToken> RefreshTokens { get; set; } = new List<RefreshToken>();
|
||||
|
||||
public List<UserRole> UserRoles { get; set; } = new List<UserRole>();
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class RefreshToken
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
public long UserId { get; set; }
|
||||
public ApplicationUser User { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
public string Token { get; set; } = null!;
|
||||
|
||||
public DateTime Expires { get; set; }
|
||||
public DateTime Created { get; set; }
|
||||
public bool IsExpired => DateTime.UtcNow >= Expires;
|
||||
|
||||
public bool IsRevoked { get; set; }
|
||||
public string? RevokedByIp { get; set; }
|
||||
public DateTime? RevokedOn { get; set; }
|
||||
|
||||
public bool IsActive => !IsRevoked && !IsExpired;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class Right
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(50)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[StringLength(100)]
|
||||
public string? Description { get; set; }
|
||||
|
||||
public List<RoleRight> RoleRights { get; set; } = new List<RoleRight>();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class RoleRight
|
||||
{
|
||||
public long RoleId { get; set; }
|
||||
public ApplicationRole Role { get; set; } = null!;
|
||||
|
||||
public long RightId { get; set; }
|
||||
public Right Right { get; set; } = null!;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using GamificationService.Utils.Enums;
|
||||
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class UserProfile
|
||||
{
|
||||
[Key]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "User is required")]
|
||||
public long UserId { get; set; }
|
||||
public ApplicationUser? User { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Name is required")]
|
||||
[StringLength(100, ErrorMessage = "Name must be less than 100 characters")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Required(ErrorMessage = "Surname is required")]
|
||||
[StringLength(100, ErrorMessage = "Surname must be less than 100 characters")]
|
||||
public string Surname { get; set; } = null!;
|
||||
|
||||
[StringLength(50, ErrorMessage = "Patronymic must be less than 50 characters")]
|
||||
public string? Patronymic { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Gender is required")]
|
||||
public Gender Gender { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Birthdate is required")]
|
||||
public DateTime Birthdate { get; set; }
|
||||
|
||||
[EmailAddress(ErrorMessage = "Invalid email")]
|
||||
public string? ContactEmail { get; set; }
|
||||
|
||||
[Phone(ErrorMessage = "Invalid contact phone number")]
|
||||
public string? ContactPhone { get; set; }
|
||||
|
||||
[Url(ErrorMessage = "Invalid avatar url")]
|
||||
public string? ProfilePicture { get; set; }
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace GamificationService.Models.Database;
|
||||
|
||||
public class UserRole
|
||||
{
|
||||
public long UserId { get; set; }
|
||||
public ApplicationUser User { get; set; } = null!;
|
||||
|
||||
public long RoleId { get; set; }
|
||||
public ApplicationRole Role { get; set; } = null!;
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.UserProfiles;
|
||||
|
||||
public class CreateUserProfileRequest
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.UserProfiles;
|
||||
|
||||
public class CreateUserProfileResponse
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.UserProfiles;
|
||||
|
||||
public class UpdateUserProfileRequest
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace GamificationService.Models.Messages.UserProfiles;
|
||||
|
||||
public class UpdateUserProfileResponse
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Models;
|
||||
|
||||
public class UserSession
|
||||
{
|
||||
public string? Login { get; set; }
|
||||
public bool IsAuthenticated { get; set; }
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
using GamificationService.Exceptions.UtilServices.Cookies;
|
||||
|
||||
namespace GamificationService.Services.Cookies;
|
||||
|
||||
public class CookieService : ICookieService
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<CookieService> _logger;
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public CookieService(IHttpContextAccessor httpContextAccessor, ILogger<CookieService> logger, IConfiguration configuration)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public Task<bool> SetCookie(string key, string value, CookieOptions options)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogDebug("Adding cookie {CookieKey} with value {CookieValue}", key, value);
|
||||
_httpContextAccessor.HttpContext.Response.Cookies.Append(key, value, options);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to add cookie {CookieKey}", key);
|
||||
throw new SetCookiesException(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveCookie(string key)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogDebug("Deleting cookie {CookieKey}", key);
|
||||
_httpContextAccessor.HttpContext.Response.Cookies.Delete(key);
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to delete cookie {CookieKey}", key);
|
||||
throw new DeleteCookiesException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Services.Cookies;
|
||||
|
||||
public interface ICookieService
|
||||
{
|
||||
Task<bool> SetCookie(string key, string value, CookieOptions options);
|
||||
Task<bool> RemoveCookie(string key);
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using GamificationService.Models;
|
||||
|
||||
namespace GamificationService.Services.CurrentUsers;
|
||||
|
||||
public class CurrentUserService : ICurrentUserService
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ILogger<ICurrentUserService> _logger;
|
||||
public CurrentUserService(IHttpContextAccessor httpContextAccessor, ILogger<ICurrentUserService> logger)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public UserSession GetCurrentUser()
|
||||
{
|
||||
UserSession currentUser = new UserSession
|
||||
{
|
||||
IsAuthenticated = _httpContextAccessor.HttpContext.User.Identity != null && _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated,
|
||||
Login = _httpContextAccessor.HttpContext.User.Identity.Name
|
||||
};
|
||||
_logger.LogDebug($"Current user extracted: {currentUser.Login}");
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using GamificationService.Models;
|
||||
|
||||
namespace GamificationService.Services.CurrentUsers;
|
||||
|
||||
public interface ICurrentUserService
|
||||
{
|
||||
UserSession GetCurrentUser();
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Services.JWT;
|
||||
|
||||
public interface IJwtService
|
||||
{
|
||||
string GenerateAccessToken(ApplicationUser user);
|
||||
JwtSecurityToken ValidateAccessToken(string token);
|
||||
Task<RefreshToken> GenerateRefreshTokenAsync(ApplicationUser user);
|
||||
Task RevokeRefreshTokenAsync(long userId, string refreshToken, string remoteIpAddress);
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Exceptions.Services.JwtService;
|
||||
using GamificationService.Exceptions.UtilServices.JWT;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace GamificationService.Services.JWT;
|
||||
|
||||
public class JwtService : IJwtService
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ILogger<JwtService> _logger;
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public JwtService(IConfiguration configuration, ILogger<JwtService> logger, UnitOfWork unitOfWork)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
public string GenerateAccessToken(ApplicationUser user)
|
||||
{
|
||||
var jwtSettings = _configuration.GetSection("JwtSettings");
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Key"]));
|
||||
var issuer = jwtSettings["Issuer"];
|
||||
var audience = jwtSettings["Audience"];
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
|
||||
new Claim(ClaimTypes.Name, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
|
||||
};
|
||||
|
||||
var userRoles = _unitOfWork.UserRoleRepository.Get()
|
||||
.Where(ur => ur.UserId == user.Id)
|
||||
.Select(ur => ur.Role)
|
||||
.Include(rr => rr.RoleRights)
|
||||
.ThenInclude(rr=>rr.Right)
|
||||
.ToList();
|
||||
|
||||
foreach (var role in userRoles)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, role.Name));
|
||||
|
||||
foreach (var right in role.RoleRights.Select(rr => rr.Right))
|
||||
{
|
||||
claims.Add(new Claim("Right", right.Name));
|
||||
}
|
||||
}
|
||||
|
||||
var expires = DateTime.UtcNow.AddMinutes(double.Parse(jwtSettings["AccessTokenExpirationMinutes"]));
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: issuer,
|
||||
audience: audience,
|
||||
claims: claims,
|
||||
expires: expires,
|
||||
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
|
||||
);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
|
||||
private string GenerateRefreshToken()
|
||||
{
|
||||
var randomNumber = new byte[32];
|
||||
using var rng = RandomNumberGenerator.Create();
|
||||
rng.GetBytes(randomNumber);
|
||||
return Convert.ToBase64String(randomNumber);
|
||||
}
|
||||
|
||||
public JwtSecurityToken ValidateAccessToken(string token)
|
||||
{
|
||||
var jwtSettings = _configuration.GetSection("JwtSettings");
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Key"]));
|
||||
var issuer = jwtSettings["Issuer"];
|
||||
var audience = jwtSettings["Audience"];
|
||||
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
var validationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = key,
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = issuer,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = audience,
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.Zero
|
||||
};
|
||||
|
||||
SecurityToken validatedToken;
|
||||
var principal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
|
||||
|
||||
return validatedToken as JwtSecurityToken;
|
||||
}
|
||||
|
||||
public async Task<RefreshToken> GenerateRefreshTokenAsync(ApplicationUser user)
|
||||
{
|
||||
var dbRefreshToken = new RefreshToken
|
||||
{
|
||||
UserId = user.Id,
|
||||
Token = GenerateRefreshToken(),
|
||||
Expires = DateTime.UtcNow.AddDays(double.Parse(_configuration["JwtSettings:RefreshTokenExpirationDays"])),
|
||||
Created = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await _unitOfWork.RefreshTokenRepository.InsertAsync(dbRefreshToken);
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new GenerateRefreshTokenException("Failed to generate refresh token");
|
||||
}
|
||||
|
||||
return dbRefreshToken;
|
||||
}
|
||||
|
||||
public async Task RevokeRefreshTokenAsync(long userId, string refreshToken, string remoteIpAddress)
|
||||
{
|
||||
var token = await _unitOfWork.RefreshTokenRepository.Get()
|
||||
.FirstOrDefaultAsync(x => x.UserId == userId && x.Token == refreshToken);
|
||||
|
||||
if (token != null)
|
||||
{
|
||||
token.IsRevoked = true;
|
||||
token.RevokedByIp = remoteIpAddress;
|
||||
token.RevokedOn = DateTime.UtcNow;
|
||||
|
||||
await _unitOfWork.SaveAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Utils;
|
||||
|
||||
namespace GamificationService.Services.NotificationService;
|
||||
|
||||
public interface INotificationService
|
||||
{
|
||||
public Task SendMailNotificationAsync(ApplicationUser user, Notification notification);
|
||||
public Task SendPushNotificationAsync(ApplicationUser user, Notification notification);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Utils;
|
||||
using GamificationService.Utils.Factory;
|
||||
|
||||
namespace GamificationService.Services.NotificationService;
|
||||
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
#region Services
|
||||
|
||||
private readonly EmailClient _emailClient;
|
||||
private readonly ILogger<NotificationService> _logger;
|
||||
private readonly PushNotificationsClient _pushNotificationsClient;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public NotificationService(EmailClient emailClient, PushNotificationsClient pushNotificationsClient, ILogger<NotificationService> logger)
|
||||
{
|
||||
_emailClient = emailClient;
|
||||
_pushNotificationsClient = pushNotificationsClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
public async Task SendMailNotificationAsync(ApplicationUser user, Notification notification)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _emailClient.SendEmail(((MailNotification)notification).ConvertToMailMessage(), user.Email);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e,e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Refactor, add reg.ru notifications
|
||||
public async Task SendPushNotificationAsync(ApplicationUser user, Notification notification)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _emailClient.SendEmail(((MailNotification)notification).ConvertToMailMessage(), user.Email);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e,e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
|
||||
namespace GamificationService.Services.Rights;
|
||||
|
||||
public interface IRightsService
|
||||
{
|
||||
Task<Right?> CreateRightAsync(string rightName, string description);
|
||||
Task<bool> UpdateRightAsync(long rightId, string newRightName, string newDescription);
|
||||
Task<bool> DeleteRightAsync(long rightId);
|
||||
Task<Right?> GetRightByIdAsync(long rightId);
|
||||
Task<(List<Right> Rights, int TotalCount)> GetAllRightsAsync(int pageNumber = 1, int pageSize = 10);
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Models.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GamificationService.Services.Rights;
|
||||
|
||||
public class RightsService : IRightsService
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
private readonly ILogger<IRightsService> _logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RightsService(UnitOfWork unitOfWork, ILogger<IRightsService> logger)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public async Task<Right?> CreateRightAsync(string rightName, string description)
|
||||
{
|
||||
var right = new Right
|
||||
{
|
||||
Name = rightName,
|
||||
Description = description
|
||||
};
|
||||
|
||||
await _unitOfWork.RightRepository.InsertAsync(right);
|
||||
if (await _unitOfWork.SaveAsync())
|
||||
{
|
||||
return right;
|
||||
}
|
||||
|
||||
throw new Exception($"Unable to create right for {rightName}");
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateRightAsync(long rightId, string newRightName, string newDescription)
|
||||
{
|
||||
var right = await _unitOfWork.RightRepository.GetByIDAsync(rightId);
|
||||
|
||||
if (right == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Right with ID {rightId} not found");
|
||||
}
|
||||
|
||||
right.Name = newRightName;
|
||||
right.Description = newDescription;
|
||||
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception($"Unable to create right for {rightId}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteRightAsync(long rightId)
|
||||
{
|
||||
var right = await _unitOfWork.RightRepository.GetByIDAsync(rightId);
|
||||
|
||||
if (right == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Right with ID {rightId} not found");
|
||||
}
|
||||
|
||||
_unitOfWork.RightRepository.Delete(right);
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception($"Unable to delete right for {rightId}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<Right?> GetRightByIdAsync(long rightId)
|
||||
{
|
||||
return await _unitOfWork.RightRepository.GetByIDAsync(rightId);
|
||||
}
|
||||
|
||||
public async Task<(List<Right> Rights, int TotalCount)> GetAllRightsAsync(int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
var query = _unitOfWork.RightRepository.Get();
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
|
||||
var pagedRights = await query
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (pagedRights, totalItems);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
|
||||
namespace GamificationService.Services.Roles;
|
||||
|
||||
public interface IRolesService
|
||||
{
|
||||
Task<ApplicationRole> CreateRoleAsync(string roleName, string description);
|
||||
Task<bool> UpdateRoleAsync(long roleId, string newRoleName, string newDescription);
|
||||
Task<bool> DeleteRoleAsync(long roleId);
|
||||
Task<bool> AddRightToRoleAsync(long roleId, long rightId);
|
||||
Task<bool> RemoveRightFromRoleAsync(long roleId, long rightId);
|
||||
Task<ApplicationRole> GetRoleByIdAsync(long roleId);
|
||||
Task<(List<ApplicationRole> Roles, int TotalCount)> GetAllRolesAsync(int pageNumber = 1, int pageSize = 10);
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Models.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace GamificationService.Services.Roles;
|
||||
|
||||
public class RolesService : IRolesService
|
||||
{
|
||||
#region Services
|
||||
|
||||
private readonly ILogger<IRolesService> _logger;
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public RolesService(ILogger<IRolesService> logger, UnitOfWork unitOfWork)
|
||||
{
|
||||
_logger = logger;
|
||||
_unitOfWork = unitOfWork;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
//TODO: refactor database work, to be more beautiful
|
||||
//ToDo: make better exception handling
|
||||
public async Task<ApplicationRole> CreateRoleAsync(string roleName, string description)
|
||||
{
|
||||
var role = new ApplicationRole(roleName)
|
||||
{
|
||||
Description = description
|
||||
};
|
||||
|
||||
await _unitOfWork.RoleRepository.InsertAsync(role);
|
||||
if (await _unitOfWork.SaveAsync())
|
||||
{
|
||||
return role;
|
||||
}
|
||||
throw new Exception("Unable to create role");
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateRoleAsync(long roleId, string newRoleName, string newDescription)
|
||||
{
|
||||
var role = await _unitOfWork.RoleRepository.GetByIDAsync(roleId);
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Role with ID {roleId} not found");
|
||||
}
|
||||
|
||||
role.Name = newRoleName;
|
||||
role.Description = newDescription;
|
||||
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception("Unable to create role");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteRoleAsync(long roleId)
|
||||
{
|
||||
var role = await _unitOfWork.RoleRepository.GetByIDAsync(roleId);
|
||||
|
||||
if (role == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Role with ID {roleId} not found");
|
||||
}
|
||||
|
||||
_unitOfWork.RoleRepository.Delete(role);
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception("Unable to delete role");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<bool> AddRightToRoleAsync(long roleId, long rightId)
|
||||
{
|
||||
var role = await _unitOfWork.RoleRepository.Get()
|
||||
.Include(r => r.RoleRights)
|
||||
.FirstOrDefaultAsync(r => r.Id == roleId);
|
||||
|
||||
var right = await _unitOfWork.RightRepository.GetByIDAsync(rightId);
|
||||
|
||||
if (role == null || right == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Role or Right not found");
|
||||
}
|
||||
|
||||
var existingRight = role.RoleRights.FirstOrDefault(rr => rr.RightId == rightId);
|
||||
|
||||
if (existingRight == null)
|
||||
{
|
||||
role.RoleRights.Add(new RoleRight { RoleId = roleId, RightId = rightId });
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception("Unable to add role right");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> RemoveRightFromRoleAsync(long roleId, long rightId)
|
||||
{
|
||||
var roleRight = await _unitOfWork.RoleRightRepository.Get()
|
||||
.FirstOrDefaultAsync(rr => rr.RoleId == roleId && rr.RightId == rightId);
|
||||
|
||||
if (roleRight == null)
|
||||
{
|
||||
throw new KeyNotFoundException($"Right not found for role");
|
||||
}
|
||||
|
||||
_unitOfWork.RoleRightRepository.Delete(roleRight);
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new Exception("Unable to remove role right");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task<ApplicationRole> GetRoleByIdAsync(long roleId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _unitOfWork.RoleRepository.Get()
|
||||
.Include(r => r.RoleRights)
|
||||
.ThenInclude(rr => rr.Right)
|
||||
.FirstOrDefaultAsync(r => r.Id == roleId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<(List<ApplicationRole> Roles, int TotalCount)> GetAllRolesAsync(int pageNumber = 1, int pageSize = 10)
|
||||
{
|
||||
var query = _unitOfWork.RoleRepository.Get()
|
||||
.Include(r => r.RoleRights)
|
||||
.ThenInclude(rr => rr.Right);
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
var pagedRoles = await query
|
||||
.Skip((pageNumber - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
return (pagedRoles, totalItems);
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Services.UsersProfile;
|
||||
|
||||
public interface IUserProfileService
|
||||
{
|
||||
public Task<UserProfileDTO> AddUserProfile(long userId, UserProfileCreateDTO userProfile);
|
||||
public Task<UserProfile> AddUserProfile(UserProfile userProfile);
|
||||
public UserProfile? GetUserProfileByUserId(long id);
|
||||
public UserProfile? GetUserProfileById(long id);
|
||||
public Task<bool> UpdateUserProfileByUserId(long userId, UserProfileCreateDTO userProfile);
|
||||
public Task<bool> UpdateUserProfile(UserProfile userProfile);
|
||||
public bool DeleteUserProfile(long id);
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
using AutoMapper;
|
||||
using GamificationService.Database.Repositories;
|
||||
using GamificationService.Exceptions.Services.ProfileService;
|
||||
using GamificationService.Models.Database;
|
||||
using GamificationService.Models.DTO;
|
||||
|
||||
namespace GamificationService.Services.UsersProfile;
|
||||
|
||||
public class UserProfileService : IUserProfileService
|
||||
{
|
||||
private readonly UnitOfWork _unitOfWork;
|
||||
|
||||
# region Services
|
||||
|
||||
private readonly ILogger<UserProfileService> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Constructor
|
||||
|
||||
public UserProfileService(UnitOfWork unitOfWork, ILogger<UserProfileService> logger, IMapper mapper)
|
||||
{
|
||||
_unitOfWork = unitOfWork;
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
# region Methods
|
||||
|
||||
public async Task<UserProfileDTO> AddUserProfile(long userId, UserProfileCreateDTO userProfile)
|
||||
{
|
||||
UserProfile userProfileEntity = _mapper.Map<UserProfile>(userProfile);
|
||||
userProfileEntity.UserId = userId;
|
||||
return _mapper.Map<UserProfileDTO>(await AddUserProfile(userProfileEntity));
|
||||
}
|
||||
|
||||
public async Task<UserProfile> AddUserProfile(UserProfile userProfile)
|
||||
{
|
||||
UserProfile userProfileEntity = userProfile;
|
||||
|
||||
// Make sure a user profile for the given user does not exist yet
|
||||
if (_unitOfWork.UserProfileRepository.Get(x => x.UserId == userProfile.UserId).Any())
|
||||
{
|
||||
_logger.LogWarning("A user profile already exists for the given user id: {UserId}", userProfile.UserId);
|
||||
throw new ProfileExistsException($"{userProfile.UserId}");
|
||||
}
|
||||
|
||||
await _unitOfWork.UserProfileRepository.InsertAsync(userProfileEntity);
|
||||
if (await _unitOfWork.SaveAsync())
|
||||
{
|
||||
_logger.LogInformation("User profile added for user id: {UserId}", userProfile.UserId);
|
||||
return userProfileEntity;
|
||||
}
|
||||
|
||||
_logger.LogError("Failed to add user profile for user id: {UserId}", userProfile.UserId);
|
||||
throw new ProfileCreationException();
|
||||
}
|
||||
|
||||
public UserProfile? GetUserProfileByUserId(long id)
|
||||
{
|
||||
return _unitOfWork.UserProfileRepository.Get(x => x.UserId == id).FirstOrDefault();
|
||||
}
|
||||
|
||||
public UserProfile? GetUserProfileById(long id)
|
||||
{
|
||||
return _unitOfWork.UserProfileRepository.GetByID(id);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateUserProfileByUserId(long userId, UserProfileCreateDTO userProfile)
|
||||
{
|
||||
var userProfileEntityUpdated = _mapper.Map<UserProfile>(userProfile);
|
||||
var profile = _unitOfWork.UserProfileRepository
|
||||
.Get(x => x.UserId == userId).FirstOrDefault() ?? throw new ProfileNotFoundException($"{userId}");
|
||||
userProfileEntityUpdated.Id = profile.Id;
|
||||
return await UpdateUserProfile(userProfileEntityUpdated);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateUserProfile(UserProfile userProfile)
|
||||
{
|
||||
var userProfileEntityUpdated = userProfile;
|
||||
var userProfileEntity = await _unitOfWork.UserProfileRepository.GetByIDAsync(userProfileEntityUpdated.Id);
|
||||
|
||||
if (userProfileEntity == null)
|
||||
{
|
||||
throw new ProfileNotFoundException($"{userProfileEntityUpdated.Id}");
|
||||
}
|
||||
|
||||
_mapper.Map(userProfileEntityUpdated, userProfileEntity);
|
||||
|
||||
if (!await _unitOfWork.SaveAsync())
|
||||
{
|
||||
throw new ProfileUpdateException($"Failed to update user profile {userProfileEntityUpdated.Id}");
|
||||
}
|
||||
|
||||
_logger.LogInformation("User profile updated for user id: {UserId}", userProfile.UserId);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DeleteUserProfile(long id)
|
||||
{
|
||||
var profile = _unitOfWork.UserProfileRepository.GetByID(id);
|
||||
if (profile == null)
|
||||
{
|
||||
throw new ProfileNotFoundException($"{id}");
|
||||
}
|
||||
|
||||
_unitOfWork.UserProfileRepository.Delete(id);
|
||||
if (_unitOfWork.Save())
|
||||
{
|
||||
_logger.LogInformation("User profile deleted: {UserId}", id);
|
||||
return true;
|
||||
}
|
||||
throw new ProfileDeletionException($"Failed to delete user profile {id}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
using GamificationService.Exceptions.UtilServices.Email;
|
||||
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public class EmailClient(SmtpClient smtpClient, string emailFrom, ILogger<EmailClient> logger)
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly string _emailFrom = emailFrom;
|
||||
private readonly ILogger<EmailClient> _logger = logger;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sends the email using the SmtpClient instance.
|
||||
/// </summary>
|
||||
/// <param name="email">Email to send.</param>
|
||||
/// <exception cref="SendEmailException">If the SmtpClient instance fails to send the email.</exception>
|
||||
/// <returns>Task that represents the asynchronous operation.</returns>
|
||||
public async Task SendEmail(MailMessage email, string emailTo)
|
||||
{
|
||||
try
|
||||
{
|
||||
email.To.Add(new MailAddress(emailTo));
|
||||
await smtpClient.SendMailAsync(email);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, ex.Message);
|
||||
throw new SendEmailException("Failed to send email", ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using GamificationService.Exceptions.UtilServices.Api;
|
||||
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public class PushNotificationsClient
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<PushNotificationsClient> _logger;
|
||||
private readonly string _applicationToken;
|
||||
private readonly string _projectId;
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PushNotificationsClient(HttpClient httpClient, ILogger<PushNotificationsClient> logger, string applicationToken, string projectId)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
_applicationToken = applicationToken;
|
||||
_projectId = projectId;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public async Task SendPushNotification(PushNotification pushNotification)
|
||||
{
|
||||
try
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
message = new
|
||||
{
|
||||
token = _applicationToken,
|
||||
notification = new
|
||||
{
|
||||
body = pushNotification.Message,
|
||||
title = pushNotification.Title,
|
||||
image = pushNotification.Image
|
||||
},
|
||||
android = new
|
||||
{
|
||||
notification = new
|
||||
{
|
||||
body = pushNotification.Message,
|
||||
title = pushNotification.Title,
|
||||
image = pushNotification.Image,
|
||||
click_action = pushNotification.ClickAction,
|
||||
click_action_type = pushNotification.ClickActionType
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post,$"/{_projectId}/messages")
|
||||
{
|
||||
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification. Status Code: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new BadRequestException($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
else if (response.StatusCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new ForbiddenException($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new Exception($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SendPushNotification(PushNotification pushNotification, string topic)
|
||||
{
|
||||
try
|
||||
{
|
||||
var payload = new
|
||||
{
|
||||
message = new
|
||||
{
|
||||
notification = new
|
||||
{
|
||||
body = pushNotification.Message,
|
||||
title = pushNotification.Title,
|
||||
image = pushNotification.Image
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var jsonPayload = JsonSerializer.Serialize(payload);
|
||||
|
||||
var request = new HttpRequestMessage(HttpMethod.Post,$"/{_projectId}/topics/{topic}/publish")
|
||||
{
|
||||
Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json")
|
||||
};
|
||||
|
||||
var response = await _httpClient.SendAsync(request);
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification. Status Code: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new BadRequestException($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
else if (response.StatusCode == HttpStatusCode.Forbidden)
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new ForbiddenException($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseContent = await response.Content.ReadAsStringAsync();
|
||||
_logger.LogError($"Failed to send push notification: {response.StatusCode}, Response: {responseContent}");
|
||||
throw new Exception($"Failed to send push notification: {response.StatusCode}");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace GamificationService.Utils.Enums;
|
||||
|
||||
public enum Gender
|
||||
{
|
||||
Male,
|
||||
Female
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace GamificationService.Utils.Enums
|
||||
{
|
||||
public enum InstructionTestScoreCalcMethod
|
||||
{
|
||||
AverageGrade,
|
||||
MaxGrade
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public enum NotificationInformationType
|
||||
{
|
||||
AUTH,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace GamificationService.Utils.Factory;
|
||||
|
||||
public class MailNotificationsFactory
|
||||
{
|
||||
public static Notification CreateNotification(NotificationInformationType type,
|
||||
string title,
|
||||
string message,List<Attachment> attachments)
|
||||
{
|
||||
return new MailNotification(type, title, message, attachments);
|
||||
}
|
||||
public Notification CreateNotification(NotificationInformationType type,
|
||||
string title,
|
||||
string message)
|
||||
{
|
||||
|
||||
return new MailNotification(type, title, message);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
namespace GamificationService.Utils.Factory;
|
||||
|
||||
public class PushNotificationsFactory
|
||||
{
|
||||
public Notification CreateNotification(NotificationInformationType type,
|
||||
string title,
|
||||
string message)
|
||||
{
|
||||
return new PushNotification(type, title, message);
|
||||
}
|
||||
|
||||
public Notification CreateNotification(NotificationInformationType type,
|
||||
string title,
|
||||
string message,
|
||||
string image)
|
||||
{
|
||||
return new PushNotification(type, title, message, image);
|
||||
}
|
||||
public Notification CreateNotification(NotificationInformationType type,
|
||||
string title,
|
||||
string message,
|
||||
string? image,
|
||||
string clickAction,
|
||||
ClickActionType clickActionType)
|
||||
{
|
||||
return new PushNotification(type, title, message, image, clickAction, clickActionType);
|
||||
}
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public class MailNotification : Notification
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private List<Attachment> _attachments;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
public List<Attachment> Attachments { get => _attachments; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public MailNotification(NotificationInformationType type, string title, string message, List<Attachment> attachments) : base(type, title, message)
|
||||
{
|
||||
_attachments = attachments;
|
||||
}
|
||||
public MailNotification(NotificationInformationType type, string title, string message) : base(type, title, message)
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public MailMessage ConvertToMailMessage()
|
||||
{
|
||||
var mailMessage = new MailMessage
|
||||
{
|
||||
Subject = CreateTitle(),
|
||||
Body = CreateBody(),
|
||||
IsBodyHtml = true,
|
||||
Priority = GetPriority()
|
||||
};
|
||||
if (_attachments != null)
|
||||
{
|
||||
mailMessage.Attachments.ToList().AddRange(_attachments);
|
||||
}
|
||||
return mailMessage;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
private string CreateTitle()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case NotificationInformationType.AUTH:
|
||||
return "Авторизация " + Title;
|
||||
case NotificationInformationType.INFO:
|
||||
return "Информация "+ Title;
|
||||
case NotificationInformationType.WARNING:
|
||||
return "Предупреждение "+ Title;
|
||||
case NotificationInformationType.ERROR:
|
||||
return "Ошибка "+ Title;
|
||||
default:
|
||||
return "Информация "+ Title;
|
||||
}
|
||||
}
|
||||
|
||||
private string CreateBody()
|
||||
{
|
||||
string formattedMessage;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case NotificationInformationType.AUTH:
|
||||
formattedMessage = "Вы успешно авторизовались.";
|
||||
break;
|
||||
case NotificationInformationType.INFO:
|
||||
formattedMessage = "Это информационное сообщение.";
|
||||
break;
|
||||
case NotificationInformationType.WARNING:
|
||||
formattedMessage = "Внимание! Обратите внимание на это предупреждение.";
|
||||
break;
|
||||
case NotificationInformationType.ERROR:
|
||||
formattedMessage = "Произошла ошибка. Пожалуйста, проверьте детали.";
|
||||
break;
|
||||
default:
|
||||
formattedMessage = "Сообщение не определено.";
|
||||
break;
|
||||
}
|
||||
|
||||
return $"<p style='font-size: 16px; line-height: 1.5; color: #555;'>{formattedMessage} {Message}</p>";
|
||||
}
|
||||
|
||||
private MailPriority GetPriority()
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case NotificationInformationType.AUTH:
|
||||
return MailPriority.High;
|
||||
case NotificationInformationType.INFO:
|
||||
return MailPriority.Normal;
|
||||
case NotificationInformationType.WARNING:
|
||||
return MailPriority.Low;
|
||||
case NotificationInformationType.ERROR:
|
||||
return MailPriority.High;
|
||||
default:
|
||||
return MailPriority.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
using System.Net.Mail;
|
||||
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public abstract class Notification
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private string _title;
|
||||
private string _message;
|
||||
private NotificationInformationType _type;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parameters
|
||||
|
||||
public string Title { get => _title;}
|
||||
public string Message { get => _message; }
|
||||
public NotificationInformationType Type { get => _type; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public Notification(NotificationInformationType type, string title, string message)
|
||||
{
|
||||
_type = type;
|
||||
_title = title;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public class PushNotification : Notification
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private readonly string? _image;
|
||||
private readonly string? _clickAction;
|
||||
private readonly ClickActionType? _clickActionType;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
public string? Image { get => _image; }
|
||||
public string? ClickAction { get => _clickAction; }
|
||||
public int? ClickActionType { get => (int)_clickActionType; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PushNotification(NotificationInformationType type, string title, string message, string image, string clickAction, ClickActionType clickActionType) : base(type, title, message)
|
||||
{
|
||||
_image = image;
|
||||
_clickAction = clickAction;
|
||||
_clickActionType = clickActionType;
|
||||
}
|
||||
|
||||
public PushNotification(NotificationInformationType type, string title, string message, string? image) : base(type, title, message)
|
||||
{
|
||||
_image = image;
|
||||
}
|
||||
|
||||
public PushNotification(NotificationInformationType type, string title, string message) : base(type, title, message)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace GamificationService.Utils;
|
||||
|
||||
public enum TwoFactorProvider
|
||||
{
|
||||
NONE,
|
||||
EMAIL,
|
||||
PHONE,
|
||||
PUSH,
|
||||
AUTHENTICATOR
|
||||
}
|
||||
Reference in New Issue
Block a user