Skip to content

Commit 657ce95

Browse files
ahmedxgoudakasya
andauthored
Update owasp app event model with calendar attributes and add reminder models (#2128)
* Update event * Add slack member and channel id fields * Apply rabbit's suggestion * Apply suggestions * Add null possibility to channel in remainder * Apply rabbit suggestions * Use channel id and add tests * Apply suggestions and add reminder shedule --------- Co-authored-by: Kate Golovanova <[email protected]>
1 parent a88d7fa commit 657ce95

11 files changed

+414
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Generated by Django 5.2.4 on 2025-09-02 13:29
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("nest", "0007_alter_googleaccountauthorization_options_and_more"),
10+
("slack", "0018_conversation_sync_messages"),
11+
]
12+
13+
operations = [
14+
migrations.CreateModel(
15+
name="Reminder",
16+
fields=[
17+
(
18+
"id",
19+
models.BigAutoField(
20+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
21+
),
22+
),
23+
(
24+
"channel_id",
25+
models.CharField(default="", max_length=15, verbose_name="Channel ID"),
26+
),
27+
("message", models.TextField(verbose_name="Reminder Message")),
28+
(
29+
"member",
30+
models.ForeignKey(
31+
null=True,
32+
on_delete=django.db.models.deletion.SET_NULL,
33+
related_name="reminders",
34+
to="slack.member",
35+
verbose_name="Slack Member",
36+
),
37+
),
38+
],
39+
options={
40+
"verbose_name": "Nest Reminder",
41+
"verbose_name_plural": "Nest Reminders",
42+
"db_table": "nest_reminders",
43+
},
44+
),
45+
migrations.CreateModel(
46+
name="ReminderSchedule",
47+
fields=[
48+
(
49+
"id",
50+
models.BigAutoField(
51+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
52+
),
53+
),
54+
("scheduled_time", models.DateTimeField(verbose_name="Scheduled Time")),
55+
(
56+
"recurrence",
57+
models.CharField(
58+
choices=[
59+
("once", "Once"),
60+
("daily", "Daily"),
61+
("weekly", "Weekly"),
62+
("monthly", "Monthly"),
63+
],
64+
default="once",
65+
max_length=50,
66+
verbose_name="Recurrence",
67+
),
68+
),
69+
(
70+
"reminder",
71+
models.ForeignKey(
72+
on_delete=django.db.models.deletion.CASCADE,
73+
related_name="schedules",
74+
to="nest.reminder",
75+
verbose_name="Nest Reminder",
76+
),
77+
),
78+
],
79+
options={
80+
"verbose_name": "Nest Reminder Schedule",
81+
"verbose_name_plural": "Nest Reminder Schedules",
82+
"db_table": "nest_reminder_schedules",
83+
},
84+
),
85+
]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from .api_key import ApiKey
22
from .badge import Badge
33
from .google_account_authorization import GoogleAccountAuthorization
4+
from .reminder import Reminder
5+
from .reminder_schedule import ReminderSchedule
46
from .user import User
57
from .user_badge import UserBadge
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Nest Reminder model."""
2+
3+
from django.db import models
4+
5+
6+
class Reminder(models.Model):
7+
"""Model representing a reminder."""
8+
9+
class Meta:
10+
db_table = "nest_reminders"
11+
verbose_name = "Nest Reminder"
12+
verbose_name_plural = "Nest Reminders"
13+
14+
member = models.ForeignKey(
15+
"slack.Member",
16+
verbose_name="Slack Member",
17+
on_delete=models.SET_NULL,
18+
related_name="reminders",
19+
null=True,
20+
)
21+
channel_id = models.CharField(verbose_name="Channel ID", max_length=15, default="")
22+
message = models.TextField(verbose_name="Reminder Message")
23+
24+
def __str__(self) -> str:
25+
"""Reminder human readable representation."""
26+
return f"Reminder for {self.member} in channel: {self.channel_id}: {self.message}"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Nest Reminder Schedule model."""
2+
3+
from django.db import models
4+
5+
6+
class ReminderSchedule(models.Model):
7+
"""Model representing a reminder schedule."""
8+
9+
class Meta:
10+
db_table = "nest_reminder_schedules"
11+
verbose_name = "Nest Reminder Schedule"
12+
verbose_name_plural = "Nest Reminder Schedules"
13+
14+
class Recurrence(models.TextChoices):
15+
ONCE = "once", "Once"
16+
DAILY = "daily", "Daily"
17+
WEEKLY = "weekly", "Weekly"
18+
MONTHLY = "monthly", "Monthly"
19+
20+
reminder = models.ForeignKey(
21+
"nest.Reminder",
22+
verbose_name="Nest Reminder",
23+
on_delete=models.CASCADE,
24+
related_name="schedules",
25+
)
26+
scheduled_time = models.DateTimeField(verbose_name="Scheduled Time")
27+
recurrence = models.CharField(
28+
verbose_name="Recurrence",
29+
max_length=50,
30+
choices=Recurrence.choices,
31+
default=Recurrence.ONCE,
32+
)
33+
34+
def __str__(self) -> str:
35+
"""Reminder Schedule human readable representation."""
36+
return f"Schedule for {self.reminder} at {self.scheduled_time} ({self.recurrence})"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Generated by Django 5.2.4 on 2025-08-26 00:34
2+
3+
import django.db.models.deletion
4+
from django.db import migrations, models
5+
6+
7+
class Migration(migrations.Migration):
8+
dependencies = [
9+
("owasp", "0048_entitymember"),
10+
("slack", "0018_conversation_sync_messages"),
11+
]
12+
13+
operations = [
14+
migrations.AddField(
15+
model_name="event",
16+
name="calendar_id",
17+
field=models.CharField(
18+
blank=True, default="", max_length=1024, verbose_name="Calendar ID"
19+
),
20+
),
21+
migrations.AddField(
22+
model_name="event",
23+
name="channel_id",
24+
field=models.CharField(default="", max_length=15, verbose_name="Channel ID"),
25+
),
26+
migrations.AddField(
27+
model_name="event",
28+
name="member",
29+
field=models.ForeignKey(
30+
null=True,
31+
on_delete=django.db.models.deletion.CASCADE,
32+
related_name="calendar_events",
33+
to="slack.member",
34+
verbose_name="Slack Member",
35+
),
36+
),
37+
migrations.AddField(
38+
model_name="event",
39+
name="status",
40+
field=models.CharField(
41+
choices=[
42+
("confirmed", "Confirmed"),
43+
("tentative", "Tentative"),
44+
("canceled", "Canceled"),
45+
],
46+
default="confirmed",
47+
max_length=11,
48+
verbose_name="Status",
49+
),
50+
),
51+
migrations.AddField(
52+
model_name="event",
53+
name="type",
54+
field=models.CharField(
55+
choices=[("calendar", "Calendar"), ("existing", "Existing")],
56+
default="existing",
57+
max_length=11,
58+
verbose_name="Type",
59+
),
60+
),
61+
]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Generated by Django 5.2.4 on 2025-08-26 01:52
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("owasp", "0049_event_calendar_id_event_channel_id_event_member_and_more"),
9+
("slack", "0018_conversation_sync_messages"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="event",
15+
name="status",
16+
field=models.CharField(
17+
choices=[
18+
("confirmed", "Confirmed"),
19+
("tentative", "Tentative"),
20+
("cancelled", "Cancelled"),
21+
],
22+
default="confirmed",
23+
max_length=11,
24+
verbose_name="Status",
25+
),
26+
),
27+
migrations.AddIndex(
28+
model_name="event",
29+
index=models.Index(fields=["type"], name="event_type_idx"),
30+
),
31+
]
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Generated by Django 5.2.4 on 2025-08-28 16:19
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("owasp", "0050_alter_event_status_event_event_type_idx"),
9+
]
10+
11+
operations = [
12+
migrations.RemoveIndex(
13+
model_name="event",
14+
name="event_type_idx",
15+
),
16+
migrations.RemoveField(
17+
model_name="event",
18+
name="channel_id",
19+
),
20+
migrations.RemoveField(
21+
model_name="event",
22+
name="member",
23+
),
24+
migrations.RemoveField(
25+
model_name="event",
26+
name="type",
27+
),
28+
migrations.AlterField(
29+
model_name="event",
30+
name="category",
31+
field=models.CharField(
32+
choices=[
33+
("appsec_days", "AppSec Days"),
34+
("global", "Global"),
35+
("other", "Other"),
36+
("partner", "Partner"),
37+
("community", "Community"),
38+
],
39+
default="other",
40+
max_length=11,
41+
verbose_name="Category",
42+
),
43+
),
44+
migrations.AlterField(
45+
model_name="event",
46+
name="status",
47+
field=models.CharField(
48+
choices=[("confirmed", "Confirmed")],
49+
default="confirmed",
50+
max_length=11,
51+
verbose_name="Status",
52+
),
53+
),
54+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.2.4 on 2025-09-02 13:15
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("owasp", "0051_remove_event_event_type_idx_remove_event_channel_id_and_more"),
9+
]
10+
11+
operations = [
12+
migrations.RemoveField(
13+
model_name="event",
14+
name="calendar_id",
15+
),
16+
migrations.AddField(
17+
model_name="event",
18+
name="google_calendar_id",
19+
field=models.CharField(
20+
blank=True, default="", max_length=1024, verbose_name="Google Calendar ID"
21+
),
22+
),
23+
]

backend/apps/owasp/models/event.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,34 @@ class Category(models.TextChoices):
3939
GLOBAL = "global", "Global"
4040
OTHER = "other", "Other"
4141
PARTNER = "partner", "Partner"
42+
COMMUNITY = "community", "Community"
43+
44+
class Status(models.TextChoices):
45+
"""Event status."""
46+
47+
CONFIRMED = "confirmed", "Confirmed"
4248

4349
category = models.CharField(
4450
verbose_name="Category",
4551
max_length=11,
4652
choices=Category.choices,
4753
default=Category.OTHER,
4854
)
55+
# Google Calendar event entity ID
56+
google_calendar_id = models.CharField(
57+
verbose_name="Google Calendar ID", max_length=1024, blank=True, default=""
58+
)
4959
name = models.CharField(verbose_name="Name", max_length=100)
5060
start_date = models.DateField(verbose_name="Start Date")
5161
end_date = models.DateField(verbose_name="End Date", null=True, blank=True)
5262
description = models.TextField(verbose_name="Description", default="", blank=True)
5363
key = models.CharField(verbose_name="Key", max_length=100, unique=True)
64+
status = models.CharField(
65+
verbose_name="Status",
66+
max_length=11,
67+
choices=Status.choices,
68+
default=Status.CONFIRMED,
69+
)
5470
summary = models.TextField(verbose_name="Summary", blank=True, default="")
5571
suggested_location = models.CharField(
5672
verbose_name="Suggested Location", max_length=255, blank=True, default=""
@@ -77,6 +93,7 @@ def upcoming_events():
7793
)
7894
.exclude(
7995
Q(name__exact="") | Q(url__exact=""),
96+
category=Event.Category.COMMUNITY,
8097
)
8198
.order_by(
8299
"start_date",

0 commit comments

Comments
 (0)