Files
breakpilot-core/consent-service/internal/handlers/notification_handlers.go
Benjamin Boenisch ad111d5e69 Initial commit: breakpilot-core - Shared Infrastructure
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>
2026-02-11 23:47:13 +01:00

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})
}