fleshout backend
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
using Backend.Gateway;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Backend.Controllers;
|
||||
|
||||
[Route("v1/[controller]")]
|
||||
[ApiController]
|
||||
public class InfoController : ControllerBase
|
||||
[Route(ApiRoutes.V1 + "/[controller]")]
|
||||
public sealed class InfoController : ControllerBase
|
||||
{
|
||||
private readonly IWebHostEnvironment _environment;
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Backend.Data;
|
||||
|
||||
namespace Backend.Controllers
|
||||
{
|
||||
[Route("v1/[controller]")]
|
||||
[ApiController]
|
||||
public class UserController : ControllerBase
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public UserController(IUserRepository userRepository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
backend/Controllers/UserRequests.cs
Normal file
13
backend/Controllers/UserRequests.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Backend.Controllers;
|
||||
|
||||
// Validation attributes must target the primary constructor parameters, not the
|
||||
// generated properties; MVC rejects record types with property-level metadata.
|
||||
public sealed record CreateUserRequest(
|
||||
[Required][EmailAddress] string Email,
|
||||
[Required][StringLength(100, MinimumLength = 1)] string DisplayName);
|
||||
|
||||
public sealed record UpdateUserRequest(
|
||||
[Required][EmailAddress] string Email,
|
||||
[Required][StringLength(100, MinimumLength = 1)] string DisplayName);
|
||||
96
backend/Controllers/UsersController.cs
Normal file
96
backend/Controllers/UsersController.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Backend.Data;
|
||||
using Backend.Gateway;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Backend.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route(ApiRoutes.V1 + "/[controller]")]
|
||||
public sealed class UsersController : ControllerBase
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
|
||||
public UsersController(IUserRepository userRepository)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType<IReadOnlyList<User>>(StatusCodes.Status200OK)]
|
||||
public async Task<IActionResult> GetAll(CancellationToken cancellationToken)
|
||||
=> Ok(await _userRepository.GetAllAsync(cancellationToken));
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
[ProducesResponseType<User>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetById(Guid id, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await _userRepository.GetByIdAsync(id, cancellationToken);
|
||||
|
||||
return user is null ? NotFound() : Ok(user);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType<User>(StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
public async Task<IActionResult> Create(
|
||||
CreateUserRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (await _userRepository.GetByEmailAsync(request.Email, cancellationToken) is not null)
|
||||
{
|
||||
return Conflict(new ProblemDetails
|
||||
{
|
||||
Title = "Email already in use",
|
||||
Status = StatusCodes.Status409Conflict,
|
||||
});
|
||||
}
|
||||
|
||||
var user = await _userRepository.AddAsync(
|
||||
new User { Email = request.Email, DisplayName = request.DisplayName },
|
||||
cancellationToken);
|
||||
|
||||
return CreatedAtAction(nameof(GetById), new { id = user.Id }, user);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
[ProducesResponseType<User>(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[ProducesResponseType(StatusCodes.Status409Conflict)]
|
||||
public async Task<IActionResult> Update(
|
||||
Guid id,
|
||||
UpdateUserRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var existing = await _userRepository.GetByIdAsync(id, cancellationToken);
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var emailOwner = await _userRepository.GetByEmailAsync(request.Email, cancellationToken);
|
||||
|
||||
if (emailOwner is not null && emailOwner.Id != id)
|
||||
{
|
||||
return Conflict(new ProblemDetails
|
||||
{
|
||||
Title = "Email already in use",
|
||||
Status = StatusCodes.Status409Conflict,
|
||||
});
|
||||
}
|
||||
|
||||
existing.Email = request.Email;
|
||||
existing.DisplayName = request.DisplayName;
|
||||
|
||||
var updated = await _userRepository.UpdateAsync(existing, cancellationToken);
|
||||
|
||||
return updated is null ? NotFound() : Ok(updated);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken cancellationToken)
|
||||
=> await _userRepository.DeleteAsync(id, cancellationToken) ? NoContent() : NotFound();
|
||||
}
|
||||
Reference in New Issue
Block a user