Docker Compose with 24+ services: - PostgreSQL (PostGIS), Valkey, MinIO, Qdrant - Vault (PKI/TLS), Nginx (Reverse Proxy) - Backend Core API, Consent Service, Billing Service - RAG Service, Embedding Service - Gitea, Woodpecker CI/CD - Night Scheduler, Health Aggregator - Jitsi (Web/XMPP/JVB/Jicofo), Mailpit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
204 lines
5.9 KiB
Go
204 lines
5.9 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/breakpilot/consent-service/internal/middleware"
|
|
"github.com/breakpilot/consent-service/internal/services"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// NotificationHandler handles notification-related requests
|
|
type NotificationHandler struct {
|
|
notificationService *services.NotificationService
|
|
}
|
|
|
|
// NewNotificationHandler creates a new notification handler
|
|
func NewNotificationHandler(notificationService *services.NotificationService) *NotificationHandler {
|
|
return &NotificationHandler{
|
|
notificationService: notificationService,
|
|
}
|
|
}
|
|
|
|
// GetNotifications returns notifications for the current user
|
|
func (h *NotificationHandler) GetNotifications(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
// Parse query parameters
|
|
limit := 20
|
|
offset := 0
|
|
unreadOnly := false
|
|
|
|
if l := c.Query("limit"); l != "" {
|
|
if parsed, err := strconv.Atoi(l); err == nil && parsed > 0 {
|
|
limit = parsed
|
|
}
|
|
}
|
|
if o := c.Query("offset"); o != "" {
|
|
if parsed, err := strconv.Atoi(o); err == nil && parsed >= 0 {
|
|
offset = parsed
|
|
}
|
|
}
|
|
if u := c.Query("unread_only"); u == "true" {
|
|
unreadOnly = true
|
|
}
|
|
|
|
notifications, total, err := h.notificationService.GetUserNotifications(c.Request.Context(), userID, limit, offset, unreadOnly)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch notifications"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"notifications": notifications,
|
|
"total": total,
|
|
"limit": limit,
|
|
"offset": offset,
|
|
})
|
|
}
|
|
|
|
// GetUnreadCount returns the count of unread notifications
|
|
func (h *NotificationHandler) GetUnreadCount(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
count, err := h.notificationService.GetUnreadCount(c.Request.Context(), userID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get unread count"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"unread_count": count})
|
|
}
|
|
|
|
// MarkAsRead marks a notification as read
|
|
func (h *NotificationHandler) MarkAsRead(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
notificationID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid notification ID"})
|
|
return
|
|
}
|
|
|
|
if err := h.notificationService.MarkAsRead(c.Request.Context(), userID, notificationID); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Notification not found or already read"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Notification marked as read"})
|
|
}
|
|
|
|
// MarkAllAsRead marks all notifications as read
|
|
func (h *NotificationHandler) MarkAllAsRead(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
if err := h.notificationService.MarkAllAsRead(c.Request.Context(), userID); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to mark notifications as read"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "All notifications marked as read"})
|
|
}
|
|
|
|
// DeleteNotification deletes a notification
|
|
func (h *NotificationHandler) DeleteNotification(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
notificationID, err := uuid.Parse(c.Param("id"))
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid notification ID"})
|
|
return
|
|
}
|
|
|
|
if err := h.notificationService.DeleteNotification(c.Request.Context(), userID, notificationID); err != nil {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "Notification not found"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Notification deleted"})
|
|
}
|
|
|
|
// GetPreferences returns notification preferences for the user
|
|
func (h *NotificationHandler) GetPreferences(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
prefs, err := h.notificationService.GetPreferences(c.Request.Context(), userID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get preferences"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, prefs)
|
|
}
|
|
|
|
// UpdatePreferences updates notification preferences for the user
|
|
func (h *NotificationHandler) UpdatePreferences(c *gin.Context) {
|
|
userID, err := middleware.GetUserID(c)
|
|
if err != nil || userID == uuid.Nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid user"})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
EmailEnabled *bool `json:"email_enabled"`
|
|
PushEnabled *bool `json:"push_enabled"`
|
|
InAppEnabled *bool `json:"in_app_enabled"`
|
|
ReminderFrequency *string `json:"reminder_frequency"`
|
|
}
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
|
|
return
|
|
}
|
|
|
|
// Get current preferences
|
|
prefs, _ := h.notificationService.GetPreferences(c.Request.Context(), userID)
|
|
|
|
// Update only provided fields
|
|
if req.EmailEnabled != nil {
|
|
prefs.EmailEnabled = *req.EmailEnabled
|
|
}
|
|
if req.PushEnabled != nil {
|
|
prefs.PushEnabled = *req.PushEnabled
|
|
}
|
|
if req.InAppEnabled != nil {
|
|
prefs.InAppEnabled = *req.InAppEnabled
|
|
}
|
|
if req.ReminderFrequency != nil {
|
|
prefs.ReminderFrequency = *req.ReminderFrequency
|
|
}
|
|
|
|
if err := h.notificationService.UpdatePreferences(c.Request.Context(), userID, prefs); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update preferences"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"message": "Preferences updated", "preferences": prefs})
|
|
}
|