357 lines
12 KiB
Go
357 lines
12 KiB
Go
package repository
|
|
|
|
// import (
|
|
// "context"
|
|
// "encoding/json"
|
|
// "fmt"
|
|
|
|
// dbgen "Yimaru-Backend/gen/db"
|
|
// "Yimaru-Backend/internal/domain"
|
|
// "Yimaru-Backend/internal/ports"
|
|
// "github.com/jackc/pgx/v5/pgtype"
|
|
// )
|
|
|
|
// func NewNotificationStore(s *Store) ports.NotificationStore { return s }
|
|
|
|
// func (r *Store) CreateNotification(ctx context.Context, notification *domain.Notification) (*domain.Notification, error) {
|
|
// var errorSeverity pgtype.Text
|
|
// if notification.ErrorSeverity != "" {
|
|
// errorSeverity.String = string(notification.ErrorSeverity)
|
|
// errorSeverity.Valid = true
|
|
// }
|
|
|
|
// var deliveryChannel pgtype.Text
|
|
// if notification.DeliveryChannel != "" {
|
|
// deliveryChannel.String = string(notification.DeliveryChannel)
|
|
// deliveryChannel.Valid = true
|
|
// }
|
|
|
|
// var priority pgtype.Int4
|
|
// if notification.Priority != 0 {
|
|
// priority.Int32 = int32(notification.Priority)
|
|
// priority.Valid = true
|
|
// }
|
|
|
|
// params := dbgen.CreateNotificationParams{
|
|
// ID: notification.ID,
|
|
// RecipientID: notification.RecipientID,
|
|
// Type: string(notification.Type),
|
|
// Level: string(notification.Level),
|
|
// ErrorSeverity: errorSeverity,
|
|
// Reciever: string(notification.Reciever),
|
|
// IsRead: notification.IsRead,
|
|
// DeliveryStatus: string(notification.DeliveryStatus),
|
|
// DeliveryChannel: deliveryChannel,
|
|
// Payload: marshalPayload(notification.Payload),
|
|
// Priority: priority,
|
|
// Timestamp: pgtype.Timestamptz{Time: notification.Timestamp, Valid: true},
|
|
// Expires: pgtype.Timestamptz{Time: notification.Expires, Valid: true},
|
|
// Img: pgtype.Text{String: notification.Image, Valid: notification.Image != ""},
|
|
// Metadata: notification.Metadata,
|
|
// }
|
|
|
|
// dbNotification, err := r.queries.CreateNotification(ctx, params)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// return r.mapDBToDomain(&dbNotification), nil
|
|
// }
|
|
|
|
// func (r *Store) UpdateNotificationStatus(ctx context.Context, id, status string, isRead bool, metadata []byte) (*domain.Notification, error) {
|
|
// params := dbgen.UpdateNotificationStatusParams{
|
|
// ID: id,
|
|
// DeliveryStatus: status,
|
|
// IsRead: isRead,
|
|
// Metadata: metadata,
|
|
// }
|
|
|
|
// dbNotification, err := r.queries.UpdateNotificationStatus(ctx, params)
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// return r.mapDBToDomain(&dbNotification), nil
|
|
// }
|
|
|
|
// func (r *Store) GetUserNotifications(ctx context.Context, recipientID int64, limit, offset int) ([]domain.Notification, int64, error) {
|
|
// params := dbgen.GetUserNotificationsParams{
|
|
// RecipientID: recipientID,
|
|
// Limit: int32(limit),
|
|
// Offset: int32(offset),
|
|
// }
|
|
|
|
// dbNotifications, err := r.queries.GetUserNotifications(ctx, params)
|
|
// if err != nil {
|
|
// return nil, 0, err
|
|
// }
|
|
|
|
// total, err := r.queries.GetUserNotificationCount(ctx, recipientID)
|
|
|
|
// if err != nil {
|
|
// return nil, 0, err
|
|
// }
|
|
|
|
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
|
// for _, dbNotif := range dbNotifications {
|
|
// domainNotif := r.mapDBToDomain(&dbNotif)
|
|
// result = append(result, *domainNotif)
|
|
// }
|
|
|
|
// return result, total, nil
|
|
// }
|
|
|
|
// func (r *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
|
|
|
// dbNotifications, err := r.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
|
// Limit: int32(limit),
|
|
// Offset: int32(offset),
|
|
// })
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// var result []domain.Notification = make([]domain.Notification, 0, len(dbNotifications))
|
|
// for _, dbNotif := range dbNotifications {
|
|
// domainNotif := r.mapDBToDomain(&dbNotif)
|
|
// result = append(result, *domainNotif)
|
|
// }
|
|
// return result, nil
|
|
// }
|
|
|
|
// func (r *Store) ListFailedNotifications(ctx context.Context, limit int) ([]domain.Notification, error) {
|
|
// dbNotifications, err := r.queries.ListFailedNotifications(ctx, int32(limit))
|
|
// if err != nil {
|
|
// return nil, err
|
|
// }
|
|
|
|
// var result []domain.Notification
|
|
// for _, dbNotif := range dbNotifications {
|
|
// domainNotif := r.mapDBToDomain(&dbNotif)
|
|
// result = append(result, *domainNotif)
|
|
// }
|
|
|
|
// return result, nil
|
|
// }
|
|
|
|
// func (r *Store) ListRecipientIDs(ctx context.Context, receiver domain.NotificationRecieverSide) ([]int64, error) {
|
|
// return r.queries.ListRecipientIDsByReceiver(ctx, string(receiver))
|
|
// }
|
|
|
|
// func (s *Store) DeleteOldNotifications(ctx context.Context) error {
|
|
// return s.queries.DeleteOldNotifications(ctx)
|
|
// }
|
|
|
|
// func (r *Store) mapDBToDomain(dbNotif *dbgen.Notification) *domain.Notification {
|
|
// var errorSeverity domain.NotificationErrorSeverity
|
|
// if dbNotif.ErrorSeverity.Valid {
|
|
// errorSeverity = domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
|
|
|
|
// } else {
|
|
// errorSeverity = ""
|
|
// }
|
|
|
|
// var deliveryChannel domain.DeliveryChannel
|
|
// if dbNotif.DeliveryChannel.Valid {
|
|
// deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String)
|
|
// } else {
|
|
// deliveryChannel = ""
|
|
// }
|
|
|
|
// var priority int
|
|
// if dbNotif.Priority.Valid {
|
|
// priority = int(dbNotif.Priority.Int32)
|
|
// }
|
|
|
|
// payload, err := unmarshalPayload(dbNotif.Payload)
|
|
// if err != nil {
|
|
// payload = domain.NotificationPayload{}
|
|
// }
|
|
|
|
// return &domain.Notification{
|
|
// ID: dbNotif.ID,
|
|
// RecipientID: dbNotif.RecipientID,
|
|
// Type: domain.NotificationType(dbNotif.Type),
|
|
// Level: domain.NotificationLevel(dbNotif.Level),
|
|
// ErrorSeverity: errorSeverity,
|
|
// Reciever: domain.NotificationRecieverSide(dbNotif.Reciever),
|
|
// IsRead: dbNotif.IsRead,
|
|
// DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus),
|
|
// DeliveryChannel: deliveryChannel,
|
|
// Payload: payload,
|
|
// Priority: priority,
|
|
// Timestamp: dbNotif.Timestamp.Time,
|
|
// Expires: dbNotif.Expires.Time,
|
|
// Image: dbNotif.Img.String,
|
|
// Metadata: dbNotif.Metadata,
|
|
// }
|
|
// }
|
|
|
|
// func marshalPayload(payload domain.NotificationPayload) []byte {
|
|
// data, _ := json.Marshal(payload)
|
|
// return data
|
|
// }
|
|
|
|
// func unmarshalPayload(data []byte) (domain.NotificationPayload, error) {
|
|
// var payload domain.NotificationPayload
|
|
// if err := json.Unmarshal(data, &payload); err != nil {
|
|
// return domain.NotificationPayload{}, err
|
|
// }
|
|
// return payload, nil
|
|
// }
|
|
|
|
// func (r *Store) CountUnreadNotifications(ctx context.Context, recipient_id int64) (int64, error) {
|
|
// return r.queries.CountUnreadNotifications(ctx, recipient_id)
|
|
// }
|
|
|
|
// func (r *Store) GetNotificationCounts(ctx context.Context, filter domain.ReportFilter) (total, read, unread int64, err error) {
|
|
// rows, err := r.queries.GetNotificationCounts(ctx)
|
|
// if err != nil {
|
|
// return 0, 0, 0, fmt.Errorf("failed to get notification counts: %w", err)
|
|
// }
|
|
|
|
// // var total, read, unread int64
|
|
// for _, row := range rows {
|
|
// total += row.Total
|
|
// read += row.Read
|
|
// unread += row.Unread
|
|
// }
|
|
|
|
// return total, read, unread, nil
|
|
// }
|
|
|
|
// func (s *Store) GetMostActiveNotificationRecipients(ctx context.Context, filter domain.ReportFilter, limit int) ([]domain.ActiveNotificationRecipient, error) {
|
|
// query := `SELECT
|
|
// n.recipient_id,
|
|
// u.first_name || ' ' || u.last_name as recipient_name,
|
|
// COUNT(*) as notification_count,
|
|
// MAX(n.timestamp) as last_notification_time
|
|
// FROM notifications n
|
|
// JOIN users u ON n.recipient_id = u.id
|
|
// WHERE n.timestamp BETWEEN $1 AND $2
|
|
// GROUP BY n.recipient_id, u.first_name, u.last_name
|
|
// ORDER BY notification_count DESC
|
|
// LIMIT $3`
|
|
|
|
// var recipients []domain.ActiveNotificationRecipient
|
|
// rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value, limit)
|
|
// if err != nil {
|
|
// return nil, fmt.Errorf("failed to get active notification recipients: %w", err)
|
|
// }
|
|
// defer rows.Close()
|
|
|
|
// for rows.Next() {
|
|
// var r domain.ActiveNotificationRecipient
|
|
// if err := rows.Scan(&r.RecipientID, &r.RecipientName, &r.NotificationCount, &r.LastNotificationTime); err != nil {
|
|
// return nil, err
|
|
// }
|
|
// recipients = append(recipients, r)
|
|
// }
|
|
|
|
// return recipients, nil
|
|
// }
|
|
|
|
// // GetNotificationDeliveryStats
|
|
// func (s *Store) GetNotificationDeliveryStats(ctx context.Context, filter domain.ReportFilter) (domain.NotificationDeliveryStats, error) {
|
|
// query := `SELECT
|
|
// COUNT(*) as total_sent,
|
|
// COUNT(CASE WHEN delivery_status = 'failed' THEN 1 END) as failed_deliveries,
|
|
// (COUNT(CASE WHEN delivery_status = 'sent' THEN 1 END) * 100.0 / NULLIF(COUNT(*), 0)) as success_rate,
|
|
// MODE() WITHIN GROUP (ORDER BY delivery_channel) as most_used_channel
|
|
// FROM notifications
|
|
// WHERE timestamp BETWEEN $1 AND $2`
|
|
|
|
// var stats domain.NotificationDeliveryStats
|
|
// row := s.conn.QueryRow(ctx, query, filter.StartTime.Value, filter.EndTime.Value)
|
|
// err := row.Scan(&stats.TotalSent, &stats.FailedDeliveries, &stats.SuccessRate, &stats.MostUsedChannel)
|
|
// if err != nil {
|
|
// return domain.NotificationDeliveryStats{}, fmt.Errorf("failed to get notification delivery stats: %w", err)
|
|
// }
|
|
|
|
// return stats, nil
|
|
// }
|
|
|
|
// // GetNotificationCountsByType
|
|
// func (s *Store) GetNotificationCountsByType(ctx context.Context, filter domain.ReportFilter) (map[string]domain.NotificationTypeCount, error) {
|
|
// query := `SELECT
|
|
// type,
|
|
// COUNT(*) as total,
|
|
// COUNT(CASE WHEN is_read = true THEN 1 END) as read,
|
|
// COUNT(CASE WHEN is_read = false THEN 1 END) as unread
|
|
// FROM notifications
|
|
// WHERE timestamp BETWEEN $1 AND $2
|
|
// GROUP BY type`
|
|
|
|
// counts := make(map[string]domain.NotificationTypeCount)
|
|
// rows, err := s.conn.Query(ctx, query, filter.StartTime.Value, filter.EndTime.Value)
|
|
// if err != nil {
|
|
// return nil, fmt.Errorf("failed to get notification counts by type: %w", err)
|
|
// }
|
|
// defer rows.Close()
|
|
|
|
// for rows.Next() {
|
|
// var nt domain.NotificationTypeCount
|
|
// var typ string
|
|
// if err := rows.Scan(&typ, &nt.Total, &nt.Read, &nt.Unread); err != nil {
|
|
// return nil, err
|
|
// }
|
|
// counts[typ] = nt
|
|
// }
|
|
|
|
// return counts, nil
|
|
// }
|
|
|
|
// // func (s *Store) GetAllNotifications(ctx context.Context, limit, offset int) ([]domain.Notification, error) {
|
|
// // dbNotifications, err := s.queries.GetAllNotifications(ctx, dbgen.GetAllNotificationsParams{
|
|
// // Limit: int32(limit),
|
|
// // Offset: int32(offset),
|
|
// // })
|
|
// // if err != nil {
|
|
// // return nil, err
|
|
// // }
|
|
|
|
// // result := make([]domain.Notification, 0, len(dbNotifications))
|
|
// // for _, dbNotif := range dbNotifications {
|
|
// // // You may want to move this mapping logic to a shared function if not already present
|
|
// // var errorSeverity *domain.NotificationErrorSeverity
|
|
// // if dbNotif.ErrorSeverity.Valid {
|
|
// // s := domain.NotificationErrorSeverity(dbNotif.ErrorSeverity.String)
|
|
// // errorSeverity = &s
|
|
// // }
|
|
|
|
// // var deliveryChannel domain.DeliveryChannel
|
|
// // if dbNotif.DeliveryChannel.Valid {
|
|
// // deliveryChannel = domain.DeliveryChannel(dbNotif.DeliveryChannel.String)
|
|
// // } else {
|
|
// // deliveryChannel = ""
|
|
// // }
|
|
|
|
// // var priority int
|
|
// // if dbNotif.Priority.Valid {
|
|
// // priority = int(dbNotif.Priority.Int32)
|
|
// // }
|
|
|
|
// // payload, err := unmarshalPayload(dbNotif.Payload)
|
|
// // if err != nil {
|
|
// // payload = domain.NotificationPayload{}
|
|
// // }
|
|
|
|
// // result = append(result, domain.Notification{
|
|
// // ID: dbNotif.ID,
|
|
// // RecipientID: dbNotif.RecipientID,
|
|
// // Type: domain.NotificationType(dbNotif.Type),
|
|
// // Level: domain.NotificationLevel(dbNotif.Level),
|
|
// // ErrorSeverity: errorSeverity,
|
|
// // Reciever: domain.NotificationRecieverSide(dbNotif.Reciever),
|
|
// // IsRead: dbNotif.IsRead,
|
|
// // DeliveryStatus: domain.NotificationDeliveryStatus(dbNotif.DeliveryStatus),
|
|
// // DeliveryChannel: deliveryChannel,
|
|
// // Payload: payload,
|
|
// // Priority: priority,
|
|
// // Timestamp: dbNotif.Timestamp.Time,
|
|
// // Metadata: dbNotif.Metadata,
|
|
// // })
|
|
// // }
|
|
// // return result, nil
|
|
// // }
|