package models import ( "errors" "time" "gorm.io/gorm" ) // NotificationType represents the different types of notifications type NotificationType string const ( NotificationTypeWelcome NotificationType = "welcome" NotificationTypePaymentSuccess NotificationType = "payment_success" NotificationTypePaymentFailed NotificationType = "payment_failed" NotificationTypeMeetingInfo NotificationType = "meeting_info" NotificationTypeReminder NotificationType = "reminder" NotificationTypeCancellation NotificationType = "cancellation" NotificationTypeReschedule NotificationType = "reschedule" ) // NotificationStatus represents the status of a notification type NotificationStatus string const ( NotificationStatusPending NotificationStatus = "pending" NotificationStatusSent NotificationStatus = "sent" NotificationStatusFailed NotificationStatus = "failed" NotificationStatusSkipped NotificationStatus = "skipped" ) // Notification represents email notifications type Notification struct { gorm.Model UserID uint `json:"user_id" gorm:"index" validate:"required"` User User `json:"user" gorm:"foreignKey:UserID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE"` BookingID *uint `json:"booking_id" gorm:"index"` Booking *Booking `json:"booking" gorm:"foreignKey:BookingID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"` Type NotificationType `json:"type" gorm:"not null;size:50;index" validate:"required,oneof=welcome payment_success payment_failed meeting_info reminder cancellation reschedule"` Subject string `json:"subject" gorm:"not null;size:255" validate:"required,max=255"` Body string `json:"body" gorm:"type:text" validate:"required"` SentAt *time.Time `json:"sent_at" gorm:"index"` Status NotificationStatus `json:"status" gorm:"default:'pending';size:20;index" validate:"required,oneof=pending sent failed skipped"` ScheduledAt *time.Time `json:"scheduled_at" gorm:"index"` RetryCount int `json:"retry_count" gorm:"default:0;check:retry_count >= 0"` ErrorMsg string `json:"error_msg" gorm:"size:500"` } // BeforeCreate is a GORM hook that runs before creating a notification record func (n *Notification) BeforeCreate(tx *gorm.DB) error { // Set default status if not provided if n.Status == "" { n.Status = NotificationStatusPending } // Validate required fields if n.Subject == "" { return errors.New("notification subject is required") } if n.Body == "" { return errors.New("notification body is required") } // If scheduled at is not set, schedule for immediate sending if n.ScheduledAt == nil { now := time.Now() n.ScheduledAt = &now } return nil } // BeforeUpdate is a GORM hook that runs before updating a notification record func (n *Notification) BeforeUpdate(tx *gorm.DB) error { // If status is being set to sent, set SentAt timestamp if n.Status == NotificationStatusSent && n.SentAt == nil { now := time.Now() n.SentAt = &now } return nil } // IsReadyToSend checks if the notification is ready to be sent func (n *Notification) IsReadyToSend() bool { if n.Status != NotificationStatusPending { return false } if n.ScheduledAt == nil { return true } return n.ScheduledAt.Before(time.Now()) || n.ScheduledAt.Equal(time.Now()) } // CanRetry checks if the notification can be retried (max 3 retries) func (n *Notification) CanRetry() bool { return n.Status == NotificationStatusFailed && n.RetryCount < 3 } // MarkAsSent marks the notification as successfully sent func (n *Notification) MarkAsSent() { n.Status = NotificationStatusSent now := time.Now() n.SentAt = &now n.ErrorMsg = "" } // MarkAsFailed marks the notification as failed with an error message func (n *Notification) MarkAsFailed(errorMsg string) { n.Status = NotificationStatusFailed n.RetryCount++ n.ErrorMsg = errorMsg }