96 lines
3.5 KiB
C#
96 lines
3.5 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using ROLAC.API.Data;
|
|
using ROLAC.API.DTOs.Notifications;
|
|
using ROLAC.API.Services.Logging;
|
|
using ROLAC.API.Services.Notifications;
|
|
|
|
namespace ROLAC.API.Controllers;
|
|
|
|
/// <summary>
|
|
/// Admin endpoints for the notification module (API-only phase). Binding-code generation, group
|
|
/// management, send history, and manual send — the manual send endpoints are the only way to fire
|
|
/// a message before a UI exists; programmatic callers use the services directly.
|
|
/// </summary>
|
|
[ApiController]
|
|
[Route("api/notifications")]
|
|
[Authorize]
|
|
public sealed class NotificationsController : ControllerBase
|
|
{
|
|
private readonly IEmailService _email;
|
|
private readonly ILineNotificationService _line;
|
|
private readonly AppDbContext _db;
|
|
private readonly CurrentUserAccessor _currentUser;
|
|
|
|
public NotificationsController(
|
|
IEmailService email, ILineNotificationService line,
|
|
AppDbContext db, CurrentUserAccessor currentUser)
|
|
{
|
|
_email = email;
|
|
_line = line;
|
|
_db = db;
|
|
_currentUser = currentUser;
|
|
}
|
|
|
|
[HttpPost("members/{id:int}/line-binding-code")]
|
|
public async Task<IActionResult> GenerateBindingCode(int id, CancellationToken ct)
|
|
=> Ok(new { code = await _line.GenerateLineBindingCodeAsync(id, ct) });
|
|
|
|
[HttpGet("groups")]
|
|
public async Task<IActionResult> Groups(CancellationToken ct)
|
|
=> Ok(await _db.MessagingGroups
|
|
.OrderBy(g => g.Id)
|
|
.Select(g => new { g.Id, g.Name, g.IsActive, g.RegisteredAt })
|
|
.ToListAsync(ct));
|
|
|
|
[HttpPut("groups/{id:int}")]
|
|
public async Task<IActionResult> UpdateGroup(int id, [FromBody] UpdateGroupRequest request, CancellationToken ct)
|
|
{
|
|
var group = await _db.MessagingGroups.FirstOrDefaultAsync(g => g.Id == id, ct);
|
|
if (group is null) return NotFound();
|
|
|
|
group.Name = request.Name;
|
|
group.IsActive = request.IsActive;
|
|
await _db.SaveChangesAsync(ct);
|
|
return NoContent();
|
|
}
|
|
|
|
[HttpGet("history")]
|
|
public async Task<IActionResult> History(
|
|
[FromQuery] int page = 1, [FromQuery] int pageSize = 50, CancellationToken ct = default)
|
|
{
|
|
var size = Math.Clamp(pageSize, 1, 200);
|
|
var skip = (Math.Max(page, 1) - 1) * size;
|
|
|
|
var query = _db.NotificationLogs.OrderByDescending(l => l.SentAt);
|
|
var total = await query.CountAsync(ct);
|
|
var items = await query
|
|
.Skip(skip).Take(size)
|
|
.Select(l => new
|
|
{
|
|
l.Id, l.Channel, l.TargetType, l.TargetExternalId, l.Subject,
|
|
l.Status, l.Error, l.SentByUserId, l.SentAt,
|
|
})
|
|
.ToListAsync(ct);
|
|
|
|
return Ok(new { total, items });
|
|
}
|
|
|
|
[HttpPost("send-line")]
|
|
public async Task<IActionResult> SendLine([FromBody] SendLineRequest request, CancellationToken ct)
|
|
=> Ok(await _line.SendLineAsync(
|
|
request.Body, request.MemberIds ?? [], request.GroupIds ?? [],
|
|
_currentUser.UserIdOrSystem, ct));
|
|
|
|
[HttpPost("send-email")]
|
|
public async Task<IActionResult> SendEmail([FromBody] SendEmailRequest request, CancellationToken ct)
|
|
=> Ok(await _email.SendAsync(new EmailMessage(
|
|
MemberIds: request.MemberIds ?? [],
|
|
Addresses: request.Addresses ?? [],
|
|
Subject: request.Subject,
|
|
HtmlBody: request.HtmlBody,
|
|
Attachments: null,
|
|
SentByUserId: _currentUser.UserIdOrSystem), ct));
|
|
}
|