Skip to content

Commit 48079c9

Browse files
authored
feat(massEmail): create new models for mass email TASK-751 (#5544)
### 📖 Description Developer-only changes ### 💭 Notes This is just meant as set up and will not add any functionality. Most of it comes from the default django app setup command. There will undoubtedly be changes as we go but at least now we have a consistent place to make those changes. No tests yet because there isn't any logic to test. Had to add a "noqa" annotation to the long line in the migration because the way the formatter wants to fix it actually changes the meaning slightly (has to do with messing around with quotes) and it causes django to want to make a new migration. ### Preview Feature/no-change template: 1. ℹ️ have a superuser account 2. Go to admin 4. 🟢 There should be a new Mass emails config object that you can add/edit 5. 🟢 When adding a config, there will be no available options for the query because none have been implemented yet
1 parent 69f5959 commit 48079c9

File tree

10 files changed

+238
-0
lines changed

10 files changed

+238
-0
lines changed

kobo/apps/mass_emails/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from django.apps import AppConfig
2+
3+
4+
class MassEmailsConfig(AppConfig):
5+
default_auto_field = 'django.db.models.BigAutoField'
6+
name = 'kobo.apps.mass_emails'
7+
verbose_name = 'Mass emails'
8+
9+
def ready(self):
10+
# Makes sure all signal handlers are connected
11+
from kobo.apps.mass_emails import signals # noqa
12+
13+
super().ready()

kobo/apps/mass_emails/admin.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from django.contrib import admin
2+
3+
from .models import MassEmailConfig
4+
5+
6+
@admin.register(MassEmailConfig)
7+
class MassEmailConfig(admin.ModelAdmin):
8+
9+
list_display = ('name', 'date_modified')
10+
fields = ('name', 'subject', 'template', 'query')

kobo/apps/mass_emails/apps.py

Whitespace-only changes.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# Generated by Django 4.2.15 on 2025-02-20 14:28
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
import kpi.fields.kpi_uid
8+
import kpi.models.abstract_models
9+
10+
11+
class Migration(migrations.Migration):
12+
13+
initial = True
14+
15+
dependencies = [
16+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17+
]
18+
19+
operations = [
20+
migrations.CreateModel(
21+
name='MassEmailConfig',
22+
fields=[
23+
(
24+
'id',
25+
models.BigAutoField(
26+
auto_created=True,
27+
primary_key=True,
28+
serialize=False,
29+
verbose_name='ID',
30+
),
31+
),
32+
(
33+
'date_created',
34+
models.DateTimeField(
35+
default=kpi.models.abstract_models._get_default_datetime
36+
),
37+
),
38+
(
39+
'date_modified',
40+
models.DateTimeField(
41+
default=kpi.models.abstract_models._get_default_datetime
42+
),
43+
),
44+
('uid', kpi.fields.kpi_uid.KpiUidField(_null=False, uid_prefix='mec')),
45+
('name', models.CharField()),
46+
('subject', models.CharField(blank=True, max_length=200, null=True)),
47+
(
48+
'template',
49+
models.TextField(
50+
blank=True,
51+
help_text="Available placeholders:<br />##username##<br />##full_name## - user's full name<br />##plan_name## - user's current subscription plan", # noqa
52+
null=True,
53+
),
54+
),
55+
(
56+
'query',
57+
models.CharField(blank=True, choices=[], max_length=100, null=True),
58+
),
59+
],
60+
options={
61+
'abstract': False,
62+
},
63+
),
64+
migrations.CreateModel(
65+
name='MassEmailJob',
66+
fields=[
67+
(
68+
'id',
69+
models.BigAutoField(
70+
auto_created=True,
71+
primary_key=True,
72+
serialize=False,
73+
verbose_name='ID',
74+
),
75+
),
76+
(
77+
'date_created',
78+
models.DateTimeField(
79+
default=kpi.models.abstract_models._get_default_datetime
80+
),
81+
),
82+
(
83+
'date_modified',
84+
models.DateTimeField(
85+
default=kpi.models.abstract_models._get_default_datetime
86+
),
87+
),
88+
('uid', kpi.fields.kpi_uid.KpiUidField(_null=False, uid_prefix='mej')),
89+
(
90+
'email_config',
91+
models.ForeignKey(
92+
on_delete=django.db.models.deletion.PROTECT,
93+
to='mass_emails.massemailconfig',
94+
),
95+
),
96+
],
97+
options={
98+
'abstract': False,
99+
},
100+
),
101+
migrations.CreateModel(
102+
name='MassEmailRecord',
103+
fields=[
104+
(
105+
'id',
106+
models.BigAutoField(
107+
auto_created=True,
108+
primary_key=True,
109+
serialize=False,
110+
verbose_name='ID',
111+
),
112+
),
113+
(
114+
'date_created',
115+
models.DateTimeField(
116+
default=kpi.models.abstract_models._get_default_datetime
117+
),
118+
),
119+
(
120+
'date_modified',
121+
models.DateTimeField(
122+
default=kpi.models.abstract_models._get_default_datetime
123+
),
124+
),
125+
(
126+
'status',
127+
models.CharField(
128+
blank=True,
129+
choices=[
130+
('enqueued', 'Enqueued'),
131+
('failed', 'Failed'),
132+
('sent', 'Sent'),
133+
],
134+
null=True,
135+
),
136+
),
137+
('uid', kpi.fields.kpi_uid.KpiUidField(_null=False, uid_prefix='mer')),
138+
(
139+
'email_job',
140+
models.ForeignKey(
141+
on_delete=django.db.models.deletion.PROTECT,
142+
to='mass_emails.massemailjob',
143+
),
144+
),
145+
(
146+
'user',
147+
models.ForeignKey(
148+
null=True,
149+
on_delete=django.db.models.deletion.SET_NULL,
150+
to=settings.AUTH_USER_MODEL,
151+
),
152+
),
153+
],
154+
options={
155+
'abstract': False,
156+
},
157+
),
158+
]

kobo/apps/mass_emails/migrations/__init__.py

Whitespace-only changes.

kobo/apps/mass_emails/models.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from collections.abc import Callable
2+
3+
from django.db import models
4+
5+
from kobo.apps.kobo_auth.shortcuts import User
6+
from kpi.fields import KpiUidField
7+
from kpi.models.abstract_models import AbstractTimeStampedModel
8+
9+
USER_QUERIES: dict[str, Callable] = {}
10+
USER_QUERY_CHOICES = {name: name.lower() for name in USER_QUERIES.keys()}
11+
12+
13+
class EmailStatus(models.TextChoices):
14+
ENQUEUED = 'enqueued'
15+
FAILED = 'failed'
16+
SENT = 'sent'
17+
18+
19+
class MassEmailConfig(AbstractTimeStampedModel):
20+
uid = KpiUidField(uid_prefix='mec')
21+
name = models.CharField()
22+
subject = models.CharField(null=True, blank=True, max_length=200)
23+
template = models.TextField(
24+
null=True,
25+
blank=True,
26+
help_text='Available placeholders:<br />'
27+
'##username##<br />'
28+
"##full_name## - user\'s full name<br />"
29+
"##plan_name## - user\'s current subscription plan",
30+
)
31+
query = models.CharField(
32+
null=True, blank=True, max_length=100, choices=USER_QUERY_CHOICES
33+
)
34+
35+
def __str__(self):
36+
return self.name
37+
38+
39+
class MassEmailJob(AbstractTimeStampedModel):
40+
email_config = models.ForeignKey(MassEmailConfig, on_delete=models.PROTECT)
41+
uid = KpiUidField(uid_prefix='mej')
42+
43+
def __str__(self):
44+
return f'{self.email_config} started at {self.date_created.isoformat()}'
45+
46+
47+
class MassEmailRecord(AbstractTimeStampedModel):
48+
user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
49+
email_job = models.ForeignKey(MassEmailJob, on_delete=models.PROTECT)
50+
status = models.CharField(choices=EmailStatus.choices, null=True, blank=True)
51+
uid = KpiUidField(uid_prefix='mer')
52+
53+
def __str__(self):
54+
return f'{self.email_job.email_config} send to {self.user.username}'

kobo/apps/mass_emails/signals.py

Whitespace-only changes.

kobo/apps/mass_emails/tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Create your tests here.

kobo/apps/mass_emails/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Create your views here.

kobo/settings/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
'kobo.apps.languages.LanguageAppConfig',
134134
'kobo.apps.project_views.ProjectViewAppConfig',
135135
'kobo.apps.audit_log.AuditLogAppConfig',
136+
'kobo.apps.mass_emails.MassEmailsConfig',
136137
'kobo.apps.trackers.TrackersConfig',
137138
'kobo.apps.trash_bin.TrashBinAppConfig',
138139
'kobo.apps.markdownx_uploader.MarkdownxUploaderAppConfig',

0 commit comments

Comments
 (0)