using foodmarket.Application.Common.Tenancy; using foodmarket.Domain.Organizations; using foodmarket.Infrastructure.Persistence; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; namespace foodmarket.Api.Controllers; /// Регистрация токенов устройств для push (iOS/Android/Web). Приложение/PWA /// вызывает после получения разрешения. Реальная отправка пока заглушка — см. /// IPushSender/StubPushSender; таблица и регистрация заложены заранее. [ApiController] [Authorize] [Route("api/me/device-tokens")] public class DeviceTokensController : ControllerBase { private readonly AppDbContext _db; private readonly ITenantContext _tenant; public DeviceTokensController(AppDbContext db, ITenantContext tenant) { _db = db; _tenant = tenant; } public record RegisterInput(string Platform, string Token); /// Зарегистрировать/обновить токен устройства текущего пользователя. /// Идемпотентно по токену (повторный вызов обновляет LastSeenAt/владельца). [HttpPost] public async Task Register([FromBody] RegisterInput input, CancellationToken ct) { var orgId = _tenant.OrganizationId; var userId = _tenant.UserId; if (orgId is null || userId is null) return Unauthorized(); if (string.IsNullOrWhiteSpace(input.Token)) return BadRequest(new { error = "Пустой токен." }); var platform = string.IsNullOrWhiteSpace(input.Platform) ? "ios" : input.Platform.Trim().ToLowerInvariant(); var now = DateTime.UtcNow; var existing = await _db.DeviceTokens.FirstOrDefaultAsync(t => t.Token == input.Token, ct); if (existing is null) { _db.DeviceTokens.Add(new DeviceToken { OrganizationId = orgId.Value, UserId = userId.Value, Platform = platform, Token = input.Token.Trim(), LastSeenAt = now, }); } else { existing.OrganizationId = orgId.Value; existing.UserId = userId.Value; existing.Platform = platform; existing.LastSeenAt = now; } await _db.SaveChangesAsync(ct); return NoContent(); } /// Удалить токен (при выходе/отзыве разрешения). [HttpDelete] public async Task Unregister([FromQuery] string token, CancellationToken ct) { var existing = await _db.DeviceTokens.FirstOrDefaultAsync(t => t.Token == token, ct); if (existing is not null) { _db.DeviceTokens.Remove(existing); await _db.SaveChangesAsync(ct); } return NoContent(); } }