diff --git a/aplus/settings.py b/aplus/settings.py
index eac9c47e1..75787aea1 100644
--- a/aplus/settings.py
+++ b/aplus/settings.py
@@ -187,6 +187,7 @@
'apps',
'redirect_old_urls',
'lti_tool',
+ 'site_alert',
'js_jquery_toggle',
'django_colortag',
diff --git a/course/templatetags/base.py b/course/templatetags/base.py
index 5cdc1c441..530a5ce38 100644
--- a/course/templatetags/base.py
+++ b/course/templatetags/base.py
@@ -7,6 +7,7 @@
from django.utils.translation import get_language, gettext_lazy as _
from lib.helpers import remove_query_param_from_url, settings_text, update_url_params
from exercise.submission_models import PendingSubmission
+from site_alert.models import SiteAlert
register = template.Library()
@@ -16,7 +17,7 @@ def pick_localized(message):
if message and isinstance(message, dict):
return (message.get(get_language()) or
message.get(settings.LANGUAGE_CODE[:2]) or
- message.values()[0])
+ list(message.values())[0])
return message
@@ -57,11 +58,13 @@ def course_alert(instance):
@register.simple_tag
def site_alert():
- message = settings.SITEWIDE_ALERT_TEXT
- if message:
- return mark_safe('
{}
'
- .format(pick_localized(message)))
- return ''
+ alerts = SiteAlert.objects.filter(status=SiteAlert.STATUS.ACTIVE)
+ return mark_safe(
+ ''.join(
+ '{}
'.format(pick_localized(alert.alert))
+ for alert in alerts
+ )
+ )
@register.simple_tag
diff --git a/deviations/admin.py b/deviations/admin.py
index dc2af264c..72bc4cc47 100644
--- a/deviations/admin.py
+++ b/deviations/admin.py
@@ -20,7 +20,7 @@ class DeadlineRuleDeviationAdmin(admin.ModelAdmin):
list_display = (
'submitter',
'exercise',
- 'extra_minutes',
+ 'extra_seconds',
'granter',
'grant_time',
)
diff --git a/deviations/forms.py b/deviations/forms.py
index b9576f2e6..04eb3468d 100644
--- a/deviations/forms.py
+++ b/deviations/forms.py
@@ -80,11 +80,11 @@ def clean(self) -> Dict[str, Any]:
class DeadlineRuleDeviationForm(BaseDeviationForm):
- minutes = DurationField(
+ seconds = DurationField(
required=False,
min_value=1,
- label=_('LABEL_MINUTES'),
- help_text=_('DEVIATION_EXTRA_MINUTES_HELPTEXT'),
+ label=_('LABEL_SECONDS'),
+ help_text=_('DEVIATION_EXTRA_SECONDS_HELPTEXT'),
)
new_date = forms.DateTimeField(
required=False,
@@ -108,10 +108,10 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
def clean(self) -> Dict[str, Any]:
cleaned_data = super().clean()
new_date = cleaned_data.get("new_date")
- minutes = cleaned_data.get("minutes")
- if minutes and new_date or not minutes and not new_date:
+ seconds = cleaned_data.get("seconds")
+ if seconds and new_date or not seconds and not new_date:
raise forms.ValidationError(
- _("MINUTES_AND_DATE_MISSING"))
+ _("SECONDS_AND_DATE_MISSING"))
return cleaned_data
diff --git a/deviations/migrations/0006_rename_extra_minutes_deadlineruledeviation_extra_seconds.py b/deviations/migrations/0006_rename_extra_minutes_deadlineruledeviation_extra_seconds.py
new file mode 100644
index 000000000..8df0ac19e
--- /dev/null
+++ b/deviations/migrations/0006_rename_extra_minutes_deadlineruledeviation_extra_seconds.py
@@ -0,0 +1,30 @@
+from django.db import migrations, models
+
+
+def multiply_by_sixty(apps, schema_editor):
+ DeadlineRuleDeviation = apps.get_model('deviations', 'DeadlineRuleDeviation')
+ # Retrieve all instances of DeadlineRuleDeviation and update extra_seconds field
+ for deviation in DeadlineRuleDeviation.objects.all():
+ deviation.extra_seconds *= 60
+ deviation.save()
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('deviations', '0005_auto_20220211_1540'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='deadlineruledeviation',
+ old_name='extra_minutes',
+ new_name='extra_seconds',
+ ),
+ migrations.AlterField(
+ model_name='deadlineruledeviation',
+ name='extra_seconds',
+ field=models.IntegerField(verbose_name='LABEL_EXTRA_SECONDS'),
+ ),
+ migrations.RunPython(multiply_by_sixty),
+ ]
diff --git a/deviations/models.py b/deviations/models.py
index 1b4d0768a..563fae13b 100644
--- a/deviations/models.py
+++ b/deviations/models.py
@@ -154,12 +154,12 @@ def get_override_url(cls, instance: CourseInstance) -> str:
class DeadlineRuleDeviationManager(SubmissionRuleDeviationManager['DeadlineRuleDeviation']):
- max_order_by = "-extra_minutes"
+ max_order_by = "-extra_seconds"
class DeadlineRuleDeviation(SubmissionRuleDeviation):
- extra_minutes = models.IntegerField(
- verbose_name=_('LABEL_EXTRA_MINUTES'),
+ extra_seconds = models.IntegerField(
+ verbose_name=_('LABEL_EXTRA_SECONDS'),
)
without_late_penalty = models.BooleanField(
verbose_name=_('LABEL_WITHOUT_LATE_PENALTY'),
@@ -173,7 +173,7 @@ class Meta(SubmissionRuleDeviation.Meta):
verbose_name_plural = _('MODEL_NAME_DEADLINE_RULE_DEVIATION_PLURAL')
def get_extra_time(self):
- return timedelta(minutes=self.extra_minutes)
+ return timedelta(seconds=self.extra_seconds)
def get_new_deadline(self, normal_deadline: Optional[datetime] = None) -> datetime:
"""
@@ -191,18 +191,18 @@ def get_normal_deadline(self):
return self.exercise.course_module.closing_time
def update_by_form(self, form_data: Dict[str, Any]) -> None:
- minutes = form_data.get('minutes')
+ seconds = form_data.get('seconds')
new_date = form_data.get('new_date')
if new_date:
- minutes = self.exercise.delta_in_minutes_from_closing_to_date(new_date)
+ seconds = self.exercise.delta_in_seconds_from_closing_to_date(new_date)
else:
- minutes = int(minutes)
- self.extra_minutes = minutes
+ seconds = int(seconds)
+ self.extra_seconds = seconds
self.without_late_penalty = bool(form_data.get('without_late_penalty'))
def is_groupable(self, other: 'DeadlineRuleDeviation') -> bool:
return (
- self.extra_minutes == other.extra_minutes
+ self.extra_seconds == other.extra_seconds
and self.without_late_penalty == other.without_late_penalty
)
diff --git a/deviations/templates/deviations/list_dl.html b/deviations/templates/deviations/list_dl.html
index d87b7d8e3..652b9b8c3 100644
--- a/deviations/templates/deviations/list_dl.html
+++ b/deviations/templates/deviations/list_dl.html
@@ -38,7 +38,7 @@ {% translate "DEADLINE_DEVIATIONS" %}
{% translate "SUBMITTER" %} |
{% translate "EXERCISE" %} |
- {% translate "EXTRA_MINUTES" %} |
+ {% translate "EXTRA_SECONDS" %} |
{% translate "DEADLINE" %} |
{% translate "DEADLINE_DEVIATIONS" %}
{% endblocktranslate %})
- | {{ deviations.0.extra_minutes }} |
+ {{ deviations.0.extra_seconds }} |
{{ deviations.0.get_new_deadline|date:'SHORT_DATETIME_FORMAT' }}
|
@@ -114,7 +114,7 @@ {% translate "DEADLINE_DEVIATIONS" %}
{{ deviation.exercise.hierarchical_name }} |
- {{ deviation.extra_minutes }} |
+ {{ deviation.extra_seconds }} |
{{ deviation.get_new_deadline|date:'SHORT_DATETIME_FORMAT' }}
|
diff --git a/deviations/templates/deviations/override_dl.html b/deviations/templates/deviations/override_dl.html
index 8f6f83068..24f5ef806 100644
--- a/deviations/templates/deviations/override_dl.html
+++ b/deviations/templates/deviations/override_dl.html
@@ -22,8 +22,8 @@ {% translate "SELECT_DEVIATIONS_TO_BE_OVERRIDDEN" %}
{% translate "SUBMITTER" %} |
{% translate "EXERCISE" %} |
- {% translate "EXTRA_MINUTES" %} ({% translate "OVERRIDE_BEFORE" %}) |
- {% translate "EXTRA_MINUTES" %} ({% translate "OVERRIDE_AFTER" %}) |
+ {% translate "EXTRA_SECONDS" %} ({% translate "OVERRIDE_BEFORE" %}) |
+ {% translate "EXTRA_SECONDS" %} ({% translate "OVERRIDE_AFTER" %}) |
{% translate "DEADLINE" %} ({% translate "OVERRIDE_BEFORE" %}) |
{% translate "DEADLINE" %} ({% translate "OVERRIDE_AFTER" %}) |
{% translate "SELECT_DEVIATIONS_TO_BE_OVERRIDDEN" %}
{% translate "UNKNOWN" as unknown %}
{% for deviations, can_group, group_id, _ in deviation_groups %}
- {% new_deviation_minutes deviations.0 session_data.minutes session_data.new_date as new_deviation_minutes %}
- {% new_deviation_date deviations.0 session_data.minutes session_data.new_date as new_deviation_date %}
+ {% new_deviation_seconds deviations.0 session_data.seconds session_data.new_date as new_deviation_seconds %}
+ {% new_deviation_date deviations.0 session_data.seconds session_data.new_date as new_deviation_date %}
{% if can_group %}
|
@@ -63,8 +63,8 @@ {% translate "SELECT_DEVIATIONS_TO_BE_OVERRIDDEN" %}
|
- {{ deviations.0.extra_minutes }} |
- {{ new_deviation_minutes }} |
+ {{ deviations.0.extra_seconds }} |
+ {{ new_deviation_seconds }} |
{{ deviations.0.get_new_deadline|date:'SHORT_DATETIME_FORMAT' }}
|
@@ -102,8 +102,8 @@ {% translate "SELECT_DEVIATIONS_TO_BE_OVERRIDDEN" %}
{{ deviation.exercise.hierarchical_name }} |
- {{ deviation.extra_minutes }} |
- {{ new_deviation_minutes }} |
+ {{ deviation.extra_seconds }} |
+ {{ new_deviation_seconds }} |
{{ deviation.get_new_deadline|date:'SHORT_DATETIME_FORMAT' }}
|
diff --git a/deviations/templatetags/deviations.py b/deviations/templatetags/deviations.py
index 29bc9a31d..679836a70 100644
--- a/deviations/templatetags/deviations.py
+++ b/deviations/templatetags/deviations.py
@@ -10,23 +10,23 @@
@register.simple_tag
-def new_deviation_minutes(
+def new_deviation_seconds(
deviation: DeadlineRuleDeviation,
- minutes: Optional[int],
+ seconds: Optional[int],
date: Optional[datetime.datetime]
) -> int:
"""
- Get the extra minutes for a deadline deviation after being overridden.
+ Get the extra seconds for a deadline deviation after being overridden.
"""
if date:
- return deviation.exercise.delta_in_minutes_from_closing_to_date(date)
- return minutes
+ return deviation.exercise.delta_in_seconds_from_closing_to_date(date)
+ return seconds
@register.simple_tag
def new_deviation_date(
deviation: DeadlineRuleDeviation,
- minutes: Optional[int],
+ seconds: Optional[int],
date: Optional[datetime.datetime]
) -> datetime.datetime:
"""
@@ -34,4 +34,4 @@ def new_deviation_date(
"""
if date:
return date
- return deviation.exercise.course_module.closing_time + datetime.timedelta(minutes=minutes)
+ return deviation.exercise.course_module.closing_time + datetime.timedelta(seconds=seconds)
diff --git a/deviations/tests.py b/deviations/tests.py
index 77965c627..a746c0cd1 100644
--- a/deviations/tests.py
+++ b/deviations/tests.py
@@ -42,8 +42,8 @@ def setUp(self):
url="Course-Url",
)
- # Truncate the datetime to minutes to make testing deadline deviations more convenient
- self.today = timezone.now().replace(second=0, microsecond=0)
+ # Truncate the datetime to seconds to make testing deadline deviations more convenient
+ self.today = timezone.now().replace(microsecond=0)
self.tomorrow = self.today + timedelta(days=1)
self.two_days_from_now = self.today + timedelta(days=2)
@@ -142,21 +142,21 @@ def setUp(self):
exercise=self.exercise_with_attachment,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=1440, # One day
+ extra_seconds=24*60*60, # One day
)
self.deadline_rule_deviation_u1_e2 = DeadlineRuleDeviation.objects.create(
exercise=self.exercise_with_attachment_2,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=2880, # Two days
+ extra_seconds=2*24*60*60, # Two days
)
self.deadline_rule_deviation_u2_e1 = DeadlineRuleDeviation.objects.create(
exercise=self.exercise_with_attachment,
submitter=self.user_2.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=4320, # Three days
+ extra_seconds=3*24*60*60, # Three days
)
def test_deadline_rule_deviation_extra_time(self):
@@ -181,7 +181,7 @@ def test_get_max_deviations(self):
)
self.assertIsNotNone(deviation)
self.assertEqual(deviation.exercise.id, self.exercise_with_attachment.id)
- self.assertEqual(deviation.extra_minutes, 1440)
+ self.assertEqual(deviation.extra_seconds, 24*60*60)
deviation = DeadlineRuleDeviation.objects.get_max_deviation(
self.user_2.userprofile,
@@ -189,7 +189,7 @@ def test_get_max_deviations(self):
)
self.assertIsNotNone(deviation)
self.assertEqual(deviation.exercise.id, self.exercise_with_attachment.id)
- self.assertEqual(deviation.extra_minutes, 4320)
+ self.assertEqual(deviation.extra_seconds, 3*24*60*60)
def test_get_max_deviations_multiple(self):
# Test that the get_max_deviations method returns the correct deviation
@@ -203,9 +203,9 @@ def test_get_max_deviations_multiple(self):
for deviation in deviations:
counter += 1
if deviation.exercise.id == self.exercise_with_attachment.id:
- self.assertEqual(deviation.extra_minutes, 1440)
+ self.assertEqual(deviation.extra_seconds, 24*60*60)
elif deviation.exercise.id == self.exercise_with_attachment_2.id:
- self.assertEqual(deviation.extra_minutes, 2880)
+ self.assertEqual(deviation.extra_seconds, 2*24*60*60)
else:
raise self.failureException('Unexpected exercise returned')
self.assertEqual(counter, 2)
@@ -218,7 +218,7 @@ def test_get_max_deviations_multiple(self):
for deviation in deviations:
counter += 1
if deviation.exercise.id == self.exercise_with_attachment.id:
- self.assertEqual(deviation.extra_minutes, 4320)
+ self.assertEqual(deviation.extra_seconds, 3*24*60*60)
else:
raise self.failureException('Unexpected exercise returned')
self.assertEqual(counter, 1)
@@ -240,7 +240,7 @@ def test_get_max_deviations_group(self):
)
self.assertIsNotNone(deviation)
self.assertEqual(deviation.exercise.id, self.exercise_with_attachment.id)
- self.assertEqual(deviation.extra_minutes, 4320)
+ self.assertEqual(deviation.extra_seconds, 3*24*60*60)
deviation = DeadlineRuleDeviation.objects.get_max_deviation(
self.user_2.userprofile,
@@ -248,7 +248,7 @@ def test_get_max_deviations_group(self):
)
self.assertIsNotNone(deviation)
self.assertEqual(deviation.exercise.id, self.exercise_with_attachment.id)
- self.assertEqual(deviation.extra_minutes, 4320)
+ self.assertEqual(deviation.extra_seconds, 3*24*60*60)
def test_update_by_form(self):
deviation = DeadlineRuleDeviation(
@@ -256,17 +256,17 @@ def test_update_by_form(self):
submitter=self.user.userprofile,
)
deviation.update_by_form({
- 'minutes': 60,
+ 'seconds': 60*60,
'without_late_penalty': False,
})
- self.assertEqual(deviation.extra_minutes, 60)
+ self.assertEqual(deviation.extra_seconds, 60*60)
self.assertEqual(deviation.without_late_penalty, False)
deviation.update_by_form({
'new_date': timezone.make_naive(self.two_days_from_now),
'without_late_penalty': True,
})
- self.assertEqual(deviation.extra_minutes, 1440)
+ self.assertEqual(deviation.extra_seconds, 24*60*60)
self.assertEqual(deviation.without_late_penalty, True)
deviation = MaxSubmissionsRuleDeviation(
exercise=self.exercise_with_attachment,
@@ -282,21 +282,21 @@ def test_is_groupable(self):
deviation_1 = DeadlineRuleDeviation(
exercise=self.exercise_with_attachment,
submitter=self.user.userprofile,
- extra_minutes=60,
+ extra_seconds=60*60,
without_late_penalty=False,
)
deviation_2 = DeadlineRuleDeviation(
exercise=self.exercise_with_attachment_2,
submitter=self.user_2.userprofile,
- extra_minutes=60,
+ extra_seconds=60*60,
without_late_penalty=False,
)
self.assertTrue(deviation_1.is_groupable(deviation_2))
- deviation_2.extra_minutes = 120
+ deviation_2.extra_seconds = 120*60
self.assertFalse(deviation_1.is_groupable(deviation_2))
- deviation_2.extra_minutes = 60
+ deviation_2.extra_seconds = 60*60
deviation_2.without_late_penalty = True
self.assertFalse(deviation_1.is_groupable(deviation_2))
@@ -316,7 +316,7 @@ def test_is_groupable(self):
self.assertFalse(deviation_1.is_groupable(deviation_2))
def test_get_deviation_groups(self):
- # The deviations of user 1 can't be grouped because of different extra minutes
+ # The deviations of user 1 can't be grouped because of different extra seconds
# The deviations of user 2 can't be grouped because there is only one deviation
groups = list(get_deviation_groups(DeadlineRuleDeviation.objects.all()))
deviations, can_group, group_id, _ = groups[0]
@@ -328,11 +328,11 @@ def test_get_deviation_groups(self):
self.assertFalse(can_group)
self.assertIsNone(group_id)
- self.deadline_rule_deviation_u1_e1.extra_minutes = 60
+ self.deadline_rule_deviation_u1_e1.extra_seconds = 60*60
self.deadline_rule_deviation_u1_e1.save()
- self.deadline_rule_deviation_u1_e2.extra_minutes = 60
+ self.deadline_rule_deviation_u1_e2.extra_seconds = 60*60
self.deadline_rule_deviation_u1_e2.save()
- self.deadline_rule_deviation_u2_e1.extra_minutes = 60
+ self.deadline_rule_deviation_u2_e1.extra_seconds = 60*60
self.deadline_rule_deviation_u2_e1.save()
# The deviations of user 1 can now be grouped
@@ -359,11 +359,11 @@ def test_get_deviation_groups(self):
self.assertIsNone(group_id)
# Reset original values
- self.deadline_rule_deviation_u1_e1.extra_minutes = 1440
+ self.deadline_rule_deviation_u1_e1.extra_seconds = 24*60*60
self.deadline_rule_deviation_u1_e1.save()
- self.deadline_rule_deviation_u1_e2.extra_minutes = 2880
+ self.deadline_rule_deviation_u1_e2.extra_seconds = 2*24*60*60
self.deadline_rule_deviation_u1_e2.save()
- self.deadline_rule_deviation_u2_e1.extra_minutes = 4320
+ self.deadline_rule_deviation_u2_e1.extra_seconds = 3*24*60*60
self.deadline_rule_deviation_u2_e1.save()
extra_exercise.delete()
@@ -377,7 +377,7 @@ def test_add_deadline_deviations(self):
{
'module': [self.course_module_2.id],
'submitter_tag': [self.user_tag.id],
- 'minutes': 60,
+ 'seconds': 60*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -387,13 +387,13 @@ def test_add_deadline_deviations(self):
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 60)
+ self.assertEqual(deviation.extra_seconds, 60*60)
deviation.delete()
deviation = DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 60)
+ self.assertEqual(deviation.extra_seconds, 60*60)
deviation.delete()
with self.assertRaises(DeadlineRuleDeviation.DoesNotExist):
@@ -413,7 +413,7 @@ def test_add_deadline_deviations(self):
{
'exercise': [self.module_2_exercise_1.id],
'submitter': [self.user.userprofile.id, self.user_2.userprofile.id],
- 'minutes': 120,
+ 'seconds': 120*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -423,13 +423,13 @@ def test_add_deadline_deviations(self):
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 120)
+ self.assertEqual(deviation.extra_seconds, 120*60)
deviation.delete()
deviation = DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user_2.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 120)
+ self.assertEqual(deviation.extra_seconds, 120*60)
deviation.delete()
with self.assertRaises(DeadlineRuleDeviation.DoesNotExist):
@@ -451,7 +451,7 @@ def test_add_deadline_deviations(self):
'exercise': [self.module_2_exercise_1.id],
'submitter_tag': [self.user_tag.id],
'submitter': [self.user_2.userprofile.id],
- 'minutes': 180,
+ 'seconds': 180*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -461,25 +461,25 @@ def test_add_deadline_deviations(self):
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 180)
+ self.assertEqual(deviation.extra_seconds, 180*60)
deviation.delete()
deviation = DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user_2.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 180)
+ self.assertEqual(deviation.extra_seconds, 180*60)
deviation.delete()
deviation = DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 180)
+ self.assertEqual(deviation.extra_seconds, 180*60)
deviation.delete()
deviation = DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user_2.userprofile,
)
- self.assertEqual(deviation.extra_minutes, 180)
+ self.assertEqual(deviation.extra_seconds, 180*60)
deviation.delete()
# No extra deviations should have been created
@@ -498,7 +498,7 @@ def test_override_deadline_deviations(self):
{
'exercise': [self.module_2_exercise_1.id],
'submitter': [self.user.userprofile.id],
- 'minutes': 30,
+ 'seconds': 30*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -508,8 +508,8 @@ def test_override_deadline_deviations(self):
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
- ).extra_minutes,
- 30,
+ ).extra_seconds,
+ 30*60,
)
# Create new deviations, one overlapping the initial deviation
@@ -518,7 +518,7 @@ def test_override_deadline_deviations(self):
{
'exercise': [self.module_2_exercise_1.id, self.module_2_exercise_2.id],
'submitter': [self.user.userprofile.id],
- 'minutes': 60,
+ 'seconds': 60*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -528,8 +528,8 @@ def test_override_deadline_deviations(self):
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
- ).extra_minutes,
- 30,
+ ).extra_seconds,
+ 30*60,
)
with self.assertRaises(DeadlineRuleDeviation.DoesNotExist):
DeadlineRuleDeviation.objects.get(
@@ -551,15 +551,15 @@ def test_override_deadline_deviations(self):
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
- ).extra_minutes,
- 60,
+ ).extra_seconds,
+ 60*60,
)
self.assertEqual(
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user.userprofile,
- ).extra_minutes,
- 60,
+ ).extra_seconds,
+ 60*60,
)
# Create deviations overlapping both deviations, override 2nd one
@@ -568,7 +568,7 @@ def test_override_deadline_deviations(self):
{
'exercise': [self.module_2_exercise_1.id, self.module_2_exercise_2.id],
'submitter': [self.user.userprofile.id],
- 'minutes': 120,
+ 'seconds': 120*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -587,15 +587,15 @@ def test_override_deadline_deviations(self):
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
- ).extra_minutes,
- 60,
+ ).extra_seconds,
+ 60*60,
)
self.assertEqual(
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user.userprofile,
- ).extra_minutes,
- 120,
+ ).extra_seconds,
+ 120*60,
)
DeadlineRuleDeviation.objects.filter(exercise__course_module=self.course_module_2).delete()
@@ -611,7 +611,7 @@ def test_remove_deadline_deviations(self):
{
'exercise': [self.module_2_exercise_1.id, self.module_2_exercise_2.id],
'submitter': [self.user.userprofile.id],
- 'minutes': 45,
+ 'seconds': 45*60,
}
)
self.assertEqual(response.status_code, 302)
@@ -621,15 +621,15 @@ def test_remove_deadline_deviations(self):
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_1,
submitter=self.user.userprofile,
- ).extra_minutes,
- 45,
+ ).extra_seconds,
+ 45*60,
)
self.assertEqual(
DeadlineRuleDeviation.objects.get(
exercise=self.module_2_exercise_2,
submitter=self.user.userprofile,
- ).extra_minutes,
- 45,
+ ).extra_seconds,
+ 45*60,
)
# Remove one deviation
diff --git a/deviations/views.py b/deviations/views.py
index 8a09aed0d..4465c2b21 100644
--- a/deviations/views.py
+++ b/deviations/views.py
@@ -34,7 +34,7 @@ def get_success_no_override_url(self) -> str:
def get_initial_get_param_spec(self) -> Dict[str, Optional[Callable[[str], Any]]]:
spec = super().get_initial_get_param_spec()
spec.update({
- "minutes": int,
+ "seconds": int,
"new_date": None,
"without_late_penalty": lambda x: x == "true",
})
@@ -43,7 +43,7 @@ def get_initial_get_param_spec(self) -> Dict[str, Optional[Callable[[str], Any]]
def serialize_session_data(self, form_data: Dict[str, Any]) -> Dict[str, Any]:
result = super().serialize_session_data(form_data)
result.update({
- 'minutes': form_data['minutes'],
+ 'seconds': form_data['seconds'],
'new_date': str(form_data['new_date']) if form_data['new_date'] else None,
'without_late_penalty': form_data['without_late_penalty'],
})
@@ -61,7 +61,7 @@ def get_success_url(self) -> str:
def deserialize_session_data(self, session_data: Dict[str, Any]) -> Dict[str, Any]:
result = super().deserialize_session_data(session_data)
result.update({
- 'minutes': session_data['minutes'],
+ 'seconds': session_data['seconds'],
'new_date': parse_datetime(session_data['new_date']) if session_data['new_date'] else None,
'without_late_penalty': session_data['without_late_penalty'],
})
diff --git a/exercise/cache/points.py b/exercise/cache/points.py
index 3904a5254..cfc18e8b1 100644
--- a/exercise/cache/points.py
+++ b/exercise/cache/points.py
@@ -665,7 +665,7 @@ def _generate_data( # noqa: MC0001
self.personal_deadline_has_penalty = None
for deviation in deadline_deviations:
self.personal_deadline = (
- self.closing_time + datetime.timedelta(minutes=deviation.extra_minutes)
+ self.closing_time + datetime.timedelta(seconds=deviation.extra_seconds)
)
self.personal_deadline_has_penalty = not deviation.without_late_penalty
diff --git a/exercise/exercise_models.py b/exercise/exercise_models.py
index a70a51e38..96aa58992 100644
--- a/exercise/exercise_models.py
+++ b/exercise/exercise_models.py
@@ -730,18 +730,18 @@ def get_timing(self, students, when):
return self.TIMING.CLOSED_AFTER, dl
- def delta_in_minutes_from_closing_to_date(self, future_date):
+ def delta_in_seconds_from_closing_to_date(self, future_date):
module_close = self.course_module.closing_time
# module_close is in utc format 2018-04-10 23:59:00+00:00
# while future_date from the teacher submitted form might
- # be in different formet, eg. 2018-05-15 23:59:00+03:00
+ # be in a different format, e.g., 2018-05-15 23:59:00+03:00
# -> convert future_date to same format as module_close
- string_date = str(future_date)[:16]
+ string_date = str(future_date)[:19]
converted = timezone.make_aware(
parse_datetime(string_date),
timezone.get_current_timezone())
delta = converted - module_close
- return delta.days * 24 * 60 + delta.seconds // 60
+ return delta.days * 24 * 60 * 60 + delta.seconds
def one_has_access(self, students, when=None):
"""
diff --git a/exercise/management/commands/export_submissions.py b/exercise/management/commands/export_submissions.py
index e6b7af944..7ffdf84c3 100644
--- a/exercise/management/commands/export_submissions.py
+++ b/exercise/management/commands/export_submissions.py
@@ -270,7 +270,7 @@ def handle(self, *args, **options): # noqa: MC0001
'exercise__course_module__closing_time',
'exercise__course_module__course_instance__id',
'submitter__user__id',
- 'extra_minutes',
+ 'extra_seconds',
)
for dl_dev in all_deadline_deviations_queryset:
diff --git a/exercise/reveal_models.py b/exercise/reveal_models.py
index 6c7429689..3053b619e 100644
--- a/exercise/reveal_models.py
+++ b/exercise/reveal_models.py
@@ -75,11 +75,13 @@ def get_reveal_time(self, state: 'BaseRevealState') -> Optional[datetime.datetim
if self.trigger in [RevealRule.TRIGGER.DEADLINE, RevealRule.TRIGGER.DEADLINE_OR_FULL_POINTS]:
deadline = state.get_deadline()
if deadline is not None:
- return deadline + datetime.timedelta(minutes=self.delay_minutes or 0)
+ seconds = self.delay_minutes * 60 if self.delay_minutes else 0
+ return deadline + datetime.timedelta(seconds=seconds)
elif self.trigger == RevealRule.TRIGGER.DEADLINE_ALL:
latest_deadline = state.get_latest_deadline()
if latest_deadline is not None:
- return latest_deadline + datetime.timedelta(minutes=self.delay_minutes or 0)
+ seconds = self.delay_minutes * 60 if self.delay_minutes else 0
+ return latest_deadline + datetime.timedelta(seconds=seconds)
return None
diff --git a/exercise/reveal_states.py b/exercise/reveal_states.py
index aa86f6c9d..6466c35fb 100644
--- a/exercise/reveal_states.py
+++ b/exercise/reveal_states.py
@@ -117,7 +117,7 @@ def get_latest_deadline(self) -> Optional[datetime.datetime]:
self.max_deviation = (
DeadlineRuleDeviation.objects
.filter(exercise_id=self.cache.id)
- .order_by('-extra_minutes').first()
+ .order_by('-extra_seconds').first()
)
self.max_deviation_fetched = True
if self.max_deviation is not None:
@@ -163,7 +163,7 @@ def get_latest_deadline(self) -> Optional[datetime.datetime]:
self.max_deviation = (
DeadlineRuleDeviation.objects
.filter(exercise__course_module_id=self.module_id)
- .order_by('-extra_minutes').first()
+ .order_by('-extra_seconds').first()
)
self.max_deviation_fetched = True
if self.max_deviation is not None:
diff --git a/exercise/tests.py b/exercise/tests.py
index 7d5d23248..fac2b8fd9 100644
--- a/exercise/tests.py
+++ b/exercise/tests.py
@@ -259,7 +259,7 @@ def setUp(self): # pylint: disable=too-many-statements
exercise=self.exercise_with_attachment,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=1440 # One day
+ extra_seconds=24*60*60 # One day
)
@@ -431,7 +431,7 @@ def test_base_exercise_deadline_deviation(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=10*24*60
+ extra_seconds=10*24*60*60 # Ten days
)
self.assertTrue(self.old_base_exercise.one_has_access([self.user.userprofile])[0])
@@ -557,7 +557,7 @@ def test_submission_late_penalty_applied(self):
exercise=self.base_exercise_with_late_submission_allowed,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=10*24*60,
+ extra_seconds=10*24*60*60,
without_late_penalty=True
)
self.late_late_submission_when_late_allowed.set_points(5, 10)
@@ -913,7 +913,7 @@ def test_can_show_model_solutions(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=1440, # One day
+ extra_seconds=24*60*60, # One day
)
self.assertFalse(self.old_base_exercise.can_show_model_solutions_to_student(self.user))
# Change the deadline extension so that it is not active anymore.
@@ -924,7 +924,7 @@ def test_can_show_model_solutions(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=10,
+ extra_seconds=10*60,
)
self.assertTrue(self.old_base_exercise.can_show_model_solutions_to_student(self.user))
@@ -941,7 +941,7 @@ def test_can_show_model_solutions(self):
exercise=base_exercise_with_late_closed,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=60*24*2,
+ extra_seconds=2*24*60*60, # Two days
)
self.assertFalse(base_exercise_with_late_closed.can_show_model_solutions_to_student(self.user))
self.assertFalse(base_exercise_with_late_closed.can_show_model_solutions_to_student(self.user2))
@@ -951,7 +951,7 @@ def test_can_show_model_solutions(self):
exercise=base_exercise_with_late_closed,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=10,
+ extra_seconds=10*60,
)
self.assertTrue(base_exercise_with_late_closed.can_show_model_solutions_to_student(self.user))
self.assertTrue(base_exercise_with_late_closed.can_show_model_solutions_to_student(self.user2))
@@ -967,7 +967,7 @@ def test_can_be_shown_as_module_model_solution(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=1440, # One day
+ extra_seconds=24*60*60, # One day
)
reveal_rule = RevealRule.objects.create(
trigger=RevealRule.TRIGGER.DEADLINE,
@@ -987,7 +987,7 @@ def test_can_be_shown_as_module_model_solution(self):
self.assertFalse(self.static_exercise.can_be_shown_as_module_model_solution(self.user))
self.assertTrue(chapter.can_be_shown_as_module_model_solution(self.user2))
- deadline_deviation_old_base_exercise.extra_minutes = 0
+ deadline_deviation_old_base_exercise.extra_seconds = 0
deadline_deviation_old_base_exercise.save()
self.assertTrue(chapter.can_be_shown_as_module_model_solution(self.user))
self.assertTrue(self.base_exercise.can_be_shown_as_module_model_solution(self.user))
@@ -1037,7 +1037,7 @@ def test_reveal_rule(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=30,
+ extra_seconds=30*60,
)
old_reveal_state_deviation = ExerciseRevealState(self.old_base_exercise, self.user)
user2_old_reveal_state_deviation = ExerciseRevealState(self.old_base_exercise, self.user2)
@@ -1176,7 +1176,7 @@ def test_module_reveal_state(self):
exercise=self.old_base_exercise,
submitter=self.user.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=4320,
+ extra_seconds=3*24*60*60, # Three days
) # this should have not effect on the module reveal state
user_reveal_state = ModuleRevealState(self.course_module, self.user)
diff --git a/exercise/tests_cache.py b/exercise/tests_cache.py
index fdb48c159..98fba60d7 100644
--- a/exercise/tests_cache.py
+++ b/exercise/tests_cache.py
@@ -604,7 +604,7 @@ def test_is_revealed(self):
exercise=self.exercise0,
submitter=self.student.userprofile,
granter=self.teacher.userprofile,
- extra_minutes=2*24*60,
+ extra_seconds=2*24*60*60,
)
reveal_rule = RevealRule.objects.create(
trigger=RevealRule.TRIGGER.DEADLINE,
diff --git a/lib/fields.py b/lib/fields.py
index 8ff67bce3..1ed93654a 100644
--- a/lib/fields.py
+++ b/lib/fields.py
@@ -31,14 +31,15 @@ class DurationField(forms.MultiValueField):
boxes, one for each given unit of time. The units of time are, by default,
days, hours and minutes, but they can also be customized by passing a list
of tuples where the first item is the name of the unit and the second item
- is its factor relative to minutes (e.g. 60 for hours).
+ is its factor relative to seconds (e.g. 3600 for hours).
"""
- DAYS = (_('DURATION_UNIT_DAYS'), 60 * 24)
- HOURS = (_('DURATION_UNIT_HOURS'), 60)
- MINUTES = (_('DURATION_UNIT_MINUTES'), 1)
+ DAYS = (_('DURATION_UNIT_DAYS'), 60 * 60 * 24)
+ HOURS = (_('DURATION_UNIT_HOURS'), 60 * 60)
+ MINUTES = (_('DURATION_UNIT_MINUTES'), 60)
+ SECONDS = (_('DURATION_UNIT_SECONDS'), 1)
# Default units
- units: List[Tuple[str, int]] = [DAYS, HOURS, MINUTES]
+ units: List[Tuple[str, int]] = [DAYS, HOURS, MINUTES, SECONDS]
def __init__( # pylint: disable=keyword-arg-before-vararg
self,
@@ -62,16 +63,16 @@ def __init__( # pylint: disable=keyword-arg-before-vararg
def compress(self, data_list: List[Optional[int]]) -> Optional[int]:
"""
- Convert the values given in different units into minutes.
+ Convert the values given in different units into seconds.
"""
- total_minutes = None
+ total_seconds = None
for value, (_name, factor) in zip(data_list, self.units):
if value is None:
continue
- if total_minutes is None:
- total_minutes = 0
- total_minutes += value * factor
- return total_minutes
+ if total_seconds is None:
+ total_seconds = 0
+ total_seconds += value * factor
+ return total_seconds
class SearchSelectField(forms.ModelMultipleChoiceField):
diff --git a/locale/en/LC_MESSAGES/django.po b/locale/en/LC_MESSAGES/django.po
index d1531d404..02ef6a4c3 100644
--- a/locale/en/LC_MESSAGES/django.po
+++ b/locale/en/LC_MESSAGES/django.po
@@ -336,11 +336,11 @@ msgstr "Assistant"
msgid "TEACHER"
msgstr "Teacher"
-#: course/models.py
+#: course/models.py site_alert/models.py
msgid "ACTIVE"
msgstr "Active"
-#: course/models.py
+#: course/models.py site_alert/models.py
msgid "REMOVED"
msgstr "Removed"
@@ -381,7 +381,7 @@ msgid "LABEL_ROLE"
msgstr "role"
#: course/models.py exercise/admin.py exercise/exercise_models.py
-#: exercise/submission_models.py
+#: exercise/submission_models.py site_alert/models.py
msgid "LABEL_STATUS"
msgstr "status"
@@ -1524,11 +1524,11 @@ msgid "SUBMITTERS_AND_TAGS_MISSING"
msgstr "You have to define submitters or tags."
#: deviations/forms.py
-msgid "LABEL_MINUTES"
+msgid "LABEL_SECONDS"
msgstr "Extra time"
#: deviations/forms.py
-msgid "DEVIATION_EXTRA_MINUTES_HELPTEXT"
+msgid "DEVIATION_EXTRA_SECONDS_HELPTEXT"
msgstr "Amount of extra time given. Leave blank if you fill in the date below."
#: deviations/forms.py
@@ -1571,7 +1571,7 @@ msgstr ""
"granted to these students IN ADDITION to the ones with the tags."
#: deviations/forms.py
-msgid "MINUTES_AND_DATE_MISSING"
+msgid "SECONDS_AND_DATE_MISSING"
msgstr "You have to provide either the extra time or a date in the future."
#: deviations/forms.py deviations/models.py
@@ -1622,8 +1622,8 @@ msgid "MODEL_NAME_SUBMISSION_RULE_DEVIATION_PLURAL"
msgstr "submission rule deviations"
#: deviations/models.py
-msgid "LABEL_EXTRA_MINUTES"
-msgstr "extra minutes"
+msgid "LABEL_EXTRA_SECONDS"
+msgstr "extra seconds"
#: deviations/models.py
msgid "MODEL_NAME_DEADLINE_RULE_DEVIATION"
@@ -1727,8 +1727,8 @@ msgstr "Assignment"
#: deviations/templates/deviations/list_dl.html
#: deviations/templates/deviations/override_dl.html
-msgid "EXTRA_MINUTES"
-msgstr "Extra minutes"
+msgid "EXTRA_SECONDS"
+msgstr "Extra seconds"
#: deviations/templates/deviations/list_dl.html
#: deviations/templates/deviations/override_dl.html
@@ -5281,6 +5281,10 @@ msgstr "hours"
msgid "DURATION_UNIT_MINUTES"
msgstr "minutes"
+#: lib/fields.py
+msgid "DURATION_UNIT_SECONDS"
+msgstr "seconds"
+
#: lib/fields.py
msgid "CLIPBOARD_STUDENT_IDS"
msgstr "Student IDs"
@@ -5454,6 +5458,18 @@ msgstr ""
msgid "SHIBBOLETH_ERROR_USER_ACCOUNT_DISABLED"
msgstr "The user account has been disabled."
+#: site_alert/models.py
+msgid "LABEL_ALERT"
+msgstr "alert"
+
+#: site_alert/models.py
+msgid "MODEL_NAME_SITEALERT"
+msgstr "site alert"
+
+#: site_alert/models.py
+msgid "MODEL_NAME_SITEALERT_PLURAL"
+msgstr "site alerts"
+
#: templates/403.html
msgid "ACCESS_RESTRICTED_403"
msgstr "Access restricted"
diff --git a/locale/fi/LC_MESSAGES/django.po b/locale/fi/LC_MESSAGES/django.po
index 614d01ebb..2d158b495 100644
--- a/locale/fi/LC_MESSAGES/django.po
+++ b/locale/fi/LC_MESSAGES/django.po
@@ -337,11 +337,11 @@ msgstr "Assistentti"
msgid "TEACHER"
msgstr "Opettaja"
-#: course/models.py
+#: course/models.py site_alert/models.py
msgid "ACTIVE"
msgstr "Aktiivinen"
-#: course/models.py
+#: course/models.py site_alert/models.py
msgid "REMOVED"
msgstr "Poistettu"
@@ -382,7 +382,7 @@ msgid "LABEL_ROLE"
msgstr "rooli"
#: course/models.py exercise/admin.py exercise/exercise_models.py
-#: exercise/submission_models.py
+#: exercise/submission_models.py site_alert/models.py
msgid "LABEL_STATUS"
msgstr "tila"
@@ -1533,11 +1533,11 @@ msgid "SUBMITTERS_AND_TAGS_MISSING"
msgstr "Valitse opiskelijat tai merkinnät."
#: deviations/forms.py
-msgid "LABEL_MINUTES"
+msgid "LABEL_SECONDS"
msgstr "Ylimääräistä palautusaikaa"
#: deviations/forms.py
-msgid "DEVIATION_EXTRA_MINUTES_HELPTEXT"
+msgid "DEVIATION_EXTRA_SECONDS_HELPTEXT"
msgstr ""
"Annettu ylimääräinen palautusaika. Jätä tyhjäksi mikäli ilmoitat määräajan "
"alempana."
@@ -1582,7 +1582,7 @@ msgstr ""
"joilla on kyseiset merkinnät."
#: deviations/forms.py
-msgid "MINUTES_AND_DATE_MISSING"
+msgid "SECONDS_AND_DATE_MISSING"
msgstr "Syötä joko ylimääräinen palautusaika tai uusi määräaika."
#: deviations/forms.py deviations/models.py
@@ -1633,8 +1633,8 @@ msgid "MODEL_NAME_SUBMISSION_RULE_DEVIATION_PLURAL"
msgstr "palautusääntöjen poikkeamat"
#: deviations/models.py
-msgid "LABEL_EXTRA_MINUTES"
-msgstr "ylimääräiset minuutit"
+msgid "LABEL_EXTRA_SECONDS"
+msgstr "ylimääräiset sekunnit"
#: deviations/models.py
msgid "MODEL_NAME_DEADLINE_RULE_DEVIATION"
@@ -1738,7 +1738,7 @@ msgstr "Tehtävä"
#: deviations/templates/deviations/list_dl.html
#: deviations/templates/deviations/override_dl.html
-msgid "EXTRA_MINUTES"
+msgid "EXTRA_SECONDS"
msgstr "Ylimääräiset minuutit"
#: deviations/templates/deviations/list_dl.html
@@ -5302,6 +5302,10 @@ msgstr "tunnit"
msgid "DURATION_UNIT_MINUTES"
msgstr "minuutit"
+#: lib/fields.py
+msgid "DURATION_UNIT_SECONDS"
+msgstr "sekunnit"
+
#: lib/fields.py
msgid "CLIPBOARD_STUDENT_IDS"
msgstr "Opiskelijanumerot"
@@ -5474,6 +5478,18 @@ msgstr ""
msgid "SHIBBOLETH_ERROR_USER_ACCOUNT_DISABLED"
msgstr "Käyttäjätili on poistettu käytöstä."
+#: site_alert/models.py
+msgid "LABEL_ALERT"
+msgstr "varoitus"
+
+#: site_alert/models.py
+msgid "MODEL_NAME_SITEALERT"
+msgstr "sivustovaroitus"
+
+#: site_alert/models.py
+msgid "MODEL_NAME_SITEALERT_PLURAL"
+msgstr "sivustovaroitukset"
+
#: templates/403.html
msgid "ACCESS_RESTRICTED_403"
msgstr "Pääsy kielletty"
diff --git a/site_alert/__init__.py b/site_alert/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/site_alert/admin.py b/site_alert/admin.py
new file mode 100644
index 000000000..81d080ece
--- /dev/null
+++ b/site_alert/admin.py
@@ -0,0 +1,19 @@
+from django.contrib import admin
+from django.utils.translation import gettext_lazy as _
+
+from site_alert.models import SiteAlert
+
+
+class SiteAlertAdmin(admin.ModelAdmin):
+ search_fields = (
+ 'alert',
+ 'status',
+ )
+ list_display = (
+ 'id',
+ 'alert',
+ 'status',
+ )
+
+
+admin.site.register(SiteAlert, SiteAlertAdmin)
diff --git a/site_alert/apps.py b/site_alert/apps.py
new file mode 100644
index 000000000..533a1308d
--- /dev/null
+++ b/site_alert/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class SiteAlertConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'site_alert'
diff --git a/site_alert/migrations/0001_initial.py b/site_alert/migrations/0001_initial.py
new file mode 100644
index 000000000..741054863
--- /dev/null
+++ b/site_alert/migrations/0001_initial.py
@@ -0,0 +1,26 @@
+# Generated by Django 4.2.10 on 2024-03-08 07:48
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='SiteAlert',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('alert', models.JSONField(verbose_name='LABEL_ALERT')),
+ ('status', models.IntegerField(choices=[(1, 'ACTIVE'), (2, 'REMOVED')], default=1, verbose_name='LABEL_STATUS')),
+ ],
+ options={
+ 'verbose_name': 'MODEL_NAME_SITEALERT',
+ 'verbose_name_plural': 'MODEL_NAME_SITEALERT_PLURAL',
+ },
+ ),
+ ]
diff --git a/site_alert/migrations/__init__.py b/site_alert/migrations/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/site_alert/models.py b/site_alert/models.py
new file mode 100644
index 000000000..29f24b7ee
--- /dev/null
+++ b/site_alert/models.py
@@ -0,0 +1,28 @@
+from django.db import models
+from django.utils.translation import gettext_lazy as _
+
+from lib.helpers import Enum
+
+
+class SiteAlert(models.Model):
+ """
+ SiteAlert models represents sitewide alerts. There can be a single or
+ multiple alerts active simultaneously.
+ """
+ STATUS = Enum([
+ ('ACTIVE', 1, _('ACTIVE')),
+ ('REMOVED', 2, _('REMOVED')),
+ ])
+
+ alert = models.JSONField(
+ verbose_name=_('LABEL_ALERT')
+ )
+ status = models.IntegerField(
+ verbose_name=_('LABEL_STATUS'),
+ choices=STATUS.choices,
+ default=STATUS.ACTIVE,
+ )
+
+ class Meta:
+ verbose_name = _('MODEL_NAME_SITEALERT')
+ verbose_name_plural = _('MODEL_NAME_SITEALERT_PLURAL')
\ No newline at end of file