feat(api): add organization management endpoints
This commit is contained in:
151
src/IncidentOps.Api/Controllers/OrgController.cs
Normal file
151
src/IncidentOps.Api/Controllers/OrgController.cs
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
using IncidentOps.Api.Auth;
|
||||||
|
using IncidentOps.Contracts.Orgs;
|
||||||
|
using IncidentOps.Contracts.Services;
|
||||||
|
using IncidentOps.Domain.Entities;
|
||||||
|
using IncidentOps.Domain.Enums;
|
||||||
|
using IncidentOps.Infrastructure.Data.Repositories;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace IncidentOps.Api.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("v1/org")]
|
||||||
|
[Authorize]
|
||||||
|
public class OrgController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IOrgRepository _orgRepository;
|
||||||
|
private readonly IOrgMemberRepository _orgMemberRepository;
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
private readonly IServiceRepository _serviceRepository;
|
||||||
|
private readonly INotificationTargetRepository _notificationTargetRepository;
|
||||||
|
|
||||||
|
public OrgController(
|
||||||
|
IOrgRepository orgRepository,
|
||||||
|
IOrgMemberRepository orgMemberRepository,
|
||||||
|
IUserRepository userRepository,
|
||||||
|
IServiceRepository serviceRepository,
|
||||||
|
INotificationTargetRepository notificationTargetRepository)
|
||||||
|
{
|
||||||
|
_orgRepository = orgRepository;
|
||||||
|
_orgMemberRepository = orgMemberRepository;
|
||||||
|
_userRepository = userRepository;
|
||||||
|
_serviceRepository = serviceRepository;
|
||||||
|
_notificationTargetRepository = notificationTargetRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<ActionResult<OrgDto>> GetCurrentOrg()
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
var org = await _orgRepository.GetByIdAsync(ctx.OrgId);
|
||||||
|
if (org == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
return new OrgDto(org.Id, org.Name, org.Slug, ctx.Role.ToString().ToLowerInvariant());
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("members")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<ActionResult<IReadOnlyList<OrgMemberDto>>> GetMembers()
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
var members = await _orgMemberRepository.GetByOrgIdAsync(ctx.OrgId);
|
||||||
|
|
||||||
|
var result = new List<OrgMemberDto>();
|
||||||
|
foreach (var member in members)
|
||||||
|
{
|
||||||
|
var user = await _userRepository.GetByIdAsync(member.UserId);
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
result.Add(new OrgMemberDto(
|
||||||
|
member.Id,
|
||||||
|
user.Id,
|
||||||
|
user.Email,
|
||||||
|
user.DisplayName,
|
||||||
|
member.Role.ToString().ToLowerInvariant(),
|
||||||
|
member.CreatedAt
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("services")]
|
||||||
|
public async Task<ActionResult<IReadOnlyList<ServiceDto>>> GetServices()
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
var services = await _serviceRepository.GetByOrgIdAsync(ctx.OrgId);
|
||||||
|
|
||||||
|
return services.Select(s => new ServiceDto(s.Id, s.Name, s.Slug, s.Description, s.CreatedAt)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("services")]
|
||||||
|
[Authorize(Policy = "Member")]
|
||||||
|
public async Task<ActionResult<ServiceDto>> CreateService([FromBody] CreateServiceRequest request)
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
|
||||||
|
var service = new Service
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
OrgId = ctx.OrgId,
|
||||||
|
Name = request.Name,
|
||||||
|
Slug = request.Slug,
|
||||||
|
Description = request.Description,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
await _serviceRepository.CreateAsync(service);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetServices), new ServiceDto(service.Id, service.Name, service.Slug, service.Description, service.CreatedAt));
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("notification-targets")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<ActionResult<IReadOnlyList<NotificationTargetDto>>> GetNotificationTargets()
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
var targets = await _notificationTargetRepository.GetByOrgIdAsync(ctx.OrgId);
|
||||||
|
|
||||||
|
return targets.Select(t => new NotificationTargetDto(
|
||||||
|
t.Id,
|
||||||
|
t.Name,
|
||||||
|
t.TargetType.ToString().ToLowerInvariant(),
|
||||||
|
t.Configuration,
|
||||||
|
t.IsEnabled,
|
||||||
|
t.CreatedAt
|
||||||
|
)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost("notification-targets")]
|
||||||
|
[Authorize(Policy = "Admin")]
|
||||||
|
public async Task<ActionResult<NotificationTargetDto>> CreateNotificationTarget([FromBody] CreateNotificationTargetRequest request)
|
||||||
|
{
|
||||||
|
var ctx = User.GetRequestContext();
|
||||||
|
|
||||||
|
if (!Enum.TryParse<NotificationTargetType>(request.TargetType, ignoreCase: true, out var targetType))
|
||||||
|
return BadRequest(new { message = "Invalid target type" });
|
||||||
|
|
||||||
|
var target = new NotificationTarget
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
OrgId = ctx.OrgId,
|
||||||
|
Name = request.Name,
|
||||||
|
TargetType = targetType,
|
||||||
|
Configuration = request.Configuration,
|
||||||
|
IsEnabled = request.IsEnabled,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
};
|
||||||
|
await _notificationTargetRepository.CreateAsync(target);
|
||||||
|
|
||||||
|
return CreatedAtAction(nameof(GetNotificationTargets), new NotificationTargetDto(
|
||||||
|
target.Id,
|
||||||
|
target.Name,
|
||||||
|
target.TargetType.ToString().ToLowerInvariant(),
|
||||||
|
target.Configuration,
|
||||||
|
target.IsEnabled,
|
||||||
|
target.CreatedAt
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user