email and password change panels added
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WatchIt.Common.Model.Accounts;
|
||||
|
||||
public class AccountEmailRequest
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
[JsonPropertyName("new_email")]
|
||||
public string NewEmail { get; set; }
|
||||
|
||||
[JsonPropertyName("password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PUBLIC METHODS
|
||||
|
||||
public void UpdateAccount(Database.Model.Account.Account account)
|
||||
{
|
||||
account.Email = NewEmail;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace WatchIt.Common.Model.Accounts;
|
||||
|
||||
public class AccountPasswordRequest
|
||||
{
|
||||
#region PROPERTIES
|
||||
|
||||
[JsonPropertyName("old_password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[JsonPropertyName("new_password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[JsonPropertyName("new_password_confirmation")]
|
||||
public string NewPasswordConfirmation { get; set; }
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -15,9 +15,9 @@ public class Account
|
||||
public short? GenderId { get; set; }
|
||||
public Guid? ProfilePictureId { get; set; }
|
||||
public Guid? BackgroundPictureId { get; set; }
|
||||
public required byte[] Password { get; set; }
|
||||
public required string LeftSalt { get; set; }
|
||||
public required string RightSalt { get; set; }
|
||||
public byte[] Password { get; set; }
|
||||
public string LeftSalt { get; set; }
|
||||
public string RightSalt { get; set; }
|
||||
public bool IsAdmin { get; set; } = false;
|
||||
public DateTime CreationDate { get; set; }
|
||||
public DateTime LastActive { get; set; }
|
||||
|
||||
@@ -114,6 +114,20 @@ public class AccountsController(IAccountsControllerService accountsControllerSer
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<ActionResult> PatchAccountUsername([FromBody]AccountUsernameRequest data) => await accountsControllerService.PatchAccountUsername(data);
|
||||
|
||||
[HttpPatch("email")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<ActionResult> PatchAccountEmail([FromBody]AccountEmailRequest data) => await accountsControllerService.PatchAccountEmail(data);
|
||||
|
||||
[HttpPatch("password")]
|
||||
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||
public async Task<ActionResult> PatchAccountPassword([FromBody]AccountPasswordRequest data) => await accountsControllerService.PatchAccountPassword(data);
|
||||
|
||||
#endregion
|
||||
|
||||
[HttpGet("{id}/movies")]
|
||||
|
||||
@@ -37,18 +37,13 @@ public class AccountsControllerService(
|
||||
|
||||
public async Task<RequestResult> Register(RegisterRequest data)
|
||||
{
|
||||
string leftSalt = StringExtensions.CreateRandom(20);
|
||||
string rightSalt = StringExtensions.CreateRandom(20);
|
||||
byte[] hash = ComputeHash(data.Password, leftSalt, rightSalt);
|
||||
|
||||
Account account = new Account
|
||||
{
|
||||
Username = data.Username,
|
||||
Email = data.Email,
|
||||
Password = hash,
|
||||
LeftSalt = leftSalt,
|
||||
RightSalt = rightSalt,
|
||||
};
|
||||
|
||||
SetPassword(account, data.Password);
|
||||
await database.Accounts.AddAsync(account);
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
@@ -284,6 +279,36 @@ public class AccountsControllerService(
|
||||
return RequestResult.Ok();
|
||||
}
|
||||
|
||||
public async Task<RequestResult> PatchAccountEmail(AccountEmailRequest data)
|
||||
{
|
||||
Account account = await database.Accounts.FirstAsync(x => x.Id == userService.GetUserId());
|
||||
|
||||
if (!ComputeHash(data.Password, account.LeftSalt, account.RightSalt).SequenceEqual(account.Password))
|
||||
{
|
||||
return RequestResult.Unauthorized();
|
||||
}
|
||||
|
||||
data.UpdateAccount(account);
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
return RequestResult.Ok();
|
||||
}
|
||||
|
||||
public async Task<RequestResult> PatchAccountPassword(AccountPasswordRequest data)
|
||||
{
|
||||
Account account = await database.Accounts.FirstAsync(x => x.Id == userService.GetUserId());
|
||||
|
||||
if (!ComputeHash(data.OldPassword, account.LeftSalt, account.RightSalt).SequenceEqual(account.Password))
|
||||
{
|
||||
return RequestResult.Unauthorized();
|
||||
}
|
||||
|
||||
SetPassword(account, data.NewPassword);
|
||||
await database.SaveChangesAsync();
|
||||
|
||||
return RequestResult.Ok();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async Task<RequestResult> GetAccountRatedMovies(long id, MovieRatedQueryParameters query)
|
||||
@@ -338,5 +363,16 @@ public class AccountsControllerService(
|
||||
|
||||
protected byte[] ComputeHash(string password, string leftSalt, string rightSalt) => SHA512.HashData(Encoding.UTF8.GetBytes($"{leftSalt}{password}{rightSalt}"));
|
||||
|
||||
private void SetPassword(Account account, string password)
|
||||
{
|
||||
string leftSalt = StringExtensions.CreateRandom(20);
|
||||
string rightSalt = StringExtensions.CreateRandom(20);
|
||||
byte[] hash = ComputeHash(password, leftSalt, rightSalt);
|
||||
|
||||
account.Password = hash;
|
||||
account.LeftSalt = leftSalt;
|
||||
account.RightSalt = rightSalt;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -22,6 +22,8 @@ public interface IAccountsControllerService
|
||||
Task<RequestResult> GetAccountInfo(long id);
|
||||
Task<RequestResult> PutAccountProfileInfo(AccountProfileInfoRequest data);
|
||||
Task<RequestResult> PatchAccountUsername(AccountUsernameRequest data);
|
||||
Task<RequestResult> PatchAccountEmail(AccountEmailRequest data);
|
||||
Task<RequestResult> PatchAccountPassword(AccountPasswordRequest data);
|
||||
Task<RequestResult> GetAccountRatedMovies(long id, MovieRatedQueryParameters query);
|
||||
Task<RequestResult> GetAccountRatedSeries(long id, SeriesRatedQueryParameters query);
|
||||
Task<RequestResult> GetAccountRatedPersons(long id, PersonRatedQueryParameters query);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
using FluentValidation;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Database;
|
||||
|
||||
namespace WatchIt.WebAPI.Validators.Accounts;
|
||||
|
||||
public class AccountEmailRequestValidator : AbstractValidator<AccountEmailRequest>
|
||||
{
|
||||
public AccountEmailRequestValidator(DatabaseContext database)
|
||||
{
|
||||
RuleFor(x => x.NewEmail).EmailAddress()
|
||||
.CannotBeIn(database.Accounts, x => x.Email)
|
||||
.WithMessage("Email was already used");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using FluentValidation;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Database;
|
||||
|
||||
namespace WatchIt.WebAPI.Validators.Accounts;
|
||||
|
||||
public class AccountPasswordRequestValidator : AbstractValidator<AccountPasswordRequest>
|
||||
{
|
||||
public AccountPasswordRequestValidator(DatabaseContext database)
|
||||
{
|
||||
RuleFor(x => x.NewPassword).MinimumLength(8)
|
||||
.Must(x => x.Any(char.IsUpper)).WithMessage("Password must contain at least one uppercase letter.")
|
||||
.Must(x => x.Any(char.IsLower)).WithMessage("Password must contain at least one lowercase letter.")
|
||||
.Must(x => x.Any(char.IsDigit)).WithMessage("Password must contain at least one digit.")
|
||||
.Equal(x => x.NewPasswordConfirmation);
|
||||
}
|
||||
}
|
||||
@@ -191,6 +191,36 @@ public class AccountsClientService(IHttpClientService httpClientService, IConfig
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task PatchAccountEmail(AccountEmailRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Accounts.PatchAccountEmail);
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Patch, url)
|
||||
{
|
||||
Body = data,
|
||||
};
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor400BadRequest(badRequestAction)
|
||||
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task PatchAccountPassword(AccountPasswordRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Accounts.PatchAccountPassword);
|
||||
HttpRequest request = new HttpRequest(HttpMethodType.Patch, url)
|
||||
{
|
||||
Body = data,
|
||||
};
|
||||
|
||||
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||
response.RegisterActionFor2XXSuccess(successAction)
|
||||
.RegisterActionFor400BadRequest(badRequestAction)
|
||||
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||
.ExecuteAction();
|
||||
}
|
||||
|
||||
public async Task GetAccountRatedMovies(long id, MovieRatedQueryParameters query, Action<IEnumerable<MovieRatedResponse>>? successAction = null, Action? notFoundAction = null)
|
||||
{
|
||||
string url = GetUrl(EndpointsConfiguration.Accounts.GetAccountRatedMovies, id);
|
||||
|
||||
@@ -21,6 +21,8 @@ public interface IAccountsClientService
|
||||
Task GetAccountInfo(long id, Action<AccountResponse>? successAction = null, Action? notFoundAction = null);
|
||||
Task PutAccountProfileInfo(AccountProfileInfoRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null);
|
||||
Task PatchAccountUsername(AccountUsernameRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null);
|
||||
Task PatchAccountEmail(AccountEmailRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null);
|
||||
Task PatchAccountPassword(AccountPasswordRequest data, Action? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null);
|
||||
Task GetAccountRatedMovies(long id, MovieRatedQueryParameters query, Action<IEnumerable<MovieRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
Task GetAccountRatedSeries(long id, SeriesRatedQueryParameters query, Action<IEnumerable<SeriesRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
Task GetAccountRatedPersons(long id, PersonRatedQueryParameters query, Action<IEnumerable<PersonRatedResponse>>? successAction = null, Action? notFoundAction = null);
|
||||
|
||||
@@ -16,6 +16,8 @@ public class Accounts
|
||||
public string GetAccountInfo { get; set; }
|
||||
public string PutAccountProfileInfo { get; set; }
|
||||
public string PatchAccountUsername { get; set; }
|
||||
public string PatchAccountEmail { get; set; }
|
||||
public string PatchAccountPassword { get; set; }
|
||||
public string GetAccountRatedMovies { get; set; }
|
||||
public string GetAccountRatedSeries { get; set; }
|
||||
public string GetAccountRatedPersons { get; set; }
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<div class="panel">
|
||||
<div class="vstack gap-3">
|
||||
<h4 class="fw-bold">Change email</h4>
|
||||
@if (_data is not null)
|
||||
{
|
||||
<EditForm Model="@(_data)">
|
||||
<AntiforgeryToken/>
|
||||
<div class="container-grid">
|
||||
<div class="row form-group my-1">
|
||||
<label for="email" class="col-2 col-form-label">New email</label>
|
||||
<div class="col-10">
|
||||
<InputText id="email" class="form-control" @bind-Value="_data!.NewEmail"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group my-1">
|
||||
<label for="password" class="col-2 col-form-label">Password</label>
|
||||
<div class="col-10">
|
||||
<InputText id="password" type="password" class="form-control" @bind-Value="_data!.Password"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col align-self-center">
|
||||
@if (!string.IsNullOrWhiteSpace(_error))
|
||||
{
|
||||
<span class="text-danger">@(_error)</span>
|
||||
}
|
||||
else if (_saved)
|
||||
{
|
||||
<span class="text-success">New email saved!</span>
|
||||
}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-secondary" disabled="@(_saving)" @onclick="@(Save)">
|
||||
<LoadingButtonContentComponent IsLoading="@(_saving)" Content="Save" LoadingContent="Saving..."/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</EditForm>
|
||||
}
|
||||
else
|
||||
{
|
||||
<LoadingComponent Color="@(LoadingComponent.LoadingComponentColors.Light)"/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,83 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Website.Services.Client.Accounts;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages.UserEditPage.Panels;
|
||||
|
||||
public partial class NewEmailPanelComponent : ComponentBase
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required AccountResponse AccountData { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private AccountEmailRequest? _data;
|
||||
private string? _error;
|
||||
private bool _saving;
|
||||
private bool _saved;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
_data = new AccountEmailRequest
|
||||
{
|
||||
NewEmail = AccountData.Email,
|
||||
};
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
void Success()
|
||||
{
|
||||
_saved = true;
|
||||
_saving = false;
|
||||
_data = new AccountEmailRequest
|
||||
{
|
||||
NewEmail = _data!.NewEmail
|
||||
};
|
||||
NavigationManager.Refresh(true);
|
||||
}
|
||||
|
||||
void BadRequest(IDictionary<string, string[]> errors)
|
||||
{
|
||||
_error = errors.SelectMany(x => x.Value).FirstOrDefault() ?? "Unknown error";
|
||||
_saving = false;
|
||||
}
|
||||
|
||||
void Unauthorized()
|
||||
{
|
||||
_error = "Incorrect password";
|
||||
_saving = false;
|
||||
}
|
||||
|
||||
_saving = true;
|
||||
_saved = false;
|
||||
_error = null;
|
||||
await AccountsClientService.PatchAccountEmail(_data!, Success, BadRequest, Unauthorized);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<div class="panel">
|
||||
<div class="vstack gap-3">
|
||||
<h4 class="fw-bold">Change password</h4>
|
||||
<EditForm Model="@(_data)">
|
||||
<AntiforgeryToken/>
|
||||
<div class="container-grid">
|
||||
<div class="row form-group my-1">
|
||||
<label for="oldPassword" class="col-2 col-form-label">Old password</label>
|
||||
<div class="col-10">
|
||||
<InputText id="oldPassword" class="form-control" @bind-Value="_data.OldPassword"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group my-1">
|
||||
<label for="newPassword" class="col-2 col-form-label">New password</label>
|
||||
<div class="col-10">
|
||||
<InputText id="newPassword" type="password" class="form-control" @bind-Value="_data.NewPassword"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group my-1">
|
||||
<label for="newPasswordConf" class="col-2 col-form-label">Confirm new password</label>
|
||||
<div class="col-10">
|
||||
<InputText id="newPasswordConf" type="password" class="form-control" @bind-Value="_data.NewPasswordConfirmation"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-2">
|
||||
<div class="col align-self-center">
|
||||
@if (!string.IsNullOrWhiteSpace(_error))
|
||||
{
|
||||
<span class="text-danger">@(_error)</span>
|
||||
}
|
||||
else if (_saved)
|
||||
{
|
||||
<span class="text-success">New email saved!</span>
|
||||
}
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<button type="submit" class="btn btn-secondary" disabled="@(_saving)" @onclick="@(Save)">
|
||||
<LoadingButtonContentComponent IsLoading="@(_saving)" Content="Save" LoadingContent="Saving..."/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</EditForm>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,60 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Website.Services.Client.Accounts;
|
||||
|
||||
namespace WatchIt.Website.Components.Pages.UserEditPage.Panels;
|
||||
|
||||
public partial class NewPasswordPanelComponent : ComponentBase
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private AccountPasswordRequest _data = new AccountPasswordRequest();
|
||||
private string? _error;
|
||||
private bool _saving;
|
||||
private bool _saved;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
void Success()
|
||||
{
|
||||
_saved = true;
|
||||
_saving = false;
|
||||
_data = new AccountPasswordRequest();
|
||||
NavigationManager.Refresh(true);
|
||||
}
|
||||
|
||||
void BadRequest(IDictionary<string, string[]> errors)
|
||||
{
|
||||
_error = errors.SelectMany(x => x.Value).FirstOrDefault() ?? "Unknown error";
|
||||
_saving = false;
|
||||
}
|
||||
|
||||
void Unauthorized()
|
||||
{
|
||||
_error = "Incorrect password";
|
||||
_saving = false;
|
||||
}
|
||||
|
||||
_saving = true;
|
||||
_saved = false;
|
||||
_error = null;
|
||||
await AccountsClientService.PatchAccountPassword(_data, Success, BadRequest, Unauthorized);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -9,7 +9,6 @@ public partial class NewUsernamePanelComponent : ComponentBase
|
||||
{
|
||||
#region SERVICES
|
||||
|
||||
[Inject] private IAuthenticationService AuthenticationService { get; set; } = default!;
|
||||
[Inject] private IAccountsClientService AccountsClientService { get; set; } = default!;
|
||||
[Inject] private NavigationManager NavigationManager { get; set; } = default!;
|
||||
|
||||
@@ -19,7 +18,7 @@ public partial class NewUsernamePanelComponent : ComponentBase
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required long Id { get; set; }
|
||||
[Parameter] public required AccountResponse AccountData { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -42,21 +41,11 @@ public partial class NewUsernamePanelComponent : ComponentBase
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
User? user = await AuthenticationService.GetUserAsync();
|
||||
|
||||
if (user is null)
|
||||
_data = new AccountUsernameRequest
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await AccountsClientService.GetAccountInfo(user.Id, data =>
|
||||
{
|
||||
_data = new AccountUsernameRequest
|
||||
{
|
||||
NewUsername = data.Username
|
||||
};
|
||||
StateHasChanged();
|
||||
});
|
||||
NewUsername = AccountData.Username,
|
||||
};
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<option value="@(default(short?))">No choice</option>
|
||||
@foreach (GenderResponse gender in _genders)
|
||||
{
|
||||
<option value="@(gender.Id)">@(gender.Name)</option>
|
||||
<option value="@(gender.Id)">@(gender.Name)</option>
|
||||
}
|
||||
</InputSelect>
|
||||
</div>
|
||||
|
||||
@@ -20,7 +20,7 @@ public partial class ProfileEditFormPanelComponent : ComponentBase
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public long Id { get; set; }
|
||||
[Parameter] public required AccountResponse AccountData { get; set; }
|
||||
[Parameter] public string Class { get; set; } = string.Empty;
|
||||
|
||||
#endregion
|
||||
@@ -47,11 +47,8 @@ public partial class ProfileEditFormPanelComponent : ComponentBase
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await Task.WhenAll(
|
||||
[
|
||||
GendersClientService.GetAllGenders(successAction: data => _genders = data),
|
||||
AccountsClientService.GetAccountInfo(Id, data => _accountProfileInfo = new AccountProfileInfoRequest(data))
|
||||
]);
|
||||
_accountProfileInfo = new AccountProfileInfoRequest(AccountData);
|
||||
await GendersClientService.GetAllGenders(successAction: data => _genders = data);
|
||||
|
||||
_loaded = true;
|
||||
StateHasChanged();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="panel" role="button" @onclick="@(() => NavigationManager.NavigateTo("/user"))">
|
||||
<div class="d-flex gap-3 align-items-center">
|
||||
<AccountPictureComponent @ref="_accountPicture" Id="@(User.Id)" Size="60"/>
|
||||
<AccountPictureComponent @ref="_accountPicture" Id="@(AccountData.Id)" Size="60"/>
|
||||
<div class="d-flex-inline flex-column">
|
||||
<h2 id="username" class="fw-bold m-0">@(_username ?? "Loading...")</h2>
|
||||
<h2 id="username" class="fw-bold m-0">@(AccountData.Username)</h2>
|
||||
<span id="secondaryText" class="text-secondary">User settings</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Website.Components.Common.Subcomponents;
|
||||
using WatchIt.Website.Services.Authentication;
|
||||
using WatchIt.Website.Services.Client.Accounts;
|
||||
@@ -18,7 +19,7 @@ public partial class UserEditPageHeaderPanelComponent : ComponentBase
|
||||
|
||||
#region PARAMETERS
|
||||
|
||||
[Parameter] public required User User { get; set; }
|
||||
[Parameter] public required AccountResponse AccountData { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -27,7 +28,6 @@ public partial class UserEditPageHeaderPanelComponent : ComponentBase
|
||||
#region FIELDS
|
||||
|
||||
private AccountPictureComponent _accountPicture = default!;
|
||||
private string? _username;
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -38,22 +38,4 @@ public partial class UserEditPageHeaderPanelComponent : ComponentBase
|
||||
public async Task ReloadPicture() => await _accountPicture.Reload();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region PRIVATE METHODS
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if (firstRender)
|
||||
{
|
||||
await AccountsClientService.GetAccountInfo(User.Id, data =>
|
||||
{
|
||||
_username = data.Username;
|
||||
StateHasChanged();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
@{
|
||||
StringBuilder sb = new StringBuilder(" - WatchIt");
|
||||
|
||||
if (_user is null) sb.Insert(0, "Loading...");
|
||||
if (_accountData is null) sb.Insert(0, "Loading...");
|
||||
else sb.Insert(0, "User settings");
|
||||
|
||||
<PageTitle>@(sb.ToString())</PageTitle>
|
||||
@@ -18,11 +18,11 @@
|
||||
|
||||
|
||||
<div class="container-grid">
|
||||
@if (_user is not null)
|
||||
@if (_accountData is not null)
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<UserEditPageHeaderPanelComponent @ref="@(_header)" User="@(_user)"/>
|
||||
<UserEditPageHeaderPanelComponent @ref="@(_header)" AccountData="@(_accountData)"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-default">
|
||||
@@ -45,7 +45,7 @@
|
||||
</div>
|
||||
<div class="row mt-default gx-default">
|
||||
<div class="col-auto">
|
||||
<PictureEditorPanelComponent Id="@(_user.Id)"
|
||||
<PictureEditorPanelComponent Id="@(_accountData.Id)"
|
||||
Class="h-100"
|
||||
PicturePlaceholder="assets/user_placeholder.png"
|
||||
Circle="true"
|
||||
@@ -55,13 +55,13 @@
|
||||
OnPictureChanged="@(async (_) => await PictureChanged())"/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<ProfileEditFormPanelComponent Id="@(_user.Id)"
|
||||
<ProfileEditFormPanelComponent AccountData="@(_accountData)"
|
||||
Class="h-100"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-default">
|
||||
<div class="col">
|
||||
<ProfileBackgroundEditorPanelComponent Id="@(_user.Id)"
|
||||
<ProfileBackgroundEditorPanelComponent Id="@(_accountData.Id)"
|
||||
OnBackgroundChanged="BackgroundChanged"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -70,7 +70,9 @@
|
||||
<TabPanel Name="account">
|
||||
<div class="vstack mt-default gap-default">
|
||||
<AccountEditHeaderPanelComponent/>
|
||||
<NewUsernamePanelComponent Id="@(_user.Id)"/>
|
||||
<NewUsernamePanelComponent AccountData="@(_accountData)"/>
|
||||
<NewEmailPanelComponent AccountData="@(_accountData)"/>
|
||||
<NewPasswordPanelComponent/>
|
||||
</div>
|
||||
</TabPanel>
|
||||
</Content>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using WatchIt.Common.Model;
|
||||
using WatchIt.Common.Model.Accounts;
|
||||
using WatchIt.Common.Model.Photos;
|
||||
using WatchIt.Website.Components.Pages.UserEditPage.Panels;
|
||||
using WatchIt.Website.Layout;
|
||||
@@ -31,7 +32,7 @@ public partial class UserEditPage : ComponentBase
|
||||
|
||||
#region FIELDS
|
||||
|
||||
private User? _user;
|
||||
private AccountResponse? _accountData;
|
||||
|
||||
private UserEditPageHeaderPanelComponent _header = default!;
|
||||
|
||||
@@ -47,15 +48,19 @@ public partial class UserEditPage : ComponentBase
|
||||
{
|
||||
Layout.BackgroundPhoto = null;
|
||||
|
||||
_user = await AuthenticationService.GetUserAsync();
|
||||
if (_user is null)
|
||||
User? user = await AuthenticationService.GetUserAsync();
|
||||
if (user is null)
|
||||
{
|
||||
NavigationManager.NavigateTo($"/auth?redirect_to={WebUtility.UrlEncode("/user/edit")}");
|
||||
return;
|
||||
}
|
||||
StateHasChanged();
|
||||
|
||||
await AccountsClientService.GetAccountProfileBackground(_user.Id, data => Layout.BackgroundPhoto = data);
|
||||
await Task.WhenAll(
|
||||
[
|
||||
AccountsClientService.GetAccountInfo(user.Id, data => _accountData = data),
|
||||
AccountsClientService.GetAccountProfileBackground(user.Id, data => Layout.BackgroundPhoto = data)
|
||||
]);
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
"GetAccountInfo": "/{0}/info",
|
||||
"PutAccountProfileInfo": "/profile_info",
|
||||
"PatchAccountUsername": "/username",
|
||||
"PatchAccountEmail": "/email",
|
||||
"PatchAccountPassword": "/password",
|
||||
"GetAccountRatedMovies": "/{0}/movies",
|
||||
"GetAccountRatedSeries": "/{0}/series",
|
||||
"GetAccountRatedPersons": "/{0}/persons"
|
||||
|
||||
Reference in New Issue
Block a user