@ -58,6 +58,7 @@ class ScheduledNotification(models.Model):
ALL_PROFESSORS = ' all_professors ' , _ ( ' All Professors ' )
ALL_PROFESSORS = ' all_professors ' , _ ( ' All Professors ' )
class ScheduleTypeChoices ( models . TextChoices ) :
class ScheduleTypeChoices ( models . TextChoices ) :
DO_NOT_REPEAT = ' do_not_repeat ' , _ ( ' Do Not Repeat ' )
DAILY = ' daily ' , _ ( ' Daily ' )
DAILY = ' daily ' , _ ( ' Daily ' )
WEEKLY = ' weekly ' , _ ( ' Weekly ' )
WEEKLY = ' weekly ' , _ ( ' Weekly ' )
MONTHLY = ' monthly ' , _ ( ' Monthly ' )
MONTHLY = ' monthly ' , _ ( ' Monthly ' )
@ -76,7 +77,8 @@ class ScheduledNotification(models.Model):
is_active = models . BooleanField ( default = True , verbose_name = _ ( ' is active ' ) )
is_active = models . BooleanField ( default = True , verbose_name = _ ( ' is active ' ) )
schedule_type = models . CharField ( max_length = 20 , choices = ScheduleTypeChoices . choices , default = ScheduleTypeChoices . DAILY , verbose_name = _ ( ' schedule type ' ) )
schedule_type = models . CharField ( max_length = 20 , choices = ScheduleTypeChoices . choices , default = ScheduleTypeChoices . DO_NOT_REPEAT , verbose_name = _ ( ' schedule type ' ) )
scheduled_time = models . DateTimeField ( null = True , blank = True , verbose_name = _ ( ' scheduled time ' ) )
time_of_day = models . TimeField ( default = " 09:00:00 " , verbose_name = _ ( ' time of day ' ) )
time_of_day = models . TimeField ( default = " 09:00:00 " , verbose_name = _ ( ' time of day ' ) )
days_of_week = models . CharField ( max_length = 50 , blank = True , null = True , help_text = _ ( ' Comma-separated days (1 for Mon, 6 for Sat, 0 for Sun). E.g. " 6,0 " for Sat and Sun. ' ) , verbose_name = _ ( ' days of week ' ) )
days_of_week = models . CharField ( max_length = 50 , blank = True , null = True , help_text = _ ( ' Comma-separated days (1 for Mon, 6 for Sat, 0 for Sun). E.g. " 6,0 " for Sat and Sun. ' ) , verbose_name = _ ( ' days of week ' ) )
@ -99,37 +101,58 @@ class ScheduledNotification(models.Model):
return self . name
return self . name
def save ( self , * args , * * kwargs ) :
def save ( self , * args , * * kwargs ) :
from django_celery_beat.models import CrontabSchedule , PeriodicTask
from django_celery_beat.models import CrontabSchedule , ClockedSchedule , PeriodicTask
import json
import json
from django.conf import settings
from django.conf import settings
# Calculate cron fields based on schedule_type
minute = str ( self . time_of_day . minute )
hour = str ( self . time_of_day . hour )
day_of_month = ' * '
month_of_year = ' * '
day_of_week = ' * '
if self . schedule_type == self . ScheduleTypeChoices . DAILY :
pass
elif self . schedule_type == self . ScheduleTypeChoices . WEEKLY :
day_of_week = self . days_of_week or ' * '
elif self . schedule_type == self . ScheduleTypeChoices . MONTHLY :
day_of_month = self . days_of_month or ' 1 '
elif self . schedule_type == self . ScheduleTypeChoices . CRON :
if self . custom_cron :
parts = self . custom_cron . split ( )
if len ( parts ) > = 5 :
minute , hour , day_of_month , month_of_year , day_of_week = parts [ : 5 ]
schedule , _ = CrontabSchedule . objects . get_or_create (
minute = minute ,
hour = hour ,
day_of_week = day_of_week ,
day_of_month = day_of_month ,
month_of_year = month_of_year ,
timezone = getattr ( settings , ' CELERY_TIMEZONE ' , ' Asia/Tehran ' )
)
schedule = None
clocked = None
one_off = False
if self . schedule_type == self . ScheduleTypeChoices . DO_NOT_REPEAT :
if self . scheduled_time :
clocked , _ = ClockedSchedule . objects . get_or_create (
clocked_time = self . scheduled_time
)
one_off = True
else :
if self . periodic_task :
task = self . periodic_task
self . periodic_task = None
super ( ) . save ( * args , * * kwargs )
task . delete ( )
return
else :
super ( ) . save ( * args , * * kwargs )
return
else :
# Calculate cron fields based on schedule_type
minute = str ( self . time_of_day . minute )
hour = str ( self . time_of_day . hour )
day_of_month = ' * '
month_of_year = ' * '
day_of_week = ' * '
if self . schedule_type == self . ScheduleTypeChoices . DAILY :
pass
elif self . schedule_type == self . ScheduleTypeChoices . WEEKLY :
day_of_week = self . days_of_week or ' * '
elif self . schedule_type == self . ScheduleTypeChoices . MONTHLY :
day_of_month = self . days_of_month or ' 1 '
elif self . schedule_type == self . ScheduleTypeChoices . CRON :
if self . custom_cron :
parts = self . custom_cron . split ( )
if len ( parts ) > = 5 :
minute , hour , day_of_month , month_of_year , day_of_week = parts [ : 5 ]
schedule , _ = CrontabSchedule . objects . get_or_create (
minute = minute ,
hour = hour ,
day_of_week = day_of_week ,
day_of_month = day_of_month ,
month_of_year = month_of_year ,
timezone = getattr ( settings , ' CELERY_TIMEZONE ' , ' Asia/Tehran ' )
)
task_name = f " Scheduled Notification: {self.name} "
task_name = f " Scheduled Notification: {self.name} "
task_kwargs = json . dumps ( {
task_kwargs = json . dumps ( {
@ -140,6 +163,8 @@ class ScheduledNotification(models.Model):
task = self . periodic_task
task = self . periodic_task
task . name = task_name
task . name = task_name
task . crontab = schedule
task . crontab = schedule
task . clocked = clocked
task . one_off = one_off
task . enabled = self . is_active
task . enabled = self . is_active
task . kwargs = task_kwargs
task . kwargs = task_kwargs
task . save ( )
task . save ( )
@ -148,6 +173,8 @@ class ScheduledNotification(models.Model):
name = task_name ,
name = task_name ,
task = ' apps.account.tasks.run_scheduled_notification_task ' ,
task = ' apps.account.tasks.run_scheduled_notification_task ' ,
crontab = schedule ,
crontab = schedule ,
clocked = clocked ,
one_off = one_off ,
enabled = self . is_active ,
enabled = self . is_active ,
kwargs = task_kwargs
kwargs = task_kwargs
)
)