Skip to content

Instantly share code, notes, and snippets.

@sadukie
Last active April 10, 2025 13:54
Show Gist options
  • Save sadukie/355a0f029bc571655f783e6ee55d5d43 to your computer and use it in GitHub Desktop.
Save sadukie/355a0f029bc571655f783e6ee55d5d43 to your computer and use it in GitHub Desktop.
eShopOnWeb - User Management - API + Tests
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
namespace Microsoft.eShopWeb.PublicApi.Extensions;
public static class ApplicationUserExtensions
{
public static UserDto ToUserDto(this ApplicationUser user)
{
UserDto dto = new UserDto();
if (user != null)
{
dto.Id = user.Id;
dto.UserName = user.UserName;
dto.Email = user.Email;
dto.PhoneNumber = user.PhoneNumber;
dto.EmailConfirmed = user.EmailConfirmed;
dto.PhoneNumberConfirmed = user.PhoneNumberConfirmed;
dto.LockoutEnd = user.LockoutEnd;
}
return dto;
}
public static void FromUserDto(this ApplicationUser user, UserDto userChanges, bool copyId = true)
{
if (user != null)
{
if (copyId)
user.Id = userChanges.Id;
user.UserName = userChanges.UserName;
user.Email = userChanges.Email;
user.PhoneNumber = userChanges.PhoneNumber;
user.EmailConfirmed = userChanges.EmailConfirmed;
user.PhoneNumberConfirmed = userChanges.PhoneNumberConfirmed;
user.LockoutEnd = userChanges.LockoutEnd;
}
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class CreateUserRequest : BaseRequest
{
public UserDto User { get; set; }
}
using System;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class CreateUserResponse : BaseResponse
{
public CreateUserResponse(Guid correlationId)
{
}
public CreateUserResponse() { }
public string UserId { get; set; }
}
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.ApplicationCore.Constants;
using Microsoft.eShopWeb.ApplicationCore.Exceptions;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.Extensions;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class CreateUserEndpoint(UserManager<ApplicationUser> userManager) : Endpoint<CreateUserRequest, CreateUserResponse>
{
public override void Configure()
{
Post("api/users");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
d.Produces<CreateUserResponse>()
.WithTags("UserManagementEndpoints")
);
}
public override async Task HandleAsync(CreateUserRequest request, CancellationToken ct)
{
var response = new CreateUserResponse(request.CorrelationId());
if (request is null || request.User is null || request.User.UserName is null)
{
await SendErrorsAsync(400, ct);
return;
}
var existingUser = await userManager.FindByNameAsync(request.User.UserName);
if (existingUser != null) {
throw new DuplicateException($"User already exists.");
};
ApplicationUser newUser = new ApplicationUser();
newUser.FromUserDto(request.User, copyId: false);
var createUser = await userManager.CreateAsync(newUser);
if (createUser.Succeeded)
{
var createdUser = await userManager.FindByNameAsync(request.User.UserName);
await userManager.AddPasswordAsync(createdUser!, AuthorizationConstants.DEFAULT_PASSWORD);
response.UserId = createdUser!.Id;
await SendCreatedAtAsync<UserGetByIdEndpoint>(new { UserId = createdUser!.Id }, response, cancellation: ct);
}
}
}
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class CreateUserEndpointTest
{
private readonly string _testName = "[email protected]";
[TestMethod]
public async Task ReturnsForbiddenGivenNormalUserToken()
{
var jsonContent = GetValidNewItemJson(_testName);
var client = HttpClientHelper.GetNormalUserClient();
var response = await client.PostAsync("api/users", jsonContent);
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}
[TestMethod]
public async Task ReturnsSuccessGivenValidNewItemAndAdminUserToken()
{
var jsonContent = GetValidNewItemJson(_testName);
var client = HttpClientHelper.GetAdminClient();
var response = await client.PostAsync("api/users", jsonContent);
response.EnsureSuccessStatusCode();
Assert.AreEqual(HttpStatusCode.Created, response.StatusCode);
var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<CreateUserResponse>();
Assert.IsNotNull(model);
Assert.IsTrue(!string.IsNullOrEmpty(model.UserId));
}
[TestMethod]
public async Task ReturnsConflictForDuplicateUserName()
{
var jsonContent = GetValidNewItemJson("[email protected]");
var client = HttpClientHelper.GetAdminClient();
var response = await client.PostAsync("api/users", jsonContent);
Assert.AreEqual(HttpStatusCode.Conflict, response.StatusCode);
}
[TestMethod]
public async Task ReturnsBadRequestForMissingUserName()
{
var jsonContent = GetInvalidNewItemJson();
var client = HttpClientHelper.GetAdminClient();
var response = await client.PostAsync("api/users", jsonContent);
Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode);
}
private StringContent GetValidNewItemJson(string userName)
{
var newUser = new UserDto()
{
UserName = userName
};
var request = new CreateUserRequest
{
User = newUser
};
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
return jsonContent;
}
private StringContent GetInvalidNewItemJson()
{
var newUser = new UserDto()
{
};
var request = new CreateUserRequest
{
User = newUser
};
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
return jsonContent;
}
}
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class DeleteUserEndpoint(UserManager<ApplicationUser> userManager) : Endpoint<DeleteUserRequest, Results<NoContent, NotFound, BadRequest>>
{
public override void Configure()
{
Delete("api/users/{userId}");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
{
d.Produces(StatusCodes.Status204NoContent);
d.Produces(StatusCodes.Status404NotFound);
d.Produces(StatusCodes.Status409Conflict);
d.WithTags("UserManagementEndpoints");
}
);
}
public override async Task<Results<NoContent, NotFound, BadRequest>> ExecuteAsync(DeleteUserRequest request, CancellationToken ct)
{
var userToDelete = await userManager.FindByIdAsync(request.UserId);
if (userToDelete is null || string.IsNullOrEmpty(userToDelete.UserName))
{
return TypedResults.NotFound();
}
if (userToDelete.UserName == "[email protected]")
{
return TypedResults.BadRequest();
}
await userManager.DeleteAsync(userToDelete);
return TypedResults.NoContent();
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class DeleteUserRequest : BaseRequest
{
public string UserId { get; init; }
public DeleteUserRequest(string userId)
{
UserId = userId;
}
}
using System.Net;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class DeleteUserEndpointTest
{
[TestMethod]
public async Task ReturnsNotFoundGivenInvalidIdAndAdminUserToken()
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.DeleteAsync("api/users/0");
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
}
[TestMethod]
public async Task ReturnsForbiddenGivenProductManagerToken()
{
var client = HttpClientHelper.GetProductManagerClient();
var response = await client.DeleteAsync("api/users/0");
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}
[TestMethod]
public async Task ReturnsForbiddenGivenNormalUserToken()
{
var client = HttpClientHelper.GetNormalUserClient();
var response = await client.DeleteAsync("api/users/0");
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}
[TestMethod]
public async Task ReturnsBadRequestTryingToDeleteAdminUser()
{
var client = HttpClientHelper.GetAdminClient();
var userName = "[email protected]";
var response = await client.GetAsync($"api/users/name/{userName}");
var adminUserResponse = await response.Content.ReadAsStringAsync();
var adminUser = adminUserResponse.FromJson<GetUserResponse>();
var deleteResponse = await client.DeleteAsync($"api/users/{adminUser!.User!.Id}");
Assert.AreEqual(HttpStatusCode.BadRequest, deleteResponse.StatusCode);
}
}
using System;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
public class GetUserResponse : BaseResponse
{
public GetUserResponse(Guid correlationId) : base(correlationId)
{
}
public GetUserResponse()
{
}
public UserDto User { get; set; }
}
using System;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
public class GetUserResponse : BaseResponse
{
public GetUserResponse(Guid correlationId) : base(correlationId)
{
}
public GetUserResponse()
{
}
public UserDto User { get; set; }
}
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class SaveRolesForUserEndpoint(UserManager<ApplicationUser> userManager) : Endpoint<SaveRolesForUserRequest, Results<Ok, NotFound, BadRequest>>
{
public override void Configure()
{
Put("api/users/{userId}/roles");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
{
d.Produces(StatusCodes.Status200OK);
d.Produces(StatusCodes.Status404NotFound);
d.WithTags("UserManagementEndpoints");
}
);
}
public override async Task<Results<Ok, NotFound, BadRequest>> ExecuteAsync(SaveRolesForUserRequest request, CancellationToken ct)
{
var userToUpdate = await userManager.FindByIdAsync(request.UserId);
if (userToUpdate is null)
{
return TypedResults.NotFound();
}
if (string.IsNullOrEmpty(userToUpdate.UserName))
{
throw new System.Exception("Unknown user to update");
}
if (userToUpdate.UserName == "[email protected]")
{
return TypedResults.BadRequest();
}
if (request.RolesToAdd.Count > 0)
await userManager.AddToRolesAsync(userToUpdate,request.RolesToAdd);
if (request.RolesToRemove.Count > 0)
await userManager.RemoveFromRolesAsync(userToUpdate,request.RolesToRemove);
return TypedResults.Ok();
}
}
using System.Collections.Generic;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class SaveRolesForUserRequest : BaseRequest
{
public string UserId { get; set; }
public List<string> RolesToAdd { get; set; } = [];
public List<string> RolesToRemove { get; set; } = [];
}
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.Extensions;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UpdateRoleEndpoint(UserManager<ApplicationUser> userManager) : Endpoint<UpdateUserRequest,Results<Ok<UpdateUserResponse>,NotFound>>
{
public override void Configure()
{
Put("api/users");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
d.Produces<UpdateUserResponse>()
.WithTags("UserManagementEndpoints"));
}
public override async Task<Results<Ok<UpdateUserResponse>, NotFound>> ExecuteAsync(UpdateUserRequest request, CancellationToken ct)
{
var response = new UpdateUserResponse(request.CorrelationId());
if (request is null || request.User is null || request.User.Id is null)
{
return TypedResults.NotFound();
}
var existingUser = await userManager.FindByIdAsync(request.User.Id);
if (existingUser is null)
{
return TypedResults.NotFound();
}
existingUser.FromUserDto(request.User);
await userManager.UpdateAsync(existingUser);
response.User = (await userManager.FindByIdAsync(existingUser.Id))!;
return TypedResults.Ok(response);
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UpdateUserRequest : BaseRequest
{
public UserDto User { get; set; }
}
using System;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UpdateUserResponse : BaseResponse
{
public UpdateUserResponse(Guid correlationId) : base(correlationId)
{
}
public UpdateUserResponse()
{
}
public ApplicationUser User { get; set; }
}
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class UpdateUserEndpointTest
{
[TestMethod]
public async Task UpdatesSuccessfullyGivenValidChangesAndAdminUserToken()
{
var client = HttpClientHelper.GetAdminClient();
var userName = "[email protected]";
var response = await client.GetAsync($"api/users/name/{userName}");
var demoUserResponse = await response.Content.ReadAsStringAsync();
var demoUser = demoUserResponse.FromJson<Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models.GetUserResponse>();
var startingEmailConfirmedValue = demoUser!.User.EmailConfirmed;
demoUser.User.EmailConfirmed = !startingEmailConfirmedValue;
UpdateUserRequest request = new UpdateUserRequest()
{
User = demoUser.User
};
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
var updateResponse = await client.PutAsync("api/users", jsonContent);
updateResponse.EnsureSuccessStatusCode();
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
var updateResponseJsonString = await updateResponse.Content.ReadAsStringAsync();
var updatedItem = updateResponseJsonString.FromJson<UpdateUserResponse>();
Assert.IsNotNull(updatedItem);
Assert.AreEqual(!startingEmailConfirmedValue, updatedItem.User.EmailConfirmed);
}
[TestMethod]
public async Task ReturnsNotFoundForNullRequest()
{
var client = HttpClientHelper.GetAdminClient();
UpdateUserRequest? request = null;
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
var updateResponse = await client.PutAsync("api/users", jsonContent);
Assert.AreEqual(HttpStatusCode.NotFound, updateResponse.StatusCode);
}
[TestMethod]
public async Task ReturnsNotFoundForNullUserInRequest()
{
var client = HttpClientHelper.GetAdminClient();
UpdateUserRequest request = new();
var jsonContent = new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json");
var updateResponse = await client.PutAsync("api/users", jsonContent);
Assert.AreEqual(HttpStatusCode.NotFound, updateResponse.StatusCode);
}
}
using System;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserDto()
{
public string Id { get; set; }
public string? UserName { get; set; }
public string? Email { get; set; }
public bool EmailConfirmed { get; set; }
public string? PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public bool TwoFactorEnabled { get; set; }
public DateTimeOffset? LockoutEnd { get; set; }
}
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.Extensions;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserGetByIdEndpoint (UserManager<ApplicationUser> userManager) : Endpoint <GetByIdUserRequest, Results<Ok<GetUserResponse>,NotFound>>
{
public override void Configure()
{
Get("api/users/{userId}");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
d.Produces<GetUserResponse>()
.WithTags("UserManagementEndpoints"));
}
public override async Task<Results<Ok<GetUserResponse>, NotFound>> ExecuteAsync(GetByIdUserRequest request, CancellationToken ct)
{
var response = new GetUserResponse(request.CorrelationId());
var userResponse = await userManager.FindByIdAsync(request.UserId);
if (userResponse is null)
{
return TypedResults.NotFound();
}
response.User = userResponse.ToUserDto();
return TypedResults.Ok(response);
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class GetByIdUserRequest : BaseRequest
{
public string UserId { get; init; }
public GetByIdUserRequest(string userId)
{
UserId = userId;
}
}
using System.Net;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class UserGetByIdEndpointTest
{
[TestMethod]
public async Task ReturnsItemGivenValidId()
{
var client = HttpClientHelper.GetAdminClient();
var userName = "[email protected]";
var response = await client.GetAsync($"api/users/name/{userName}");
var adminUserResponse = await response.Content.ReadAsStringAsync();
var adminUser = adminUserResponse.FromJson<GetUserResponse>();
var getUserById = await client.GetAsync($"api/users/{adminUser!.User!.Id}");
getUserById.EnsureSuccessStatusCode();
var adminUserByIdResponse = await response.Content.ReadAsStringAsync();
var adminModel = adminUserByIdResponse.FromJson<GetUserResponse>();
Assert.IsNotNull(adminModel);
Assert.IsNotNull(adminModel.User.UserName);
Assert.AreEqual(userName, adminModel.User.UserName);
}
[TestMethod]
public async Task ReturnsNotFoundGivenInvalidId()
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.GetAsync("api/users/0");
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
}
}
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.Extensions;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserGetByUserNameEndpoint (UserManager<ApplicationUser> userManager) : Endpoint <GetByUserNameUserRequest, Results<Ok<GetUserResponse>,NotFound>>
{
public override void Configure()
{
Get("api/users/name/{userName}");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
d.Produces<GetUserResponse>()
.WithTags("UserManagementEndpoints"));
}
public override async Task<Results<Ok<GetUserResponse>, NotFound>> ExecuteAsync(GetByUserNameUserRequest request, CancellationToken ct)
{
var response = new GetUserResponse(request.CorrelationId());
var userResponse = await userManager.FindByNameAsync(request.UserName);
if (userResponse is null)
{
return TypedResults.NotFound();
}
response.User = userResponse.ToUserDto();
return TypedResults.Ok(response);
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class GetByUserNameUserRequest : BaseRequest
{
public string UserName { get; init; }
public GetByUserNameUserRequest(string userName)
{
UserName = userName;
}
}
using System.Net;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class UserGetByUserNameEndpointTest
{
[TestMethod]
[DataRow("[email protected]")]
[DataRow("[email protected]")]
[DataRow("[email protected]")]
public async Task ReturnsItemGivenValidName(string userName)
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.GetAsync($"api/users/name/{userName}");
response.EnsureSuccessStatusCode();
var adminRoleResponse = await response.Content.ReadAsStringAsync();
var adminModel = adminRoleResponse.FromJson<GetUserResponse>();
Assert.IsNotNull(adminModel);
Assert.IsNotNull(adminModel.User);
Assert.IsNotNull(adminModel.User.UserName);
Assert.AreEqual(userName, adminModel.User.UserName);
}
[TestMethod]
public async Task ReturnsNotFoundGivenInvalidName()
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.GetAsync("api/users/name/0");
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
}
}
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserGetRolesByIdEndpoint (UserManager<ApplicationUser> userManager) : Endpoint <GetRolesByUserIdRequest, Results<Ok<GetUserRolesResponse>,NotFound>>
{
public override void Configure()
{
Get("api/users/{userId}/roles");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d =>
d.Produces<GetUserRolesResponse>()
.WithTags("UserManagementEndpoints"));
}
public override async Task<Results<Ok<GetUserRolesResponse>, NotFound>> ExecuteAsync(GetRolesByUserIdRequest request, CancellationToken ct)
{
var response = new GetUserRolesResponse(request.CorrelationId());
var user = await userManager.FindByIdAsync(request.UserId);
if (user is null)
{
return TypedResults.NotFound();
}
var rolesForUser = await userManager.GetRolesAsync(user);
if (rolesForUser is null)
{
return TypedResults.NotFound();
}
response.Roles = [.. rolesForUser];
return TypedResults.Ok(response);
}
}
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class GetRolesByUserIdRequest : BaseRequest
{
public string UserId { get; init; }
public GetRolesByUserIdRequest(string userId)
{
UserId = userId;
}
}
using System;
using System.Collections.Generic;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class GetUserRolesResponse : BaseResponse
{
public GetUserRolesResponse(Guid correlationId) : base(correlationId)
{
}
public GetUserRolesResponse()
{
}
public List<string> Roles { get; set; }
}
using System.Net;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.eShopWeb.PublicApi.UserManagementEndpoints.Models;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class UserGetRolesByIdEndpointTest
{
[TestMethod]
public async Task ReturnsItemGivenValidId()
{
var client = HttpClientHelper.GetAdminClient();
var userName = "[email protected]";
var response = await client.GetAsync($"api/users/name/{userName}");
var adminUserResponse = await response.Content.ReadAsStringAsync();
var adminUser = adminUserResponse.FromJson<GetUserResponse>();
var getUserRoles = await client.GetAsync($"api/users/{adminUser!.User!.Id}/roles");
getUserRoles.EnsureSuccessStatusCode();
var userRoles = await getUserRoles.Content.ReadAsStringAsync();
var userRolesList = userRoles.FromJson<GetUserRolesResponse>();
Assert.IsNotNull(userRolesList);
Assert.IsNotNull(userRolesList.Roles);
Assert.IsTrue(userRolesList.Roles.Count > 0);
}
[TestMethod]
public async Task ReturnsNotFoundGivenInvalidId()
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.GetAsync("api/users/0/roles");
Assert.AreEqual(HttpStatusCode.NotFound, response.StatusCode);
}
}
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FastEndpoints;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.PublicApi.Extensions;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserListEndpoint(UserManager<ApplicationUser> userManager):EndpointWithoutRequest<UserListResponse>
{
public override void Configure()
{
Get("api/users");
Roles(BlazorShared.Authorization.Constants.Roles.ADMINISTRATORS);
AuthSchemes(JwtBearerDefaults.AuthenticationScheme);
Description(d => d.Produces<UserListResponse>()
.WithTags("UserManagementEndpoints"));
}
public override async Task<UserListResponse> ExecuteAsync(CancellationToken ct)
{
await Task.Delay(1000, ct);
var response = new UserListResponse();
var users = userManager.Users.ToList();
foreach ( var user in users)
{
response.Users.Add(user.ToUserDto());
}
return response;
}
}
using System;
using System.Collections.Generic;
namespace Microsoft.eShopWeb.PublicApi.UserManagementEndpoints;
public class UserListResponse : BaseResponse
{
public UserListResponse(Guid correlationId) : base(correlationId)
{
}
public UserListResponse()
{
}
public List<UserDto> Users{ get; set; } = [];
}
using System.Net;
using System.Threading.Tasks;
using Microsoft.eShopWeb;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PublicApiIntegrationTests.Helpers;
namespace PublicApiIntegrationTests.UserManagementEndpoints;
[TestClass]
public class UserListEndpointTest
{
[TestMethod]
public async Task ReturnsUnauthorizedForAnonymousAccess()
{
var client = ProgramTest.NewClient;
var response = await client.GetAsync("/api/users");
Assert.AreEqual(HttpStatusCode.Unauthorized, response.StatusCode);
}
[TestMethod]
public async Task ReturnsForbiddenForGeneralAuthorizedAccess()
{
var client = HttpClientHelper.GetNormalUserClient();
var response = await client.GetAsync("/api/users");
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}
[TestMethod]
public async Task ReturnsForbiddenForProductManagerAccess()
{
var client = HttpClientHelper.GetProductManagerClient();
var response = await client.GetAsync("/api/users");
Assert.AreEqual(HttpStatusCode.Forbidden, response.StatusCode);
}
[TestMethod]
public async Task ReturnsSuccessAndRolesForAdministratorAccess()
{
var client = HttpClientHelper.GetAdminClient();
var response = await client.GetAsync("/api/users");
response.EnsureSuccessStatusCode();
var stringResponse = await response.Content.ReadAsStringAsync();
var model = stringResponse.FromJson<UserListResponse>();
Assert.IsNotNull(model);
Assert.IsNotNull(model.Users);
Assert.IsTrue(model.Users.Count > 0);
}
}

Comments are disabled for this gist.