- Add comprehensive validation and error handling for Notification model - Introduce strongly typed enums for notification types and statuses - Implement GORM hooks for pre-create and pre-update validation - Add helper methods for notification retry and sending logic - Improve Schedule model with validation, availability checks, and duration methods - Add constraints and validation for schedule time slots - Enhance model relationships with foreign key references - Implement additional utility methods for schedule management Improves data integrity, adds robust validation, and provides more comprehensive model behaviors for notifications and schedules.
118 lines
3.9 KiB
Go
118 lines
3.9 KiB
Go
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
|
|
}
|