246 lines
8.2 KiB
C#
246 lines
8.2 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using System.Security.Claims;
|
|
using LittleShop.DTOs;
|
|
using LittleShop.Services;
|
|
|
|
namespace LittleShop.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/push")]
|
|
public class PushNotificationController : ControllerBase
|
|
{
|
|
private readonly IPushNotificationService _pushNotificationService;
|
|
|
|
public PushNotificationController(IPushNotificationService pushNotificationService)
|
|
{
|
|
_pushNotificationService = pushNotificationService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the VAPID public key for client-side push subscription
|
|
/// </summary>
|
|
[HttpGet("vapid-key")]
|
|
public IActionResult GetVapidPublicKey()
|
|
{
|
|
try
|
|
{
|
|
var publicKey = _pushNotificationService.GetVapidPublicKey();
|
|
return Ok(new { publicKey });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe admin user to push notifications
|
|
/// </summary>
|
|
[HttpPost("subscribe")]
|
|
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
|
|
public async Task<IActionResult> Subscribe([FromBody] PushSubscriptionDto subscriptionDto)
|
|
{
|
|
try
|
|
{
|
|
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
var username = User.FindFirst(ClaimTypes.Name)?.Value ?? User.Identity?.Name;
|
|
|
|
// Debug logging
|
|
var logger = HttpContext.RequestServices.GetRequiredService<ILogger<PushNotificationController>>();
|
|
logger.LogInformation("Push subscription attempt - UserIdClaim: {UserIdClaim}, Username: {Username}", userIdClaim, username);
|
|
|
|
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out Guid userId))
|
|
{
|
|
return Unauthorized(new { error = "Invalid user ID", userIdClaim, username });
|
|
}
|
|
|
|
var userAgent = Request.Headers.UserAgent.ToString();
|
|
var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
|
|
|
var success = await _pushNotificationService.SubscribeUserAsync(userId, subscriptionDto, userAgent, ipAddress);
|
|
|
|
if (success)
|
|
{
|
|
return Ok(new { message = "Successfully subscribed to push notifications" });
|
|
}
|
|
else
|
|
{
|
|
return StatusCode(500, new { error = "Failed to subscribe to push notifications" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var logger = HttpContext.RequestServices.GetRequiredService<ILogger<PushNotificationController>>();
|
|
logger.LogError(ex, "Push subscription error");
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe customer to push notifications (for customer-facing apps)
|
|
/// </summary>
|
|
[HttpPost("subscribe/customer")]
|
|
[AllowAnonymous]
|
|
public async Task<IActionResult> SubscribeCustomer([FromBody] PushSubscriptionDto subscriptionDto, [FromQuery] Guid customerId)
|
|
{
|
|
try
|
|
{
|
|
if (customerId == Guid.Empty)
|
|
{
|
|
return BadRequest("Invalid customer ID");
|
|
}
|
|
|
|
var userAgent = Request.Headers.UserAgent.ToString();
|
|
var ipAddress = HttpContext.Connection.RemoteIpAddress?.ToString();
|
|
|
|
var success = await _pushNotificationService.SubscribeCustomerAsync(customerId, subscriptionDto, userAgent, ipAddress);
|
|
|
|
if (success)
|
|
{
|
|
return Ok(new { message = "Successfully subscribed to push notifications" });
|
|
}
|
|
else
|
|
{
|
|
return StatusCode(500, new { error = "Failed to subscribe to push notifications" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribe from push notifications
|
|
/// </summary>
|
|
[HttpPost("unsubscribe")]
|
|
public async Task<IActionResult> Unsubscribe([FromBody] UnsubscribeDto unsubscribeDto)
|
|
{
|
|
try
|
|
{
|
|
var success = await _pushNotificationService.UnsubscribeAsync(unsubscribeDto.Endpoint);
|
|
|
|
if (success)
|
|
{
|
|
return Ok(new { message = "Successfully unsubscribed from push notifications" });
|
|
}
|
|
else
|
|
{
|
|
return NotFound(new { error = "Subscription not found" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send test notification to current admin user
|
|
/// </summary>
|
|
[HttpPost("test")]
|
|
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
|
|
public async Task<IActionResult> SendTestNotification([FromBody] TestPushNotificationDto testDto)
|
|
{
|
|
try
|
|
{
|
|
var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
var success = await _pushNotificationService.SendTestNotificationAsync(userIdClaim, testDto.Title, testDto.Body);
|
|
|
|
if (success)
|
|
{
|
|
return Ok(new { message = "Test notification sent successfully" });
|
|
}
|
|
else
|
|
{
|
|
return StatusCode(500, new { error = "Failed to send test notification. Make sure you are subscribed to push notifications." });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Send broadcast notification to all admin users
|
|
/// </summary>
|
|
[HttpPost("broadcast")]
|
|
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
|
|
public async Task<IActionResult> SendBroadcastNotification([FromBody] PushNotificationDto notificationDto)
|
|
{
|
|
try
|
|
{
|
|
var success = await _pushNotificationService.SendNotificationToAllUsersAsync(notificationDto);
|
|
|
|
if (success)
|
|
{
|
|
return Ok(new { message = "Broadcast notification sent successfully" });
|
|
}
|
|
else
|
|
{
|
|
return StatusCode(500, new { error = "Failed to send broadcast notification" });
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get active push subscriptions (admin only)
|
|
/// </summary>
|
|
[HttpGet("subscriptions")]
|
|
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
|
|
public async Task<IActionResult> GetActiveSubscriptions()
|
|
{
|
|
try
|
|
{
|
|
var subscriptions = await _pushNotificationService.GetActiveSubscriptionsAsync();
|
|
|
|
var result = subscriptions.Select(s => new
|
|
{
|
|
id = s.Id,
|
|
userId = s.UserId,
|
|
customerId = s.CustomerId,
|
|
userName = s.User?.Username,
|
|
customerName = s.Customer?.TelegramDisplayName ?? s.Customer?.TelegramUsername,
|
|
subscribedAt = s.SubscribedAt,
|
|
lastUsedAt = s.LastUsedAt,
|
|
userAgent = s.UserAgent,
|
|
endpoint = s.Endpoint[..Math.Min(50, s.Endpoint.Length)] + "..." // Truncate for security
|
|
}).ToList();
|
|
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cleanup expired push subscriptions
|
|
/// </summary>
|
|
[HttpPost("cleanup")]
|
|
[Authorize(AuthenticationSchemes = "Cookies", Roles = "Admin")]
|
|
public async Task<IActionResult> CleanupExpiredSubscriptions()
|
|
{
|
|
try
|
|
{
|
|
var cleanedCount = await _pushNotificationService.CleanupExpiredSubscriptionsAsync();
|
|
return Ok(new { message = $"Cleaned up {cleanedCount} expired subscriptions" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, new { error = ex.Message });
|
|
}
|
|
}
|
|
}
|
|
|
|
public class UnsubscribeDto
|
|
{
|
|
public string Endpoint { get; set; } = string.Empty;
|
|
} |