Merge pull request #147 from mateuszskoczek/features/profile_info_endpoints
Features/profile info endpoints
This commit is contained in:
19
WatchIt.Common/WatchIt.Common.Model/Accounts/Account.cs
Normal file
19
WatchIt.Common/WatchIt.Common.Model/Accounts/Account.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Accounts;
|
||||||
|
|
||||||
|
public abstract class Account
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
[JsonPropertyName("username")]
|
||||||
|
public required string Username { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("email")]
|
||||||
|
public required string Email { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("description")]
|
||||||
|
public string? Description { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Accounts;
|
||||||
|
|
||||||
|
public class AccountRequest : Account
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
[JsonPropertyName("gender_id")]
|
||||||
|
public short? GenderId { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region PUBLIC METHODS
|
||||||
|
|
||||||
|
public void UpdateAccount(Database.Model.Account.Account account)
|
||||||
|
{
|
||||||
|
account.Username = Username;
|
||||||
|
account.Email = Email;
|
||||||
|
account.Description = Description;
|
||||||
|
account.GenderId = GenderId;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using WatchIt.Common.Model.Genders;
|
||||||
|
|
||||||
|
namespace WatchIt.Common.Model.Accounts;
|
||||||
|
|
||||||
|
public class AccountResponse : Account
|
||||||
|
{
|
||||||
|
#region PROPERTIES
|
||||||
|
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public required long Id { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("gender")]
|
||||||
|
public GenderResponse? Gender { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region CONSTRUCTORS
|
||||||
|
|
||||||
|
[SetsRequiredMembers]
|
||||||
|
public AccountResponse(Database.Model.Account.Account account)
|
||||||
|
{
|
||||||
|
Id = account.Id;
|
||||||
|
Username = account.Username;
|
||||||
|
Email = account.Email;
|
||||||
|
Description = account.Description;
|
||||||
|
Gender = account.Gender is not null ? new GenderResponse(account.Gender) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ public class RegisterResponse
|
|||||||
public RegisterResponse() {}
|
public RegisterResponse() {}
|
||||||
|
|
||||||
[SetsRequiredMembers]
|
[SetsRequiredMembers]
|
||||||
public RegisterResponse(Account account)
|
public RegisterResponse(Database.Model.Account.Account account)
|
||||||
{
|
{
|
||||||
Id = account.Id;
|
Id = account.Id;
|
||||||
Username = account.Username;
|
Username = account.Username;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using WatchIt.Common.Model.Accounts;
|
using WatchIt.Common.Model.Accounts;
|
||||||
@@ -41,4 +42,24 @@ public class AccountsController(IAccountsControllerService accountsControllerSer
|
|||||||
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
[ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult> GetAccountProfilePicture([FromRoute(Name = "id")]long id) => await accountsControllerService.GetAccountProfilePicture(id);
|
public async Task<ActionResult> GetAccountProfilePicture([FromRoute(Name = "id")]long id) => await accountsControllerService.GetAccountProfilePicture(id);
|
||||||
|
|
||||||
|
[HttpGet("{id}/info")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
[ProducesResponseType(typeof(AccountResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetAccountInfo([FromRoute]long id) => await accountsControllerService.GetAccountInfo(id);
|
||||||
|
|
||||||
|
[HttpGet("info")]
|
||||||
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
|
[ProducesResponseType(typeof(AccountResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> GetAccountInfo() => await accountsControllerService.GetAccountInfo();
|
||||||
|
|
||||||
|
[HttpPut("info")]
|
||||||
|
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
|
||||||
|
[ProducesResponseType(typeof(AccountResponse), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
|
public async Task<ActionResult> PutAccountInfo([FromBody]AccountRequest data) => await accountsControllerService.PutAccountInfo(data);
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,7 @@ using WatchIt.WebAPI.Services.Controllers.Common;
|
|||||||
using WatchIt.WebAPI.Services.Utility.Tokens;
|
using WatchIt.WebAPI.Services.Utility.Tokens;
|
||||||
using WatchIt.WebAPI.Services.Utility.Tokens.Exceptions;
|
using WatchIt.WebAPI.Services.Utility.Tokens.Exceptions;
|
||||||
using WatchIt.WebAPI.Services.Utility.User;
|
using WatchIt.WebAPI.Services.Utility.User;
|
||||||
|
using Account = WatchIt.Database.Model.Account.Account;
|
||||||
using AccountProfilePicture = WatchIt.Common.Model.Accounts.AccountProfilePicture;
|
using AccountProfilePicture = WatchIt.Common.Model.Accounts.AccountProfilePicture;
|
||||||
|
|
||||||
namespace WatchIt.WebAPI.Services.Controllers.Accounts;
|
namespace WatchIt.WebAPI.Services.Controllers.Accounts;
|
||||||
@@ -129,6 +130,31 @@ public class AccountsControllerService(
|
|||||||
return RequestResult.Ok(picture);
|
return RequestResult.Ok(picture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> GetAccountInfo() => await GetAccountInfo(userService.GetUserId());
|
||||||
|
public async Task<RequestResult> GetAccountInfo(long id)
|
||||||
|
{
|
||||||
|
Account? account = await database.Accounts.FirstOrDefaultAsync(x => x.Id == id);
|
||||||
|
if (account is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
AccountResponse response = new AccountResponse(account);
|
||||||
|
return RequestResult.Ok(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<RequestResult> PutAccountInfo(AccountRequest data)
|
||||||
|
{
|
||||||
|
Account? account = await database.Accounts.FirstOrDefaultAsync(x => x.Id == userService.GetUserId());
|
||||||
|
if (account is null)
|
||||||
|
{
|
||||||
|
return RequestResult.NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
data.UpdateAccount(account);
|
||||||
|
return RequestResult.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,4 +10,7 @@ public interface IAccountsControllerService
|
|||||||
Task<RequestResult> AuthenticateRefresh();
|
Task<RequestResult> AuthenticateRefresh();
|
||||||
Task<RequestResult> Logout();
|
Task<RequestResult> Logout();
|
||||||
Task<RequestResult> GetAccountProfilePicture(long id);
|
Task<RequestResult> GetAccountProfilePicture(long id);
|
||||||
|
Task<RequestResult> GetAccountInfo();
|
||||||
|
Task<RequestResult> GetAccountInfo(long id);
|
||||||
|
Task<RequestResult> PutAccountInfo(AccountRequest data);
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Security.Claims;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
using System.Security.Claims;
|
||||||
using WatchIt.Database;
|
using WatchIt.Database;
|
||||||
|
|
||||||
namespace WatchIt.WebAPI.Services.Utility.User;
|
namespace WatchIt.WebAPI.Services.Utility.User;
|
||||||
@@ -53,5 +54,17 @@ public class UserValidator
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserValidator MustHaveId(long id)
|
||||||
|
{
|
||||||
|
Claim adminClaim = _claimsPrincipal.FindFirst(x => x.Type == JwtRegisteredClaimNames.Sub)!;
|
||||||
|
if (adminClaim.Value == id.ToString())
|
||||||
|
{
|
||||||
|
IsValid = false;
|
||||||
|
_validationErrors.Add("User have wrong id");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using FluentValidation;
|
||||||
|
using WatchIt.Common.Model.Accounts;
|
||||||
|
using WatchIt.Database;
|
||||||
|
|
||||||
|
namespace WatchIt.WebAPI.Validators.Accounts;
|
||||||
|
|
||||||
|
public class AccountRequestValidator : AbstractValidator<AccountRequest>
|
||||||
|
{
|
||||||
|
public AccountRequestValidator(DatabaseContext database)
|
||||||
|
{
|
||||||
|
RuleFor(x => x.Username).NotEmpty()
|
||||||
|
.MaximumLength(50);
|
||||||
|
RuleFor(x => x.Email).EmailAddress()
|
||||||
|
.MaximumLength(320);
|
||||||
|
RuleFor(x => x.Description).MaximumLength(1000);
|
||||||
|
When(x => x.GenderId.HasValue, () =>
|
||||||
|
{
|
||||||
|
RuleFor(x => x.GenderId!.Value).MustBeIn(database.Genders.Select(x => x.Id));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,6 +46,7 @@ public static class Program
|
|||||||
|
|
||||||
while (!dbContext.Database.CanConnect())
|
while (!dbContext.Database.CanConnect())
|
||||||
{
|
{
|
||||||
|
app.Logger.LogInformation("Waiting for database...");
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,4 +8,7 @@ public class Accounts
|
|||||||
public string AuthenticateRefresh { get; set; }
|
public string AuthenticateRefresh { get; set; }
|
||||||
public string Logout { get; set; }
|
public string Logout { get; set; }
|
||||||
public string GetProfilePicture { get; set; }
|
public string GetProfilePicture { get; set; }
|
||||||
|
public string GetAccountInfoById { get; set; }
|
||||||
|
public string GetAccountInfo { get; set; }
|
||||||
|
public string PutAccountInfo { get; set; }
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,45 @@ public class AccountsWebAPIService(IHttpClientService httpClientService, IConfig
|
|||||||
.ExecuteAction();
|
.ExecuteAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task GetAccountInfoById(long id, Action<AccountResponse>? successAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.GetAccountInfoById, id);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GetAccountInfo(Action<AccountResponse>? successAction = null, Action? unauthorizedAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.GetAccountInfo);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Get, url);
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PutAccountInfo(AccountRequest data, Action<AccountResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null, Action? notFoundAction = null)
|
||||||
|
{
|
||||||
|
string url = GetUrl(EndpointsConfiguration.Accounts.PutAccountInfo);
|
||||||
|
HttpRequest request = new HttpRequest(HttpMethodType.Put, url)
|
||||||
|
{
|
||||||
|
Body = data,
|
||||||
|
};
|
||||||
|
|
||||||
|
HttpResponse response = await httpClientService.SendRequestAsync(request);
|
||||||
|
response.RegisterActionFor2XXSuccess(successAction)
|
||||||
|
.RegisterActionFor400BadRequest(badRequestAction)
|
||||||
|
.RegisterActionFor401Unauthorized(unauthorizedAction)
|
||||||
|
.RegisterActionFor404NotFound(notFoundAction)
|
||||||
|
.ExecuteAction();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,7 @@ public interface IAccountsWebAPIService
|
|||||||
Task AuthenticateRefresh(Action<AuthenticateResponse>? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null);
|
Task AuthenticateRefresh(Action<AuthenticateResponse>? successAction = null, Action? unauthorizedAction = null, Action? forbiddenAction = null);
|
||||||
Task Logout(Action? successAction = null);
|
Task Logout(Action? successAction = null);
|
||||||
Task GetAccountProfilePicture(long id, Action<AccountProfilePictureResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? notFoundAction = null);
|
Task GetAccountProfilePicture(long id, Action<AccountProfilePictureResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? notFoundAction = null);
|
||||||
|
Task GetAccountInfoById(long id, Action<AccountResponse>? successAction = null, Action? notFoundAction = null);
|
||||||
|
Task GetAccountInfo(Action<AccountResponse>? successAction = null, Action? unauthorizedAction = null, Action? notFoundAction = null);
|
||||||
|
Task PutAccountInfo(AccountRequest data, Action<AccountResponse>? successAction = null, Action<IDictionary<string, string[]>>? badRequestAction = null, Action? unauthorizedAction = null, Action? notFoundAction = null);
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,10 @@
|
|||||||
"Authenticate": "/authenticate",
|
"Authenticate": "/authenticate",
|
||||||
"AuthenticateRefresh": "/authenticate-refresh",
|
"AuthenticateRefresh": "/authenticate-refresh",
|
||||||
"Logout": "/logout",
|
"Logout": "/logout",
|
||||||
"GetProfilePicture": "/{0}/profile-picture"
|
"GetProfilePicture": "/{0}/profile-picture",
|
||||||
|
"GetAccountInfoById": "/{0}/info",
|
||||||
|
"GetAccountInfo": "/info",
|
||||||
|
"PutAccountInfo": "/info"
|
||||||
},
|
},
|
||||||
"Genders": {
|
"Genders": {
|
||||||
"Base": "/genders",
|
"Base": "/genders",
|
||||||
|
|||||||
Reference in New Issue
Block a user