WebPush-and-photo-upload-fixes
This commit is contained in:
238
LittleShop/Controllers/PushNotificationController.cs
Normal file
238
LittleShop/Controllers/PushNotificationController.cs
Normal file
@@ -0,0 +1,238 @@
|
||||
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;
|
||||
if (string.IsNullOrEmpty(userIdClaim) || !Guid.TryParse(userIdClaim, out Guid userId))
|
||||
{
|
||||
return Unauthorized("Invalid user ID");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user