2025-12-03 19:29:37 +00:00
|
|
|
package handlers
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"net/http"
|
|
|
|
|
|
2025-12-24 10:23:24 +00:00
|
|
|
apperrors "veza-backend-api/internal/errors"
|
2025-12-03 19:29:37 +00:00
|
|
|
"veza-backend-api/internal/services"
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
2025-12-24 10:23:24 +00:00
|
|
|
"github.com/google/uuid"
|
2025-12-03 19:29:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var NotificationHandlersInstance *NotificationHandlers
|
|
|
|
|
|
2025-12-28 21:26:31 +00:00
|
|
|
// NotificationServiceInterface defines the interface for notification operations
|
|
|
|
|
// This allows for easier testing with mocks
|
|
|
|
|
type NotificationServiceInterface interface {
|
|
|
|
|
GetNotifications(userID uuid.UUID, unreadOnly bool) ([]services.Notification, error)
|
|
|
|
|
MarkAsRead(userID uuid.UUID, notificationID uuid.UUID) error
|
|
|
|
|
MarkAllAsRead(userID uuid.UUID) error
|
|
|
|
|
GetUnreadCount(userID uuid.UUID) (int, error)
|
feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application
🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode
✨ **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements
🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes
🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions
The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 01:32:21 +00:00
|
|
|
DeleteNotification(userID uuid.UUID, notificationID uuid.UUID) error
|
|
|
|
|
DeleteAllNotifications(userID uuid.UUID) error
|
2026-02-21 15:41:39 +00:00
|
|
|
GetPreferences(userID uuid.UUID) (*services.NotificationPrefs, error)
|
|
|
|
|
UpdatePreferences(userID uuid.UUID, pushFollow, pushLike, pushComment, pushMessage, pushMention *bool) error
|
2025-12-28 21:26:31 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-03 19:29:37 +00:00
|
|
|
type NotificationHandlers struct {
|
2025-12-28 21:26:31 +00:00
|
|
|
notificationService NotificationServiceInterface
|
2026-02-21 15:41:39 +00:00
|
|
|
pushService *services.PushService
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
2026-02-21 15:41:39 +00:00
|
|
|
func NewNotificationHandlers(notificationService *services.NotificationService, pushService *services.PushService) {
|
2025-12-03 19:29:37 +00:00
|
|
|
NotificationHandlersInstance = &NotificationHandlers{
|
|
|
|
|
notificationService: notificationService,
|
2026-02-21 15:41:39 +00:00
|
|
|
pushService: pushService,
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-28 21:26:31 +00:00
|
|
|
// NewNotificationHandlersWithInterface creates new notification handlers with an interface (for testing)
|
|
|
|
|
func NewNotificationHandlersWithInterface(notificationService NotificationServiceInterface) *NotificationHandlers {
|
|
|
|
|
return &NotificationHandlers{
|
|
|
|
|
notificationService: notificationService,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-03 19:29:37 +00:00
|
|
|
// GetNotifications retrieves all notifications for the authenticated user
|
2025-12-24 10:23:24 +00:00
|
|
|
// GET /api/v1/notifications
|
|
|
|
|
// BE-API-016: Implement notifications endpoints
|
2025-12-03 19:29:37 +00:00
|
|
|
func (nh *NotificationHandlers) GetNotifications(c *gin.Context) {
|
2025-12-24 10:23:24 +00:00
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return // Erreur déjà envoyée par GetUserIDUUID
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
read := c.DefaultQuery("read", "")
|
|
|
|
|
var unreadOnly bool
|
|
|
|
|
if read == "false" {
|
|
|
|
|
unreadOnly = true
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-24 10:23:24 +00:00
|
|
|
notifications, err := nh.notificationService.GetNotifications(userID, unreadOnly)
|
2025-12-03 19:29:37 +00:00
|
|
|
if err != nil {
|
2025-12-24 10:23:24 +00:00
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get notifications", err))
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:21:59 +00:00
|
|
|
RespondSuccess(c, http.StatusOK, notifications)
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarkAsRead marks a notification as read
|
2025-12-24 10:23:24 +00:00
|
|
|
// POST /api/v1/notifications/:id/read
|
|
|
|
|
// BE-API-016: Implement notifications endpoints
|
2025-12-03 19:29:37 +00:00
|
|
|
func (nh *NotificationHandlers) MarkAsRead(c *gin.Context) {
|
2025-12-24 10:23:24 +00:00
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return // Erreur déjà envoyée par GetUserIDUUID
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notificationID, err := uuid.Parse(c.Param("id"))
|
|
|
|
|
if err != nil {
|
2025-12-24 10:23:24 +00:00
|
|
|
RespondWithAppError(c, apperrors.NewValidationError("invalid notification id"))
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-24 10:23:24 +00:00
|
|
|
err = nh.notificationService.MarkAsRead(userID, notificationID)
|
2025-12-03 19:29:37 +00:00
|
|
|
if err != nil {
|
2025-12-24 10:23:24 +00:00
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to mark notification as read", err))
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:21:59 +00:00
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "Notification marked as read"})
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MarkAllAsRead marks all notifications as read for the user
|
2025-12-24 10:23:24 +00:00
|
|
|
// POST /api/v1/notifications/read-all
|
|
|
|
|
// BE-API-016: Implement notifications endpoints
|
2025-12-03 19:29:37 +00:00
|
|
|
func (nh *NotificationHandlers) MarkAllAsRead(c *gin.Context) {
|
2025-12-24 10:23:24 +00:00
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return // Erreur déjà envoyée par GetUserIDUUID
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
2025-12-24 10:23:24 +00:00
|
|
|
if err := nh.notificationService.MarkAllAsRead(userID); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to mark all notifications as read", err))
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:21:59 +00:00
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "All notifications marked as read"})
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUnreadCount returns the count of unread notifications
|
|
|
|
|
func (nh *NotificationHandlers) GetUnreadCount(c *gin.Context) {
|
feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application
🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode
✨ **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements
🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes
🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions
The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 01:32:21 +00:00
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application
🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode
✨ **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements
🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes
🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions
The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 01:32:21 +00:00
|
|
|
count, err := nh.notificationService.GetUnreadCount(userID)
|
2025-12-03 19:29:37 +00:00
|
|
|
if err != nil {
|
feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application
🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode
✨ **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements
🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes
🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions
The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 01:32:21 +00:00
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get unread count", err))
|
2025-12-03 19:29:37 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 16:21:59 +00:00
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"count": count})
|
2025-12-03 19:29:37 +00:00
|
|
|
}
|
feat: Visual masterpiece - true light mode & premium UI
🎨 **True Light/Dark Mode**
- Implemented proper light mode with inverted color scheme
- Smooth theme transitions (0.3s ease)
- Light mode colors: white backgrounds, dark text, vibrant accents
- System theme detection with proper class application
🌈 **Enhanced Theme System**
- 4 color themes work in both light and dark modes
- Cyber (cyan/magenta), Ocean (blue/teal), Forest (green/lime), Sunset (orange/purple)
- Theme-specific glassmorphism effects
- Proper contrast in light mode
✨ **Premium Animations**
- Float, glow-pulse, slide-in, scale-in, rotate-in animations
- Smooth page transitions
- Hover effects with depth (lift, glow, scale)
- Micro-interactions on all interactive elements
🎯 **Visual Polish**
- Enhanced glassmorphism for light/dark modes
- Custom scrollbar with theme colors
- Beautiful text selection
- Focus indicators for accessibility
- Premium utility classes
🔧 **Technical Improvements**
- Updated UIStore to properly apply light/dark classes
- Added data-theme attribute for CSS targeting
- Smooth scroll behavior
- Optimized transitions
The app is now a visual masterpiece with perfect light/dark mode support!
2026-01-11 01:32:21 +00:00
|
|
|
|
|
|
|
|
// DeleteNotification deletes a notification
|
|
|
|
|
func (nh *NotificationHandlers) DeleteNotification(c *gin.Context) {
|
|
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
notificationID, err := uuid.Parse(c.Param("id"))
|
|
|
|
|
if err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.NewValidationError("invalid notification id"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = nh.notificationService.DeleteNotification(userID, notificationID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to delete notification", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "Notification deleted"})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DeleteAllNotifications deletes all notifications for the user
|
|
|
|
|
func (nh *NotificationHandlers) DeleteAllNotifications(c *gin.Context) {
|
|
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := nh.notificationService.DeleteAllNotifications(userID); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to delete all notifications", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "All notifications deleted"})
|
|
|
|
|
}
|
2026-02-21 15:41:39 +00:00
|
|
|
|
|
|
|
|
// SubscribePushRequest is the DTO for Web Push subscription (N1.1)
|
|
|
|
|
type SubscribePushRequest struct {
|
|
|
|
|
Endpoint string `json:"endpoint" binding:"required"`
|
|
|
|
|
Keys struct {
|
|
|
|
|
P256dh string `json:"p256dh" binding:"required"`
|
|
|
|
|
Auth string `json:"auth" binding:"required"`
|
|
|
|
|
} `json:"keys" binding:"required"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SubscribePush stores a Web Push subscription (N1.1)
|
|
|
|
|
func (nh *NotificationHandlers) SubscribePush(c *gin.Context) {
|
|
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req SubscribePushRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.NewValidationError("invalid request body"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if nh.pushService == nil {
|
|
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "Push not configured"})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := nh.pushService.SubscribePush(c.Request.Context(), userID, req.Endpoint, req.Keys.P256dh, req.Keys.Auth); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to subscribe", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusCreated, gin.H{"message": "Subscribed"})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetPreferences returns notification preferences (N1.3)
|
|
|
|
|
func (nh *NotificationHandlers) GetPreferences(c *gin.Context) {
|
|
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prefs, err := nh.notificationService.GetPreferences(userID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to get preferences", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{
|
|
|
|
|
"push_follow": prefs.PushFollow,
|
|
|
|
|
"push_like": prefs.PushLike,
|
|
|
|
|
"push_comment": prefs.PushComment,
|
|
|
|
|
"push_message": prefs.PushMessage,
|
|
|
|
|
"push_mention": prefs.PushMention,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdatePreferencesRequest is the DTO for updating preferences
|
|
|
|
|
type UpdatePreferencesRequest struct {
|
|
|
|
|
PushFollow *bool `json:"push_follow"`
|
|
|
|
|
PushLike *bool `json:"push_like"`
|
|
|
|
|
PushComment *bool `json:"push_comment"`
|
|
|
|
|
PushMessage *bool `json:"push_message"`
|
|
|
|
|
PushMention *bool `json:"push_mention"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UpdatePreferences updates notification preferences (N1.3)
|
|
|
|
|
func (nh *NotificationHandlers) UpdatePreferences(c *gin.Context) {
|
|
|
|
|
userID, ok := GetUserIDUUID(c)
|
|
|
|
|
if !ok {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var req UpdatePreferencesRequest
|
|
|
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.NewValidationError("invalid request body"))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := nh.notificationService.UpdatePreferences(userID, req.PushFollow, req.PushLike, req.PushComment, req.PushMessage, req.PushMention); err != nil {
|
|
|
|
|
RespondWithAppError(c, apperrors.Wrap(apperrors.ErrCodeInternal, "Failed to update preferences", err))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RespondSuccess(c, http.StatusOK, gin.H{"message": "Preferences updated"})
|
|
|
|
|
}
|