• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kobotoolbox / kpi / 35242188777
83%
master: 76%

Build:
Build:
LAST BUILD BRANCH: main
DEFAULT BRANCH: master
Ran 17 Sep 2026 03:48PM UTC
Jobs 10
Files 907
Run time 3min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

17 Sep 2026 03:44PM UTC coverage: 82.841% (+0.004%) from 82.837%
35242188777

push

github

web-flow
fix(massemails): fix edge cases for one-off mass email campaigns DEV-2737 (#7555)

### đŸ“Ŗ Summary
Fixes edge cases where one-off mass email campaigns (`frequency = -1`)
could be accidentally resent if remaining enqueued records transitioned
to STALE or if the Celery worker process terminated before the campaign
was finalized

### 📖 Description
* `get_users_for_config()` now excludes users who already have a
terminal status (SENT, FAILED, STALE) under that one-off config
* Any one-off campaign that has already run and has 0 enqueued records
is disabled immediately, even if all remaining records went STALE.
`send_emails()` now filters on `jobs__isnull=False` instead of
`pk__in=sender.config_ids`.
* If an unclosed one-off config has records and no eligible recipients
remaining, `generate_mass_email_user_lists()` marks `live = False`
directly without creating an empty `MassEmailJob` re-enqueueing records
* Included new unit tests to validate that the edge cases are handled
correctly

### 👀 Preview steps
1. â„šī¸ have two user accounts (one of them should be inactive)
2. Create a mass email config with `frequency = -1`, `query =
'test_users'` and `live = True`
```
from django.core.cache import cache
from kobo.apps.mass_emails.tasks import generate_mass_email_user_lists, send_emails
from datetime import timedelta
from django.utils import timezone

cache.clear()

# First call to send_emails to 
send_emails()

config = MassEmailConfig.objects.get(id=<id>)
# It has to be 1 day old to be processed
config.date_created = timezone.now() - timedelta(days=1)
config.save()

generate_mass_email_user_lists()

# đŸŸĸ [on PR] Config is turned off immediately
# The inactive account should have status = STALE
assert not config.live
assert MassEmailRecord.objects.get(user__username='<inactive username>').status == EmailStatus.STALE


send_emails()
```
3. Wait for the next 15-minute window and clear cache to simulate next
run and verify that no new records are created:
```
# Make c... (continued)

10185 of 13517 branches covered (75.35%)

0 of 23 new or added lines in 1 file covered. (0.0%)

2180 existing lines in 87 files now uncovered.

32587 of 39337 relevant lines covered (82.84%)

5.51 hits per line

Uncovered Changes

Lines Coverage ∆ File
23
0.0
0.0% kobo/apps/mass_emails/tasks.py

Coverage Regressions

Lines Coverage ∆ File
336
25.32
-47.26% kpi/models/import_export_task.py
178
61.33
-30.32% kpi/models/asset.py
97
30.58
-47.09% kobo/apps/project_ownership/models/transfer.py
81
0.0
-93.1% kobo/apps/stripe/serializers.py
80
71.12
-21.8% kpi/mixins/object_permission.py
75
0.0
-41.9% kobo/apps/stripe/views.py
68
20.57
-48.23% kobo/apps/stripe/utils/subscription_limits.py
67
31.76
-45.27% kobo/apps/accounts/forms.py
67
25.35
-31.46% kpi/filters.py
64
12.36
-71.91% kobo/apps/reports/report_data.py
63
0.0
-51.64% kobo/apps/stripe/models.py
54
35.34
-40.6% kpi/paginators.py
53
38.56
-8.66% kpi/deployment_backends/openrosa_backend.py
51
54.55
-12.53% kpi/deployment_backends/base_backend.py
44
0.0
-67.69% kobo/apps/accounts/adapter.py
44
37.61
-37.61% kpi/models/asset_snapshot.py
41
46.29
-9.21% kobo/apps/audit_log/models.py
39
35.2
-31.2% kpi/models/paired_data.py
38
34.52
-45.24% kobo/apps/audit_log/base_views.py
36
20.2
-36.36% kobo/apps/stripe/utils/billing_dates.py
32
53.57
-16.33% kpi/mixins/formpack_xlsform_utils.py
32
53.92
-31.37% kpi/models/asset_file.py
27
15.52
-15.52% kobo/apps/project_ownership/utils.py
27
33.96
-50.94% kpi/fields/file.py
24
40.0
-53.33% kpi/fields/jsonschema_form_field.py
20
53.13
-31.25% hub/models/extra_user_detail.py
20
0.0
-68.97% kobo/apps/audit_log/tasks.py
19
0.0
-65.52% kobo/apps/stripe/admin.py
17
39.73
-7.76% kobo/apps/organizations/views.py
17
77.53
-19.1% kpi/deployment_backends/mock_backend.py
16
60.0
-11.43% kobo/apps/audit_log/signals.py
16
87.05
-2.41% kobo/apps/openrosa/libs/utils/logger_tools.py
16
31.82
-36.36% kobo/apps/stripe/utils/limit_enforcement.py
15
0.0
-20.55% kobo/apps/stripe/signals.py
14
37.14
-20.0% hub/utils/i18n.py
13
26.09
-56.52% kpi/fields/relative_prefix_hyperlinked_related.py
12
43.06
-16.67% kobo/apps/project_ownership/serializers/invite.py
12
35.0
-60.0% kobo/apps/stripe/utils/import_management.py
11
59.76
-13.41% kobo/apps/project_ownership/models/invite.py
11
67.86
-19.64% kpi/context_processors.py
11
69.44
-30.56% kpi/models/asset_user_partial_permission.py
10
59.42
-14.49% kobo/apps/accounts/models.py
10
60.71
-35.71% kobo/apps/audit_log/utils.py
10
14.8
-5.1% kobo/apps/subsequences/utils/versioning.py
9
56.22
-4.86% kobo/apps/organizations/models.py
9
0.0
-29.03% kobo/apps/stripe/utils/manual_subscription.py
8
0.0
-100.0% kobo/apps/stripe/urls.py
7
50.0
-18.42% kobo/apps/organizations/utils.py
7
61.76
-20.59% kobo/apps/storage_backends/base.py
7
0.0
-100.0% kobo/apps/stripe/apps.py
7
32.14
-25.0% kobo/apps/subsequences/utils/supplement_data.py
7
57.14
-33.33% kpi/fields/paginated_api.py
7
53.33
-46.67% kpi/maintenance_tasks.py
7
70.37
-25.93% kpi/models/extra_project_metadata_field.py
6
30.38
-7.59% kobo/apps/accounts/utils.py
6
43.75
-37.5% kobo/apps/project_ownership/filters.py
6
72.09
-13.95% kobo/apps/project_ownership/serializers/transfer.py
6
0.0
-100.0% kobo/apps/project_views/tasks.py
6
0.0
-100.0% kobo/apps/stripe/exceptions.py
6
0.0
-37.5% kobo/apps/stripe/utils/view_utils.py
6
42.86
-42.86% kpi/mixins/asset.py
5
30.0
-7.14% kobo/apps/organizations/permissions.py
5
46.34
-12.2% kobo/apps/organizations/tasks.py
5
53.85
-6.41% kpi/deployment_backends/kc_access/utils.py
5
57.14
-23.81% kpi/fields/writable_json.py
5
83.33
-10.42% kpi/models/asset_version.py
5
75.0
-20.83% kpi/models/authorized_application.py
4
53.85
-30.77% kobo/apps/accounts/templatetags/customize_email_content.py
4
77.5
-10.0% kobo/apps/kobo_auth/signals.py
4
0.0
0.0% kobo/apps/mass_emails/tasks.py
4
89.47
-7.02% kpi/deployment_backends/mixin.py
3
65.79
-7.89% kobo/apps/data_collectors/signals.py
3
31.43
-2.86% kobo/apps/organizations/admin/organization.py
3
89.19
-8.11% kobo/apps/project_views/models/project_view.py
2
46.27
-2.99% kobo/apps/accounts/signals.py
2
70.83
-1.67% kobo/apps/openrosa/libs/utils/middleware.py
2
91.3
-8.7% kobo/apps/project_ownership/views/invite.py
2
83.33
-6.67% kobo/urls.py
2
87.2
-1.6% kpi/exceptions.py
2
64.52
-6.45% kpi/mixins/standardize_searchable_field.py
2
96.36
-3.64% kpi/mixins/xls_exportable.py
1
44.44
-5.56% kobo/apps/accounts/templatetags/get_provider_appname.py
1
86.11
-2.78% kobo/apps/openrosa/apps/logger/fields.py
1
76.27
-1.69% kobo/apps/user_reports/utils/migrations.py
1
67.95
-1.28% kpi/authentication.py
1
57.89
-2.63% kpi/db_routers.py
1
70.83
-4.17% kpi/urls/__init__.py
Jobs
ID Job ID Ran Files Coverage
1 35242188777.1 17 Sep 2026 03:48PM UTC 902
43.87
2 35242188777.2 17 Sep 2026 03:49PM UTC 902
49.5
3 35242188777.3 17 Sep 2026 03:50PM UTC 902
52.73
4 35242188777.4 17 Sep 2026 03:50PM UTC 904
45.16
5 35242188777.5 17 Sep 2026 03:51PM UTC 904
50.76
6 35242188777.6 17 Sep 2026 03:52PM UTC 904
53.99
7 35242188777.7 17 Sep 2026 03:52PM UTC 905
67.92
8 35242188777.8 17 Sep 2026 03:53PM UTC 902
58.67
9 35242188777.9 17 Sep 2026 03:54PM UTC 904
59.76
10 35242188777.10 17 Sep 2026 03:56PM UTC 907
70.23
Source Files on build 35242188777
  • Tree
  • List 907
  • Changed 2
  • Source Changed 0
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • 0ad8f4ed on github
  • Prev Build on release/2.026.37 (#35085485875)
  • Next Build on release/2.026.37 (#35346079805)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc