151 lines
6.3 KiB
Go
151 lines
6.3 KiB
Go
package entities
|
|
|
|
import (
|
|
"database/sql/driver"
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type NotificationPriority string
|
|
type NotificationDeliveryStatus string
|
|
type NotificationChannel string
|
|
type NotificationProvider string
|
|
|
|
const (
|
|
NotificationPriorityLow NotificationPriority = "low"
|
|
NotificationPriorityNormal NotificationPriority = "normal"
|
|
NotificationPriorityHigh NotificationPriority = "high"
|
|
|
|
NotificationDeliveryStatusPending NotificationDeliveryStatus = "pending"
|
|
NotificationDeliveryStatusSent NotificationDeliveryStatus = "sent"
|
|
NotificationDeliveryStatusDelivered NotificationDeliveryStatus = "delivered"
|
|
NotificationDeliveryStatusFailed NotificationDeliveryStatus = "failed"
|
|
|
|
NotificationChannelPush NotificationChannel = "push"
|
|
NotificationChannelWebsocket NotificationChannel = "websocket"
|
|
NotificationChannelEmail NotificationChannel = "email"
|
|
|
|
NotificationProviderFirebase NotificationProvider = "firebase"
|
|
)
|
|
|
|
// NotificationData is a JSON-serializable map for extra notification payload.
|
|
type NotificationData map[string]interface{}
|
|
|
|
func (d NotificationData) Value() (driver.Value, error) {
|
|
if d == nil {
|
|
return nil, nil
|
|
}
|
|
return json.Marshal(d)
|
|
}
|
|
|
|
func (d *NotificationData) Scan(value interface{}) error {
|
|
if value == nil {
|
|
*d = nil
|
|
return nil
|
|
}
|
|
bytes, ok := value.([]byte)
|
|
if !ok {
|
|
return errors.New("type assertion to []byte failed")
|
|
}
|
|
return json.Unmarshal(bytes, d)
|
|
}
|
|
|
|
// Notification is the master notification record.
|
|
type Notification struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
Title string `gorm:"not null;size:255" json:"title"`
|
|
Body string `gorm:"type:text" json:"body"`
|
|
Type string `gorm:"size:100" json:"type"`
|
|
Category string `gorm:"size:100" json:"category"`
|
|
Priority NotificationPriority `gorm:"size:50;default:'normal'" json:"priority"`
|
|
ImageURL string `gorm:"size:512" json:"image_url"`
|
|
ActionURL string `gorm:"size:512" json:"action_url"`
|
|
NotifiableType string `gorm:"size:100" json:"notifiable_type"`
|
|
NotifiableID *uuid.UUID `gorm:"type:uuid" json:"notifiable_id"`
|
|
Data NotificationData `gorm:"type:jsonb" json:"data"`
|
|
ScheduledAt *time.Time `gorm:"type:timestamptz" json:"scheduled_at"`
|
|
SentAt *time.Time `gorm:"type:timestamptz" json:"sent_at"`
|
|
ExpiredAt *time.Time `gorm:"type:timestamptz" json:"expired_at"`
|
|
CreatedBy *uuid.UUID `gorm:"type:uuid" json:"created_by"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
|
|
Creator *User `gorm:"foreignKey:CreatedBy" json:"creator,omitempty"`
|
|
Receivers []*NotificationReceiver `gorm:"foreignKey:NotificationID" json:"receivers,omitempty"`
|
|
}
|
|
|
|
func (n *Notification) BeforeCreate(tx *gorm.DB) error {
|
|
if n.ID == uuid.Nil {
|
|
n.ID = uuid.New()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (Notification) TableName() string {
|
|
return "notifications"
|
|
}
|
|
|
|
// NotificationReceiver links a notification to a specific user.
|
|
type NotificationReceiver struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
NotificationID uuid.UUID `gorm:"type:uuid;not null;index" json:"notification_id"`
|
|
UserID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_id"`
|
|
IsRead bool `gorm:"default:false" json:"is_read"`
|
|
ReadAt *time.Time `gorm:"type:timestamptz" json:"read_at"`
|
|
IsDeleted bool `gorm:"default:false" json:"is_deleted"`
|
|
DeletedAt *time.Time `gorm:"type:timestamptz" json:"deleted_at"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
|
|
Notification *Notification `gorm:"foreignKey:NotificationID" json:"notification,omitempty"`
|
|
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
|
|
Deliveries []*NotificationDelivery `gorm:"foreignKey:NotificationReceiverID" json:"deliveries,omitempty"`
|
|
}
|
|
|
|
func (n *NotificationReceiver) BeforeCreate(tx *gorm.DB) error {
|
|
if n.ID == uuid.Nil {
|
|
n.ID = uuid.New()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (NotificationReceiver) TableName() string {
|
|
return "notification_receivers"
|
|
}
|
|
|
|
// NotificationDelivery tracks per-device delivery attempts.
|
|
type NotificationDelivery struct {
|
|
ID uuid.UUID `gorm:"type:uuid;primary_key;default:gen_random_uuid()" json:"id"`
|
|
NotificationReceiverID uuid.UUID `gorm:"type:uuid;not null;index" json:"notification_receiver_id"`
|
|
UserDeviceID uuid.UUID `gorm:"type:uuid;not null;index" json:"user_device_id"`
|
|
Channel NotificationChannel `gorm:"size:50;default:'push'" json:"channel"`
|
|
DeliveryStatus NotificationDeliveryStatus `gorm:"size:50;default:'pending'" json:"delivery_status"`
|
|
Provider NotificationProvider `gorm:"size:50" json:"provider"`
|
|
ProviderMessageID string `gorm:"size:255" json:"provider_message_id"`
|
|
SentAt *time.Time `gorm:"type:timestamptz" json:"sent_at"`
|
|
DeliveredAt *time.Time `gorm:"type:timestamptz" json:"delivered_at"`
|
|
FailedAt *time.Time `gorm:"type:timestamptz" json:"failed_at"`
|
|
FailureReason string `gorm:"type:text" json:"failure_reason"`
|
|
RetryCount int `gorm:"default:0" json:"retry_count"`
|
|
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
|
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
|
|
|
NotificationReceiver *NotificationReceiver `gorm:"foreignKey:NotificationReceiverID" json:"notification_receiver,omitempty"`
|
|
UserDevice *UserDevice `gorm:"foreignKey:UserDeviceID" json:"user_device,omitempty"`
|
|
}
|
|
|
|
func (n *NotificationDelivery) BeforeCreate(tx *gorm.DB) error {
|
|
if n.ID == uuid.Nil {
|
|
n.ID = uuid.New()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (NotificationDelivery) TableName() string {
|
|
return "notification_deliveries"
|
|
}
|