140 lines
3.7 KiB
Go
140 lines
3.7 KiB
Go
|
|
package jobs
|
||
|
|
|
||
|
|
import (
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ReminderConfig represents the configuration for reminder scheduling
|
||
|
|
type ReminderConfig struct {
|
||
|
|
// Default reminder times before the meeting (in minutes)
|
||
|
|
DefaultReminders []int `json:"default_reminders"`
|
||
|
|
|
||
|
|
// Maximum number of reminders per booking
|
||
|
|
MaxReminders int `json:"max_reminders"`
|
||
|
|
|
||
|
|
// Minimum time before meeting to send reminder (in minutes)
|
||
|
|
MinReminderTime int `json:"min_reminder_time"`
|
||
|
|
|
||
|
|
// Whether reminders are enabled globally
|
||
|
|
Enabled bool `json:"enabled"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// DefaultReminderConfig returns the default reminder configuration
|
||
|
|
func DefaultReminderConfig() *ReminderConfig {
|
||
|
|
return &ReminderConfig{
|
||
|
|
DefaultReminders: []int{1440, 60, 15}, // 24 hours, 1 hour, 15 minutes before
|
||
|
|
MaxReminders: 3,
|
||
|
|
MinReminderTime: 5, // Don't send reminders less than 5 minutes before
|
||
|
|
Enabled: true,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ReminderScheduler handles the scheduling of reminder notifications
|
||
|
|
type ReminderScheduler struct {
|
||
|
|
config *ReminderConfig
|
||
|
|
jobScheduler *JobScheduler
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewReminderScheduler creates a new reminder scheduler
|
||
|
|
func NewReminderScheduler(config *ReminderConfig, jobScheduler *JobScheduler) *ReminderScheduler {
|
||
|
|
if config == nil {
|
||
|
|
config = DefaultReminderConfig()
|
||
|
|
}
|
||
|
|
|
||
|
|
return &ReminderScheduler{
|
||
|
|
config: config,
|
||
|
|
jobScheduler: jobScheduler,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ScheduleRemindersForBooking schedules all reminders for a booking
|
||
|
|
func (rs *ReminderScheduler) ScheduleRemindersForBooking(bookingID uint, userID uint, meetingTime time.Time) error {
|
||
|
|
if !rs.config.Enabled {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
now := time.Now()
|
||
|
|
scheduledCount := 0
|
||
|
|
|
||
|
|
for _, reminderMinutes := range rs.config.DefaultReminders {
|
||
|
|
if scheduledCount >= rs.config.MaxReminders {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
|
||
|
|
reminderTime := meetingTime.Add(-time.Duration(reminderMinutes) * time.Minute)
|
||
|
|
|
||
|
|
// Skip if reminder time is in the past
|
||
|
|
if reminderTime.Before(now) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
// Skip if reminder is too close to the meeting
|
||
|
|
if meetingTime.Sub(reminderTime).Minutes() < float64(rs.config.MinReminderTime) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
|
||
|
|
// Schedule the reminder job
|
||
|
|
rs.jobScheduler.ScheduleReminderJob(bookingID, userID, reminderTime)
|
||
|
|
scheduledCount++
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// CancelRemindersForBooking cancels all scheduled reminders for a booking
|
||
|
|
func (rs *ReminderScheduler) CancelRemindersForBooking(bookingID uint) error {
|
||
|
|
// In a production system, this would mark the reminders as cancelled in a persistent store
|
||
|
|
// For now, we'll just log the cancellation
|
||
|
|
// The actual implementation would depend on how jobs are persisted
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// UpdateReminderConfig updates the reminder configuration
|
||
|
|
func (rs *ReminderScheduler) UpdateReminderConfig(config *ReminderConfig) {
|
||
|
|
rs.config = config
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetReminderConfig returns the current reminder configuration
|
||
|
|
func (rs *ReminderScheduler) GetReminderConfig() *ReminderConfig {
|
||
|
|
return rs.config
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetNextReminderTime calculates the next reminder time for a meeting
|
||
|
|
func (rs *ReminderScheduler) GetNextReminderTime(meetingTime time.Time) *time.Time {
|
||
|
|
if !rs.config.Enabled {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
now := time.Now()
|
||
|
|
|
||
|
|
for _, reminderMinutes := range rs.config.DefaultReminders {
|
||
|
|
reminderTime := meetingTime.Add(-time.Duration(reminderMinutes) * time.Minute)
|
||
|
|
|
||
|
|
if reminderTime.After(now) {
|
||
|
|
return &reminderTime
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// IsReminderTimeValid checks if a reminder time is valid
|
||
|
|
func (rs *ReminderScheduler) IsReminderTimeValid(reminderTime, meetingTime time.Time) bool {
|
||
|
|
if !rs.config.Enabled {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if reminder is in the future
|
||
|
|
if reminderTime.Before(time.Now()) {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if reminder is not too close to the meeting
|
||
|
|
timeDiff := meetingTime.Sub(reminderTime).Minutes()
|
||
|
|
if timeDiff < float64(rs.config.MinReminderTime) {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
return true
|
||
|
|
}
|