Add user profile endpoints

This commit is contained in:
Jiří Vrabec 2025-08-11 22:08:13 +02:00
parent 84e16d655d
commit 602496ec08
7 changed files with 147 additions and 41 deletions

View file

@ -1,6 +0,0 @@
namespace DrinkRateAPI.ApiModels.UserProfile;
public class UserProfileAdminStatusPut
{
public bool ChangeStatusTo { get; set; }
}

View file

@ -2,5 +2,28 @@ namespace DrinkRateAPI.ApiModels.UserProfile;
public class UserProfileGet
{
/// <summary>
/// User profile ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// User profile name
/// </summary>
public string UserName { get; set; }
/// <summary>
/// Is user admin
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// Is user deleted
/// </summary>
public bool IsDeleted { get; set; }
/// <summary>
/// Applicaton user ID of the user profile
/// </summary>
public string ApplicationUserId { get; set; }
}

View file

@ -1,6 +1,9 @@
namespace DrinkRateAPI.ApiModels.UserProfile;
public class UserProfilePut
public class UserProfilePut : UserProfileSelfPut
{
public string UserName { get; set; }
/// <summary>
/// Is user admin
/// </summary>
public bool? IsAdmin { get; set; }
}

View file

@ -0,0 +1,9 @@
namespace DrinkRateAPI.ApiModels.UserProfile;
public class UserProfileSelfPut
{
/// <summary>
/// User profile name
/// </summary>
public string? UserName { get; set; }
}

View file

@ -1,4 +1,3 @@
using System.Security.Claims;
using DrinkRateAPI.ApiModels.UserProfile;
using DrinkRateAPI.Services;
using Microsoft.AspNetCore.Authorization;
@ -10,30 +9,40 @@ namespace DrinkRateAPI.Controllers;
[Route("userProfile")]
public class UserProfileController : ControllerBase
{
private readonly ILogger<UserProfileController> _logger;
private readonly UserProfileService _userProfileService;
public UserProfileController(ILogger<UserProfileController> logger, UserProfileService userProfileService)
public UserProfileController(UserProfileService userProfileService)
{
_logger = logger;
_userProfileService = userProfileService;
}
[HttpPut]
public UserProfileGet PutUserProfile([FromBody] UserProfilePut userProfile)
[Produces("application/json")]
public async Task<UserProfileGet> PutUserProfileSelf([FromBody] UserProfileSelfPut userProfile)
{
throw new ApplicationException();
var x = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; //HttpContext.User.Identities.First();
return new();
return await _userProfileService.PutUserProfileSelfAsync(User, userProfile);
}
[HttpPut("{userId}/adminStatus")]
[HttpGet]
[Produces("application/json")]
public async Task<UserProfileGet> GetUserProfileSelf()
{
return await _userProfileService.GetUserProfileSelfAsync(User);
}
[HttpPut("{userId}")]
[Authorize(Policy = "AdminOnly")]
[Produces("application/json")]
public async Task<IActionResult> PutUserAdminStatus(string userId, [FromBody] UserProfileAdminStatusPut body)
public async Task<UserProfileGet> PutUserProfile(string userId, [FromBody] UserProfilePut userProfile)
{
var changedProfile = await _userProfileService.PutUserProfileAdminStatusAsync(userId, body.ChangeStatusTo);
return await _userProfileService.PutUserProfileAsync(User, userProfile, userId);
}
return Ok(changedProfile);
[HttpGet("{userId}")]
[Authorize(Policy = "AdminOnly")]
[Produces("application/json")]
public async Task<UserProfileGet> GetUserProfile(string userId)
{
return await _userProfileService.GetUserProfileAsync(User, userId);
}
}

View file

@ -20,6 +20,5 @@ public class DbUserProfile : DbEntityWithHistory
public bool IsDeleted { get; set; }
public Guid ApplicationUserId { get; set; }
public virtual DbApplicationUser ApplicationUser { get; set; }
}

View file

@ -2,12 +2,8 @@ using System.Security.Claims;
using DrinkRateAPI.ApiModels.UserProfile;
using DrinkRateAPI.Contexts;
using DrinkRateAPI.DbEntities;
using DrinkRateAPI.DbEntities;
using DrinkRateAPI.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace DrinkRateAPI.Services;
@ -21,29 +17,102 @@ public class UserProfileService(ApplicationDbContext context, ApplicationUserSer
return userProfile.IsAdmin;
}
public async Task<DbUserProfile> PutUserProfileAdminStatusAsync(string userId, bool changeStatusTo)
public async Task<UserProfileGet> PutUserProfileSelfAsync(ClaimsPrincipal identity, UserProfileSelfPut userProfileSelfPut)
{
var userProfile = GetUserProfileById(userId);
userProfile.IsAdmin = changeStatusTo;
var authenticatedUser = await _applicationUserService.UserProfileByApplicationUserAsync(identity);
var userId = authenticatedUser.Id.ToString();
await PutUserProfile(userProfileSelfPut, userId, false);
return await GetUserProfile(userId);
}
public async Task<UserProfileGet> GetUserProfileSelfAsync(ClaimsPrincipal identity)
{
var authenticatedUser = await _applicationUserService.UserProfileByApplicationUserAsync(identity);
var userId = authenticatedUser.Id.ToString();
return await GetUserProfile(userId);
}
public async Task<UserProfileGet> PutUserProfileAsync(ClaimsPrincipal identity, UserProfilePut userProfilePut, string userId)
{
var authenticatedUser = await _applicationUserService.UserProfileByApplicationUserAsync(identity);
if (authenticatedUser.Id.ToString() == userId)
{
// Prevent admin de-admining him/herself
await PutUserProfile(userProfilePut, userId, false);
}
else
{
await PutUserProfile(userProfilePut, userId, IsUserProfileAdmin(authenticatedUser));
}
return await GetUserProfile(userId);
}
public async Task<UserProfileGet> GetUserProfileAsync(ClaimsPrincipal identity, string userId)
{
var authenticatedUser = await _applicationUserService.UserProfileByApplicationUserAsync(identity);
return await GetUserProfile(userId);
}
private async Task PutUserProfile<TUserProfilePut>(TUserProfilePut userProfilePut, string userId, bool byAdmin) where TUserProfilePut : UserProfileSelfPut
{
var userProfile = await GetUserProfileById(userId);
if (!string.IsNullOrEmpty(userProfilePut.UserName) && userProfile.UserName != userProfilePut.UserName)
{
var userByName = await TryGetUserProfileByUserName(userProfilePut.UserName);
if (userByName == null)
{
userProfile.UserName = userProfilePut.UserName;
}
else
{
throw new BadRequestException($"User with username {userProfilePut.UserName} already exists");
}
}
if (byAdmin && userProfilePut is UserProfilePut adminPut && adminPut.IsAdmin != null)
{
userProfile.IsAdmin = (bool)adminPut.IsAdmin;
}
_context.UserProfiles.Update(userProfile);
await _context.SaveChangesAsync();
return userProfile;
}
public async Task<UserProfileGet> PutUserProfileAsync(UserProfilePut userProfile, ClaimsPrincipal identity)
{
var profile = _applicationUserService.UserProfileByApplicationUserAsync(identity);
return new();
}
public DbUserProfile GetUserProfileById(string userId)
private async Task<UserProfileGet> GetUserProfile(string userId)
{
var userProfile = _context.UserProfiles.FirstOrDefault(x => x.Id.ToString() == userId);
var userProfile = await GetUserProfileById(userId);
var userProfileGet = new UserProfileGet
{
Id = userProfile.Id.ToString(),
UserName = userProfile.UserName,
IsAdmin = userProfile.IsAdmin,
IsDeleted = userProfile.IsDeleted,
ApplicationUserId = userProfile.ApplicationUserId.ToString(),
};
return userProfileGet;
}
private async Task<DbUserProfile> GetUserProfileById(string userId)
{
var userProfile = await _context.UserProfiles.FirstOrDefaultAsync(x => x.Id.ToString() == userId);
return userProfile ?? throw new NotFoundException();
}
private async Task<DbUserProfile?> TryGetUserProfileByUserName(string userName)
{
var userProfile = await _context.UserProfiles.FirstOrDefaultAsync(x => x.UserName == userName);
return userProfile;
}
}