diff --git a/.gitignore b/.gitignore
index 8afdcb6..24319b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@
*.user
*.userosscache
*.sln.docstates
+*.Development.json
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
diff --git a/Server/Configurations/MapperInitializer.cs b/Server/Configurations/MapperInitializer.cs
index 3be0b46..9005edc 100644
--- a/Server/Configurations/MapperInitializer.cs
+++ b/Server/Configurations/MapperInitializer.cs
@@ -35,6 +35,7 @@ public class MapperInitializer : Profile
CreateMap
().ReverseMap();
CreateMap().ReverseMap();
CreateMap().ReverseMap();
+ CreateMap().ReverseMap();
CreateMap()
.ForMember(d => d.AddressName, opt => opt.MapFrom(src => src.Address.Name))
@@ -107,9 +108,6 @@ public class MapperInitializer : Profile
CreateMap().ReverseMap();
CreateMap().ForMember(d => d.CompanyId, o => o.MapFrom(s => s.Employer.CompanyId));
- CreateMap().ReverseMap();
- CreateMap().ReverseMap();
- CreateMap().ReverseMap();
CreateMap().ReverseMap();
CreateMap().ReverseMap();
diff --git a/Server/Controllers/AccountController.cs b/Server/Controllers/AccountController.cs
new file mode 100644
index 0000000..08ca6d8
--- /dev/null
+++ b/Server/Controllers/AccountController.cs
@@ -0,0 +1,95 @@
+using Microsoft.AspNetCore.Mvc;
+using Server.Services;
+using SharedModels.Requests;
+
+namespace Server.Controllers;
+
+[Route("api/account")]
+[ApiController]
+public class AccountController : ControllerBase
+{
+ private readonly IAccountManagementService _accountManagementService;
+
+ public AccountController(IAccountManagementService accountManagementService)
+ {
+ _accountManagementService = accountManagementService;
+ }
+
+ [HttpPost("changeInformation")]
+ public async Task ChangeInformation([FromBody] ChangeInformationRequest request)
+ {
+ var result = await _accountManagementService.ChangeInformation(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+
+ [HttpPost("changeEmail")]
+ public async Task ChangeEmail([FromBody] ChangeEmailRequest request)
+ {
+ var result = await _accountManagementService.ChangeEmail(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+
+ [HttpPost("confirmationEmailCallback")]
+ public async Task ConfirmChangeEmail([FromBody] ConfirmChangeEmailRequest request)
+ {
+ var result = await _accountManagementService.ConfirmChangeEmail(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+
+ [HttpPost("changePhoneNumber")]
+ public async Task ChangePhoneNumber([FromBody] ChangePhoneNumberRequest request)
+ {
+ var result = await _accountManagementService.ChangePhoneNumber(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+
+ [HttpPost("confirmPhoneNumber")]
+ public async Task ConfirmPhoneNumber([FromBody] ConfirmChangePhoneNumberRequest request)
+ {
+ var result = await _accountManagementService.ConfirmPhoneNumberChange(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+
+ [HttpPost("changePassword")]
+ public async Task ChangePassword([FromBody] ChangePasswordRequest request)
+ {
+ var result = await _accountManagementService.ChangePassword(request);
+
+ if (!result.isSucceed)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/Server/Controllers/AuthenticationController.cs b/Server/Controllers/AuthenticationController.cs
index f997aee..31f8d67 100644
--- a/Server/Controllers/AuthenticationController.cs
+++ b/Server/Controllers/AuthenticationController.cs
@@ -22,30 +22,42 @@ public class AuthenticationController : ControllerBase
}
[HttpPost("register")]
- public async Task RegisterAsync([FromBody] RegistrationRequest registerRequest)
+ public async Task RegisterAsync([FromBody] RegistrationRequest request)
{
- var (succeeded, message) = await _authService.RegisterAsync(registerRequest);
+ var result = await _authService.Register(request);
- if (!succeeded)
+ if (!result.succeeded)
{
- return BadRequest(new ResponseBase {Message = message});
+ return result.actionResult;
}
- return Ok(new ResponseBase{ Message = message });
+ return Ok();
}
- [HttpGet("confirmEmail")]
- public async Task ConfirmEmailAsync([FromQuery] string email, [FromQuery] string token,
- [FromQuery] string redirectionUrl)
+ [HttpPost("confirmEmail")]
+ public async Task ConfirmEmail([FromBody] ConfirmRegistrationEmailRequest request)
{
- var (succeeded, message) = await _authService.ConfirmEmailAsync(email, token);
+ var result = await _authService.ConfirmRegistrationEmail(request);
- if (!succeeded)
+ if (!result.succeeded)
{
- return BadRequest(new ResponseBase {Message = message});
+ return result.actionResult;
}
+
+ return Ok();
+ }
+
+ [HttpPost("confirmPhoneNumber")]
+ public async Task ConfirmPhoneNumber([FromBody] ConfirmRegistrationPhoneNumberRequest request)
+ {
+ var result = await _authService.ConfirmRegistrationPhoneNumber(request);
- return Redirect(redirectionUrl);
+ if (!result.succeeded)
+ {
+ return result.actionResult;
+ }
+
+ return Ok();
}
[HttpPost("authenticate")]
diff --git a/Server/Data/SeedData.cs b/Server/Data/SeedData.cs
index 3a0ab8c..4833402 100644
--- a/Server/Data/SeedData.cs
+++ b/Server/Data/SeedData.cs
@@ -30,8 +30,7 @@ public class SeedData
var adminUser = new User
{
FirstName = "user", LastName = "user", Patronymic = "user",
- Email = "admin@autobus.com",
- EmailConfirmed = true,
+ Email = "admin@autobus.com", EmailConfirmed = true
};
await userManager.CreateAsync(adminUser, Identity.DefaultPassword);
@@ -41,7 +40,7 @@ public class SeedData
companyUser = new User
{
- FirstName = "user", LastName = "user", Patronymic = "user",
+ FirstName = "Firstname", LastName = "Lastname", Patronymic = "Patronymic",
Email = "company@autobus.com",
EmailConfirmed = true
};
@@ -54,8 +53,11 @@ public class SeedData
driverUser = new User
{
FirstName = "user", LastName = "user", Patronymic = "user",
- Email = "driver@autobus.com",
- EmailConfirmed = true
+ Email = "driver@autobus.com", EmailConfirmed = true,
+ PhoneNumber = "+380951935723", PhoneNumberConfirmed = true,
+ BirthDate = DateTime.Now.ToUniversalTime(),
+ Document = Identity.Document.Passport, DocumentDetails = "Some details",
+ Gender = Identity.Gender.Male
};
await userManager.CreateAsync(driverUser, Identity.DefaultPassword);
@@ -66,8 +68,7 @@ public class SeedData
var defaultUser = new User
{
FirstName = "user", LastName = "user", Patronymic = "user",
- Email = "user@autobus.com",
- EmailConfirmed = true
+ Email = "user@autobus.com", EmailConfirmed = true
};
await userManager.CreateAsync(defaultUser, Identity.DefaultPassword);
diff --git a/Server/Program.cs b/Server/Program.cs
index a3894ad..5a14a9f 100644
--- a/Server/Program.cs
+++ b/Server/Program.cs
@@ -107,6 +107,7 @@ services.AddAutoMapper(typeof(MapperInitializer));
services.AddScoped();
services.AddScoped();
+services.AddScoped();
services.AddScoped();
diff --git a/Server/Services/AccountManagementService.cs b/Server/Services/AccountManagementService.cs
new file mode 100644
index 0000000..4051132
--- /dev/null
+++ b/Server/Services/AccountManagementService.cs
@@ -0,0 +1,130 @@
+using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
+using Server.Models;
+using SharedModels.Requests;
+
+namespace Server.Services;
+
+public class AccountManagementService : IAccountManagementService
+{
+ private readonly IEmailSenderService _emailSender;
+ private readonly UserManager _userManager;
+ private readonly ISessionUserService _sessionUserService;
+
+ public AccountManagementService(IEmailSenderService emailSender, UserManager userManager,
+ ISessionUserService sessionUserService)
+ {
+ _emailSender = emailSender;
+ _userManager = userManager;
+ _sessionUserService = sessionUserService;
+
+ _userManager.UserValidators.Clear();
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ChangeInformation(ChangeInformationRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ dbUser.FirstName = request.FistName;
+ dbUser.LastName = request.LastName;
+ dbUser.Patronymic = request.Patronymic;
+ dbUser.BirthDate = new DateTime(request.BirthDate.Year, request.BirthDate.Month, request.BirthDate.Day, 0, 0, 0, DateTimeKind.Utc);
+ dbUser.Gender = request.Gender;
+
+ await _userManager.UpdateAsync(dbUser);
+
+ return (true, null!);
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ChangeEmail(ChangeEmailRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ if (dbUser.Email.ToLower() == request.NewEmail.ToLower())
+ {
+ return (false, new BadRequestObjectResult("You must specify a new email"));
+ }
+
+ var changeEmailToken = await _userManager.GenerateChangeEmailTokenAsync(dbUser, request.NewEmail);
+
+ var securityMessage =
+ $"Someone is trying to change email address of your account to {request.NewEmail}. " +
+ "If it is not you please follow account recovery procedure.";
+ var confirmationMessage =
+ "Someone changed account email to your address.\n" +
+ $"Here is your confirmation code: {changeEmailToken}\n\n" +
+ "If this was not you, please ignore this message.";
+
+ try { await _emailSender.SendMail(dbUser.Email, "Security alert", securityMessage); }
+ catch (Exception) { /* ignored */ }
+
+ try { await _emailSender.SendMail(request.NewEmail, "Change email confirmation", confirmationMessage); }
+ catch (Exception) { /* ignored */ }
+
+ return (true, null!);
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ConfirmChangeEmail(ConfirmChangeEmailRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ var result = await _userManager.ChangeEmailAsync(dbUser, request.NewEmail, request.Token);
+ if (!result.Succeeded)
+ {
+ return (false, new BadRequestObjectResult($"Error confirming email change {request.NewEmail}"));
+ }
+
+ return (true, null!);
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ChangePhoneNumber(ChangePhoneNumberRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ var changePhoneNumberToken = await _userManager.GenerateChangePhoneNumberTokenAsync(dbUser, request.PhoneNumber);
+
+ var securityMessage =
+ $"Someone is trying to change phone number of your account to {request.PhoneNumber}. " +
+ "If it is not you please follow account recovery procedure.";
+
+ try { await _emailSender.SendMail(dbUser.Email, "Security alert", securityMessage); }
+ catch (Exception) { /* ignored */ }
+
+ // TODO: Send sms message to new phone number
+
+ return (true, null!);
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ConfirmPhoneNumberChange(ConfirmChangePhoneNumberRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ var result = await _userManager.ChangePhoneNumberAsync(dbUser, request.PhoneNumber, request.Token);
+ if (!result.Succeeded)
+ {
+ return (false, new BadRequestObjectResult(result.Errors));
+ }
+
+ return (true, null!);
+ }
+
+ public async Task<(bool isSucceed, IActionResult actionResult)> ChangePassword(ChangePasswordRequest request)
+ {
+ var dbUser = await _userManager.FindByIdAsync(_sessionUserService.GetAuthUserId());
+
+ if (!await _userManager.CheckPasswordAsync(dbUser, request.CurrentPassword))
+ {
+ return (false, new BadRequestObjectResult("Invalid current password"));
+ }
+
+ await _userManager.ChangePasswordAsync(dbUser, request.CurrentPassword, request.NewPassword);
+
+ var securityMessage = "Someone is changed your account password." +
+ "If this was not you please follow account recovery procedure.";
+
+ try { await _emailSender.SendMail(dbUser.Email, "Security alert", securityMessage); }
+ catch (Exception) { /* ignored */ }
+
+ return (true, null!);
+ }
+}
\ No newline at end of file
diff --git a/Server/Services/AuthenticationService.cs b/Server/Services/AuthenticationService.cs
index 5262bf7..499f949 100644
--- a/Server/Services/AuthenticationService.cs
+++ b/Server/Services/AuthenticationService.cs
@@ -5,6 +5,7 @@ using System.Security.Cryptography;
using System.Text;
using Google.Apis.Auth;
using Microsoft.AspNetCore.Identity;
+using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
@@ -22,114 +23,104 @@ public class AuthenticationService : IAuthenticationService
private readonly Jwt _jwt;
private readonly UserManager _userManager;
- private readonly RoleManager _roleManager;
- private readonly IHttpContextAccessor _contextAccessor;
- private readonly LinkGenerator _linkGenerator;
private readonly IEmailSenderService _emailSender;
private readonly IConfiguration _configuration;
- public AuthenticationService(UserManager userManager,
- RoleManager roleManager, IOptions jwt,
- IHttpContextAccessor contextAccessor, LinkGenerator linkGenerator,
+ public AuthenticationService(UserManager userManager, IOptions jwt,
IEmailSenderService emailSender, IConfiguration configuration)
{
_jwt = jwt.Value;
_userManager = userManager;
- _roleManager = roleManager;
- _contextAccessor = contextAccessor;
- _linkGenerator = linkGenerator;
_emailSender = emailSender;
_configuration = configuration;
_userManager.UserValidators.Clear();
}
- public async Task<(bool succeeded, string message)> RegisterAsync(RegistrationRequest regRequest)
+ public async Task<(bool succeeded, IActionResult actionResult)> Register(RegistrationRequest request)
{
- var userWithSameEmail = await _userManager.FindByEmailAsync(regRequest.Email);
+ var userWithSameEmail = await _userManager.FindByEmailAsync(request.Email);
if (userWithSameEmail != null)
{
- return (false, "Email is already registered.");
+ return (false, new BadRequestObjectResult("Email is already registered."));
}
var userWithSamePhone = await _userManager.Users
- .SingleOrDefaultAsync(u => u.PhoneNumber == regRequest.PhoneNumber);
+ .SingleOrDefaultAsync(u => u.PhoneNumber == request.PhoneNumber);
if (userWithSamePhone != null)
{
- return (false, "Phone is already registered.");
+ return (false, new BadRequestObjectResult("Phone is already registered."));
}
var user = new User
{
UserName = "temp",
- FirstName = regRequest.FirstName,
- LastName = regRequest.LastName,
- Patronymic = regRequest.Patronymic,
- Email = regRequest.Email,
- PhoneNumber = regRequest.PhoneNumber
+ FirstName = request.FirstName,
+ LastName = request.LastName,
+ Patronymic = request.Patronymic,
+ Email = request.Email,
+ PhoneNumber = request.PhoneNumber
};
- var createUserResult = await _userManager.CreateAsync(user, regRequest.Password);
+ var createUserResult = await _userManager.CreateAsync(user, request.Password);
if (!createUserResult.Succeeded)
{
- return (false, $"{createUserResult.Errors?.First().Description}");
+ return (false, new BadRequestObjectResult(createUserResult.Errors));
}
await _userManager.AddToRoleAsync(user, Identity.DefaultRole.ToString());
- var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
- var confirmationLink = _linkGenerator.GetUriByAction(_contextAccessor.HttpContext,
- "confirmEmail", "authentication",
- new { email = user.Email, token = token, redirectionUrl = regRequest.EmailConfirmationRedirectUrl },
- _contextAccessor.HttpContext.Request.Scheme);
+ var emailConfirmationToken = await _userManager.GenerateEmailConfirmationTokenAsync(user);
+ var confirmationMessage =
+ "Someone registered an account on our service with your email.\n" +
+ $"Here is your confirmation code: {emailConfirmationToken}\n\n" +
+ "If this was not you, please ignore this message.";
+
+ try { await _emailSender.SendMail(user.Email, "Email confirmation", confirmationMessage); }
+ catch (Exception e) { /* ignored */ }
+
+ // TODO: Add phone number confirmation
- try
- {
- await _emailSender.SendMail(user.Email, "Email confirmation", confirmationLink);
- }
- catch (Exception e)
- {
- throw;
- }
-
- return (true, $"User registered with email {user.Email}. Before signing in confirm your email" +
- $"by following a link sent to registered email address.");
+ return (true, null!);
}
- public async Task<(bool succeeded, string? message)> ConfirmEmailAsync(string email, string token)
+ public async Task<(bool succeeded, IActionResult actionResult)> ConfirmRegistrationEmail(ConfirmRegistrationEmailRequest request)
{
- var user = await _userManager.FindByEmailAsync(email);
- if (user == null)
- {
- return (false, $"Email {email} not registered");
- }
+ var dbUser = await _userManager.FindByEmailAsync(request.Email);
- var result = await _userManager.ConfirmEmailAsync(user, token);
+ var result = await _userManager.ConfirmEmailAsync(dbUser, request.Token);
if (!result.Succeeded)
{
- return (false, $"Error confirming email {email} with token {token}");
+ return (false, new BadRequestObjectResult($"Error confirming email."));
}
- return (true, $"Email {email} confirmed");
+ return (true, null!);
+ }
+
+ public async Task<(bool succeeded, IActionResult actionResult)> ConfirmRegistrationPhoneNumber(ConfirmRegistrationPhoneNumberRequest numberRequest)
+ {
+ var dbUser = await _userManager.Users.FirstAsync(u => u.PhoneNumber == numberRequest.PhoneNumber);
+
+ // TODO: Add phone number confirmation token validation
+
+ return (true, null!);
}
public async Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
- AuthenticateAsync(AuthenticationRequest authRequest)
+ AuthenticateAsync(AuthenticationRequest request)
{
var authResponse = new AuthenticationResponse();
- User user;
-
- user = await _userManager.FindByEmailAsync(authRequest.Email);
+ var user = await _userManager.FindByEmailAsync(request.Email);
if (user == null)
{
- authResponse.Message = $"No accounts registered with {authRequest.Email}.";
+ authResponse.Message = $"No accounts registered with {request.Email}.";
return (false, authResponse, null);
}
- if (!await _userManager.CheckPasswordAsync(user, authRequest.Password))
+ if (!await _userManager.CheckPasswordAsync(user, request.Password))
{
authResponse.Message = $"Incorrect email or password.";
return (false, authResponse, null);
@@ -160,13 +151,13 @@ public class AuthenticationService : IAuthenticationService
}
public async Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
- AuthenticateWithGoogleAsync(GoogleAuthenticationRequest authRequest)
+ AuthenticateWithGoogleAsync(GoogleAuthenticationRequest request)
{
GoogleJsonWebSignature.ValidationSettings settings = new GoogleJsonWebSignature.ValidationSettings();
settings.Audience = new List { _configuration["Authentication:Google:ClientId"] };
- GoogleJsonWebSignature.Payload payload = GoogleJsonWebSignature.ValidateAsync(authRequest.IdToken, settings).Result;
+ GoogleJsonWebSignature.Payload payload = GoogleJsonWebSignature.ValidateAsync(request.IdToken, settings).Result;
var authResponse = new AuthenticationResponse();
@@ -209,8 +200,8 @@ public class AuthenticationService : IAuthenticationService
return (true, authResponse, refreshTokenString);
}
- public async Task<(bool succeeded, AuthenticationResponse authResponse,
- string? refreshToken)> RenewRefreshTokenAsync(string? token)
+ public async Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
+ RenewRefreshTokenAsync(string? token)
{
var authResponse = new AuthenticationResponse();
diff --git a/Server/Services/EmailSenderService.cs b/Server/Services/EmailSenderService.cs
index 3ae2020..2db14f2 100644
--- a/Server/Services/EmailSenderService.cs
+++ b/Server/Services/EmailSenderService.cs
@@ -22,6 +22,11 @@ public class EmailSenderService : IEmailSenderService
_smtpClient = new SmtpClient();
_smtpClient.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
}
+
+ ~EmailSenderService()
+ {
+ _smtpClient.Dispose();
+ }
public async Task<(bool succeeded, string message)> SendMail(string toEmail, string subject, string message)
{
@@ -38,7 +43,6 @@ public class EmailSenderService : IEmailSenderService
await _smtpClient.AuthenticateAsync(Encoding.ASCII, _smtpCredentials.User, _smtpCredentials.Password);
await _smtpClient.SendAsync(mailMessage);
await _smtpClient.DisconnectAsync(true);
- _smtpClient.Dispose();
return (true, "Letter has been sent successfully");
}
diff --git a/Server/Services/IAccountManagementService.cs b/Server/Services/IAccountManagementService.cs
new file mode 100644
index 0000000..d6dd9c8
--- /dev/null
+++ b/Server/Services/IAccountManagementService.cs
@@ -0,0 +1,19 @@
+using Microsoft.AspNetCore.Mvc;
+using SharedModels.Requests;
+
+namespace Server.Services;
+
+public interface IAccountManagementService
+{
+ Task<(bool isSucceed, IActionResult actionResult)> ChangeInformation(ChangeInformationRequest request);
+
+ Task<(bool isSucceed, IActionResult actionResult)> ChangeEmail(ChangeEmailRequest request);
+
+ Task<(bool isSucceed, IActionResult actionResult)> ConfirmChangeEmail(ConfirmChangeEmailRequest request);
+
+ Task<(bool isSucceed, IActionResult actionResult)> ChangePhoneNumber(ChangePhoneNumberRequest request);
+
+ Task<(bool isSucceed, IActionResult actionResult)> ConfirmPhoneNumberChange(ConfirmChangePhoneNumberRequest request);
+
+ Task<(bool isSucceed, IActionResult actionResult)> ChangePassword(ChangePasswordRequest request);
+}
\ No newline at end of file
diff --git a/Server/Services/IAuthenticationService.cs b/Server/Services/IAuthenticationService.cs
index f68e1d4..fe64d35 100644
--- a/Server/Services/IAuthenticationService.cs
+++ b/Server/Services/IAuthenticationService.cs
@@ -1,3 +1,4 @@
+using Microsoft.AspNetCore.Mvc;
using SharedModels.Requests;
using SharedModels.Responses;
@@ -5,15 +6,17 @@ namespace Server.Services;
public interface IAuthenticationService
{
- Task<(bool succeeded, string message)> RegisterAsync(RegistrationRequest regRequest);
+ Task<(bool succeeded, IActionResult actionResult)> Register(RegistrationRequest request);
+
+ Task<(bool succeeded, IActionResult actionResult)> ConfirmRegistrationEmail(ConfirmRegistrationEmailRequest request);
+
+ Task<(bool succeeded, IActionResult actionResult)> ConfirmRegistrationPhoneNumber(ConfirmRegistrationPhoneNumberRequest numberRequest);
- Task<(bool succeeded, string message)> ConfirmEmailAsync(string email, string token);
+ Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
+ AuthenticateAsync(AuthenticationRequest request);
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
- AuthenticateAsync(AuthenticationRequest authRequest);
-
- Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
- AuthenticateWithGoogleAsync(GoogleAuthenticationRequest authRequest);
+ AuthenticateWithGoogleAsync(GoogleAuthenticationRequest request);
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)>
RenewRefreshTokenAsync(string? token);
diff --git a/Server/Services/ISessionUserService.cs b/Server/Services/ISessionUserService.cs
index 2738df7..55d829a 100644
--- a/Server/Services/ISessionUserService.cs
+++ b/Server/Services/ISessionUserService.cs
@@ -10,6 +10,5 @@ public interface ISessionUserService
public Task IsAuthUserCompanyVehicleEnrollment(int enrollmentId);
public Task IsAuthUserCompanyDriver(string driverId);
-
public Task IsAuthUserReview(int reviewId);
}
\ No newline at end of file
diff --git a/Server/Services/IUserManagementService.cs b/Server/Services/IUserManagementService.cs
index e3877b6..1b743c2 100644
--- a/Server/Services/IUserManagementService.cs
+++ b/Server/Services/IUserManagementService.cs
@@ -8,14 +8,15 @@ namespace Server.Services;
public interface IUserManagementService
{
- Task<(bool isSucceeded, IActionResult? actionResult, UserDto user)> AddUser(CreateUserDto createUserDto);
+ Task<(bool isSucceeded, IActionResult actionResult, UserDto user)> AddUser(CreateUserDto createUserDto);
- Task<(bool isSucceeded, IActionResult? actionResult, IEnumerable users, PagingMetadata pagingMetadata)>
+ Task<(bool isSucceeded, IActionResult actionResult, IEnumerable users, PagingMetadata pagingMetadata)>
GetUsers(UserParameters parameters);
+
+ Task<(bool isSucceeded, IActionResult actionResult, ExpandoObject user)> GetUser(string id, string? fields);
+
+ Task<(bool isSucceeded, IActionResult actionResult, UserDto user)>
+ UpdateUser(string id, UpdateUserDto updateUserDto);
- Task<(bool isSucceeded, IActionResult? actionResult, ExpandoObject user)> GetUser(string id, string? fields);
-
- Task<(bool isSucceeded, IActionResult? actionResult, UserDto user)> UpdateUser(string id, UpdateUserDto updateUserDto);
-
- Task<(bool isSucceed, IActionResult? actionResult)> DeleteUser(string id);
+ Task<(bool isSucceed, IActionResult actionResult)> DeleteUser(string id);
}
\ No newline at end of file
diff --git a/Server/Services/UserManagementService.cs b/Server/Services/UserManagementService.cs
index bb1123a..bb7b3c7 100644
--- a/Server/Services/UserManagementService.cs
+++ b/Server/Services/UserManagementService.cs
@@ -9,6 +9,7 @@ using Server.Models;
using SharedModels.DataTransferObjects.Model;
using SharedModels.QueryParameters;
using SharedModels.QueryParameters.Objects;
+using SharedModels.Requests;
namespace Server.Services;
@@ -21,9 +22,9 @@ public class UserManagementService : IUserManagementService
private readonly IDataShaper _userDataShaper;
private readonly IPager _pager;
- public UserManagementService(IMapper mapper, UserManager userManager, RoleManager roleManager,
- ISortHelper userSortHelper, IDataShaper userDataShaper, IPager pager,
- ApplicationDbContext dbContext)
+ public UserManagementService(IMapper mapper, UserManager userManager,
+ RoleManager roleManager, ISortHelper userSortHelper,
+ IDataShaper userDataShaper, IPager pager)
{
_mapper = mapper;
_userManager = userManager;
@@ -35,7 +36,8 @@ public class UserManagementService : IUserManagementService
_userManager.UserValidators.Clear();
}
- public async Task<(bool isSucceeded, IActionResult? actionResult, UserDto user)> AddUser(CreateUserDto createUserDto)
+ public async Task<(bool isSucceeded, IActionResult actionResult, UserDto user)>
+ AddUser(CreateUserDto createUserDto)
{
var user = _mapper.Map(createUserDto);
user.BirthDate = user.BirthDate == null ? null : new DateTime(user.BirthDate.Value.Ticks, DateTimeKind.Utc);
@@ -45,12 +47,12 @@ public class UserManagementService : IUserManagementService
if (await _userManager.FindByEmailAsync(user.Email) != null)
{
- return (false, new BadRequestObjectResult("Email already registered"), null);
+ return (false, new BadRequestObjectResult("Email already registered"), null!);
}
if (user.PhoneNumber != null && await _userManager.Users.FirstOrDefaultAsync(u => u.PhoneNumber == user.PhoneNumber) != null)
{
- return (false, new BadRequestObjectResult("Phone number already registered"), null);
+ return (false, new BadRequestObjectResult("Phone number already registered"), null!);
}
if (createUserDto.Roles != null!)
@@ -59,7 +61,7 @@ public class UserManagementService : IUserManagementService
{
if (!await _roleManager.RoleExistsAsync(role))
{
- return (false, new BadRequestObjectResult($"Roles \"{role}\" doesn't exist"), null);
+ return (false, new BadRequestObjectResult($"Roles \"{role}\" doesn't exist"), null!);
}
userDto.Roles.Add(role);
@@ -71,11 +73,11 @@ public class UserManagementService : IUserManagementService
userDto.Id = user.Id;
- return (true, null, userDto);
+ return (true, null!, userDto);
}
- public async Task<(bool isSucceeded, IActionResult? actionResult, IEnumerable users,
- PagingMetadata pagingMetadata)> GetUsers(UserParameters parameters)
+ public async Task<(bool isSucceeded, IActionResult actionResult, IEnumerable users, PagingMetadata pagingMetadata)>
+ GetUsers(UserParameters parameters)
{
var dbUsers = _userManager.Users.Include(u => u.Company)
.Include(u => u.Reviews).Include(u => u.TicketGroups)
@@ -108,7 +110,7 @@ public class UserManagementService : IUserManagementService
}
}
- return (true, null, shapedData, pagingMetadata);
+ return (true, null!, shapedData, pagingMetadata);
void SearchByAllUserFields(ref IQueryable users, string? search)
{
@@ -126,7 +128,7 @@ public class UserManagementService : IUserManagementService
}
}
- public async Task<(bool isSucceeded, IActionResult? actionResult, ExpandoObject user)>
+ public async Task<(bool isSucceeded, IActionResult actionResult, ExpandoObject user)>
GetUser(string id, string? fields)
{
var dbUser = await _userManager.Users.Include(u => u.Employer).
@@ -142,24 +144,24 @@ public class UserManagementService : IUserManagementService
fields = UserParameters.DefaultFields;
}
- var userDto = _mapper.Map(dbUser);
+ var userDto = _mapper.Map(dbUser);
var shapedData = _userDataShaper.ShapeData(userDto, fields);
- return (true, null, shapedData);
+ return (true, null!, shapedData);
}
- public async Task<(bool isSucceeded, IActionResult? actionResult, UserDto user)>
+ public async Task<(bool isSucceeded, IActionResult actionResult, UserDto user)>
UpdateUser(string id, UpdateUserDto updateUserDto)
{
if (id != updateUserDto.Id)
{
- return (false, new BadRequestObjectResult("Object and query ids don't match"), null);
+ return (false, new BadRequestObjectResult("Object and query ids don't match"), null!);
}
if (!await _userManager.Users.AnyAsync(u => u.Id == id))
{
- return (false, new NotFoundResult(), null);
+ return (false, new NotFoundResult(), null!);
}
var dbUser = await _userManager.FindByIdAsync(id);
@@ -198,7 +200,7 @@ public class UserManagementService : IUserManagementService
{
if (!await _roleManager.RoleExistsAsync(role))
{
- return (false, new BadRequestObjectResult($"Roles \"{role}\" doesn't exist"), null);
+ return (false, new BadRequestObjectResult($"Roles \"{role}\" doesn't exist"), null!);
}
}
@@ -212,10 +214,10 @@ public class UserManagementService : IUserManagementService
await _userManager.UpdateAsync(dbUser);
- return (true, null, userDto);
+ return (true, null!, userDto);
}
- public async Task<(bool isSucceed, IActionResult? actionResult)> DeleteUser(string id)
+ public async Task<(bool isSucceed, IActionResult actionResult)> DeleteUser(string id)
{
var dbUser = await _userManager.FindByIdAsync(id);
@@ -226,6 +228,6 @@ public class UserManagementService : IUserManagementService
await _userManager.DeleteAsync(dbUser);
- return (true, null);
+ return (true, null!);
}
}
\ No newline at end of file
diff --git a/Server/appsettings.Development.json b/Server/appsettings.Development.json
deleted file mode 100644
index 2ce6a28..0000000
--- a/Server/appsettings.Development.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- },
- "AllowedHosts": "*",
- "ConnectionStrings": {
- "DefaultConnection": "host=localhost;database=auto.bus;user id=postgres;password=postgres;Include Error Detail = true"
- },
- "ApplicationName": "auto.bus",
- "SmtpCredentials": {
- "Host": "",
- "Port": 587,
- "User": "",
- "Password": ""
- },
- "Authentication": {
- "Google": {
- "ClientId": "",
- "ClientSecret": ""
- }
- },
- "Jwt": {
- "Key": "Secret which will never be exposed",
- "Audience": "Application URL",
- "Issuer": "Application URL",
- "ValidityInMinutes": 60,
- "RefreshTokenValidityInDays": 10
- }
-}
diff --git a/Server/appsettings.json b/Server/appsettings.json
index 717c5ab..2792325 100644
--- a/Server/appsettings.json
+++ b/Server/appsettings.json
@@ -7,10 +7,10 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
- "DefaultConnection": "host=localhost;database=auto.bus;user id=postgres;password=postgres;Include Error Detail = true"
+ "DefaultConnection": ""
},
- "UseApiExplorer": true,
- "ApplicationName": "auto.bus",
+ "UseApiExplorer": false,
+ "ApplicationName": "",
"SmtpCredentials": {
"Host": "",
"Port": 587,
@@ -24,10 +24,10 @@
}
},
"Jwt": {
- "Key": "Secret which will never be exposed",
- "Audience": "Application URL",
- "Issuer": "Application URL",
- "ValidityInMinutes": 1,
+ "Key": "",
+ "Audience": "",
+ "Issuer": "",
+ "ValidityInMinutes": 5,
"RefreshTokenValidityInDays": 10
}
}
diff --git a/SharedModels/Requests/ChangeEmailRequest.cs b/SharedModels/Requests/ChangeEmailRequest.cs
new file mode 100644
index 0000000..ff19d54
--- /dev/null
+++ b/SharedModels/Requests/ChangeEmailRequest.cs
@@ -0,0 +1,10 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ChangeEmailRequest
+{
+ [Required]
+ [DataType(DataType.EmailAddress)]
+ public string NewEmail { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ChangeInformationRequest.cs b/SharedModels/Requests/ChangeInformationRequest.cs
new file mode 100644
index 0000000..5560cf9
--- /dev/null
+++ b/SharedModels/Requests/ChangeInformationRequest.cs
@@ -0,0 +1,21 @@
+using System.ComponentModel.DataAnnotations;
+using Utils;
+
+namespace SharedModels.Requests;
+
+public class ChangeInformationRequest
+{
+ [Required]
+ public string FistName { get; set; } = null!;
+ [Required]
+ public string LastName { get; set; } = null!;
+ [Required]
+ public string Patronymic { get; set; } = null!;
+
+ [Required]
+ [DataType(DataType.Date)]
+ public DateTime BirthDate { get; set; }
+
+ [Required]
+ public Identity.Gender Gender { get; set; }
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ChangePasswordRequest.cs b/SharedModels/Requests/ChangePasswordRequest.cs
new file mode 100644
index 0000000..c957d4d
--- /dev/null
+++ b/SharedModels/Requests/ChangePasswordRequest.cs
@@ -0,0 +1,12 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ChangePasswordRequest
+{
+ [Required]
+ public string CurrentPassword { get; set; } = null!;
+
+ [Required]
+ public string NewPassword { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ChangePhoneNumberRequest.cs b/SharedModels/Requests/ChangePhoneNumberRequest.cs
new file mode 100644
index 0000000..9755c4e
--- /dev/null
+++ b/SharedModels/Requests/ChangePhoneNumberRequest.cs
@@ -0,0 +1,10 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ChangePhoneNumberRequest
+{
+ [Required]
+ [DataType(DataType.PhoneNumber)]
+ public string PhoneNumber { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ConfirmChangeEmailRequest.cs b/SharedModels/Requests/ConfirmChangeEmailRequest.cs
new file mode 100644
index 0000000..a388131
--- /dev/null
+++ b/SharedModels/Requests/ConfirmChangeEmailRequest.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ConfirmChangeEmailRequest : ChangeEmailRequest
+{
+ [Required]
+ public string Token { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ConfirmChangePhoneNumberRequest.cs b/SharedModels/Requests/ConfirmChangePhoneNumberRequest.cs
new file mode 100644
index 0000000..09c2e57
--- /dev/null
+++ b/SharedModels/Requests/ConfirmChangePhoneNumberRequest.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ConfirmChangePhoneNumberRequest : ChangePhoneNumberRequest
+{
+ [Required]
+ public string Token { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ConfirmRegistrationEmailRequest.cs b/SharedModels/Requests/ConfirmRegistrationEmailRequest.cs
new file mode 100644
index 0000000..c63f354
--- /dev/null
+++ b/SharedModels/Requests/ConfirmRegistrationEmailRequest.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ConfirmRegistrationEmailRequest
+{
+ [Required]
+ [DataType(DataType.EmailAddress)]
+ public string Email { get; set; } = null!;
+
+ [Required]
+ public string Token { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/ConfirmRegistrationPhoneNumberRequest.cs b/SharedModels/Requests/ConfirmRegistrationPhoneNumberRequest.cs
new file mode 100644
index 0000000..dfbfc4b
--- /dev/null
+++ b/SharedModels/Requests/ConfirmRegistrationPhoneNumberRequest.cs
@@ -0,0 +1,13 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace SharedModels.Requests;
+
+public class ConfirmRegistrationPhoneNumberRequest
+{
+ [Required]
+ [DataType(DataType.PhoneNumber)]
+ public string PhoneNumber { get; set; } = null!;
+
+ [Required]
+ public string Token { get; set; } = null!;
+}
\ No newline at end of file
diff --git a/SharedModels/Requests/RegistrationRequest.cs b/SharedModels/Requests/RegistrationRequest.cs
index 31495d1..7f330a8 100644
--- a/SharedModels/Requests/RegistrationRequest.cs
+++ b/SharedModels/Requests/RegistrationRequest.cs
@@ -24,7 +24,4 @@ public class RegistrationRequest
[Required(ErrorMessage = "Password is required")]
[DataType(DataType.Password)]
public string Password { get; set; } = null!;
-
- [Url]
- public string EmailConfirmationRedirectUrl { get; set; } = null!;
}