BmorricalDjangoWorkflows 2.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bmorricaldjangoworkflows-2.0.2/BmorricalDjangoWorkflows.egg-info/PKG-INFO +268 -0
- bmorricaldjangoworkflows-2.0.2/BmorricalDjangoWorkflows.egg-info/SOURCES.txt +19 -0
- bmorricaldjangoworkflows-2.0.2/BmorricalDjangoWorkflows.egg-info/dependency_links.txt +1 -0
- bmorricaldjangoworkflows-2.0.2/BmorricalDjangoWorkflows.egg-info/requires.txt +3 -0
- bmorricaldjangoworkflows-2.0.2/BmorricalDjangoWorkflows.egg-info/top_level.txt +2 -0
- bmorricaldjangoworkflows-2.0.2/LICENSE +3 -0
- bmorricaldjangoworkflows-2.0.2/MANIFEST.in +3 -0
- bmorricaldjangoworkflows-2.0.2/PKG-INFO +268 -0
- bmorricaldjangoworkflows-2.0.2/README.md +244 -0
- bmorricaldjangoworkflows-2.0.2/VERSION +1 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/__init__.py +1 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/services/__init__.py +5 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/services/mailgun.py +254 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/users/__init__.py +1 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/users/services/__init__.py +1 -0
- bmorricaldjangoworkflows-2.0.2/django_workflows/users/services/auth_flow.py +463 -0
- bmorricaldjangoworkflows-2.0.2/setup.cfg +4 -0
- bmorricaldjangoworkflows-2.0.2/setup.py +27 -0
- bmorricaldjangoworkflows-2.0.2/tests/__init__.py +0 -0
- bmorricaldjangoworkflows-2.0.2/tests/test_auth_flow.py +537 -0
- bmorricaldjangoworkflows-2.0.2/tests/test_mailgun.py +270 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: BmorricalDjangoWorkflows
|
|
3
|
+
Version: 2.0.2
|
|
4
|
+
Summary: Reusable Django Workflows
|
|
5
|
+
Home-page: https://github.com/Bmorrical/django-workflows
|
|
6
|
+
Author: Bradley Morrical
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Framework :: Django
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: Django>=4.0
|
|
13
|
+
Requires-Dist: djangorestframework>=3.14
|
|
14
|
+
Requires-Dist: requests>=2.31.0
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# django-workflows
|
|
26
|
+
|
|
27
|
+
Reusable Django service helpers for common account flows:
|
|
28
|
+
|
|
29
|
+
- Registration and verification-code email flow
|
|
30
|
+
- Forgot-password code flow
|
|
31
|
+
- Reset-code validation and lockout handling
|
|
32
|
+
- Mailgun email utility with recipient validation
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Install from PyPI:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install BmorricalDjangoWorkflows==1.2.3
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
In `requirements.txt`, pin it directly:
|
|
43
|
+
|
|
44
|
+
```txt
|
|
45
|
+
BmorricalDjangoWorkflows==1.2.3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Note: distribution name is `BmorricalDjangoWorkflows`, while imports remain under `django_workflows`.
|
|
49
|
+
|
|
50
|
+
## Host Project Requirements
|
|
51
|
+
|
|
52
|
+
This package expects the host Django project to provide:
|
|
53
|
+
|
|
54
|
+
- A Django user model available through `django.contrib.auth.get_user_model()`
|
|
55
|
+
- A user meta model referenced by `WORKFLOWS["USER_META_MODEL"]`
|
|
56
|
+
- A user manager `create_user(...)` method that accepts `username`, because this package explicitly sets `username=email`
|
|
57
|
+
|
|
58
|
+
The user meta model should include at least:
|
|
59
|
+
|
|
60
|
+
- `user` relation
|
|
61
|
+
- `verify_code` field
|
|
62
|
+
- `verify_time` field
|
|
63
|
+
- `attempts` field
|
|
64
|
+
|
|
65
|
+
Optional (used if present):
|
|
66
|
+
|
|
67
|
+
- `force_password_reset`
|
|
68
|
+
|
|
69
|
+
## Django Settings
|
|
70
|
+
|
|
71
|
+
Add a `WORKFLOWS` dict in your Django settings.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
WORKFLOWS = {
|
|
75
|
+
# Required in most projects unless your model path matches the default.
|
|
76
|
+
"USER_META_MODEL": "users.models_user_meta.UserMeta",
|
|
77
|
+
|
|
78
|
+
# Optional settings with defaults shown.
|
|
79
|
+
"COMPANY_NAME": "My Company",
|
|
80
|
+
"ENABLE_MAILGUN": False,
|
|
81
|
+
"RESET_CODE_TTL_MINUTES": 10,
|
|
82
|
+
"MAX_VERIFY_ATTEMPTS": 3,
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Notes:
|
|
87
|
+
|
|
88
|
+
- `USER_META_MODEL` must be a dotted import path such as `myapp.models.UserMeta`.
|
|
89
|
+
- If `ENABLE_MAILGUN` is true, configure the Mailgun environment variables used by the mail service.
|
|
90
|
+
|
|
91
|
+
## Mailgun Environment Variables
|
|
92
|
+
|
|
93
|
+
When mail sending is enabled, set:
|
|
94
|
+
|
|
95
|
+
- `MAILGUN_COMPANY_NAME`
|
|
96
|
+
- `MAILGUN_API_KEY`
|
|
97
|
+
- `MAILGUN_DOMAIN`
|
|
98
|
+
- `ENABLE_MAILGUN=true`
|
|
99
|
+
|
|
100
|
+
Optional:
|
|
101
|
+
|
|
102
|
+
- `MAILGUN_BCC_RECIPIENTS` as a comma-separated list
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
MAILGUN_BCC_RECIPIENTS="audit@example.com,ops@example.com"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If `MAILGUN_BCC_RECIPIENTS` is not set, no static BCC recipients are added.
|
|
111
|
+
|
|
112
|
+
## Example Usage
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from django_workflows.users.services.auth_flow import (
|
|
116
|
+
register_user_and_send_verification_email,
|
|
117
|
+
send_forgot_password_code,
|
|
118
|
+
verify_reset_code,
|
|
119
|
+
change_password,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
result = register_user_and_send_verification_email(
|
|
123
|
+
email="person@example.com",
|
|
124
|
+
first_name="First",
|
|
125
|
+
last_name="Last",
|
|
126
|
+
password="example-password",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
forgot = send_forgot_password_code("person@example.com")
|
|
130
|
+
|
|
131
|
+
verify = verify_reset_code(email="person@example.com", code="AB12CD")
|
|
132
|
+
|
|
133
|
+
changed = change_password(
|
|
134
|
+
email="person@example.com",
|
|
135
|
+
password="new-password",
|
|
136
|
+
password_verify="new-password",
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Direct Mailgun Usage
|
|
141
|
+
|
|
142
|
+
Attachment tuple shape:
|
|
143
|
+
|
|
144
|
+
- `(filename, file_bytes_or_file_object, mimetype)`
|
|
145
|
+
|
|
146
|
+
Example attachment entry:
|
|
147
|
+
|
|
148
|
+
- `("report.pdf", pdf_bytes, "application/pdf")`
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from django_workflows.services.mailgun import send_mailgun_email
|
|
152
|
+
|
|
153
|
+
response = send_mailgun_email(
|
|
154
|
+
to=["primary@example.com", "secondary@example.com"],
|
|
155
|
+
subject="Welcome",
|
|
156
|
+
html="<p>Thanks for joining.</p>",
|
|
157
|
+
cc="manager@example.com",
|
|
158
|
+
bcc=["audit@example.com"],
|
|
159
|
+
attachments=[("report.pdf", pdf_bytes, "application/pdf")],
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Optional: explicit runtime override for enablement
|
|
163
|
+
send_mailgun_email(
|
|
164
|
+
to="user@example.com",
|
|
165
|
+
subject="Dry run",
|
|
166
|
+
html="<p>This will not send.</p>",
|
|
167
|
+
enabled=False,
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Local Development
|
|
172
|
+
|
|
173
|
+
Run tests:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
make test
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Run tests with coverage:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
make test-coverage
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
CI runs tests on push and pull requests using [`.github/workflows/tests.yml`](.github/workflows/tests.yml).
|
|
186
|
+
|
|
187
|
+
## Troubleshooting
|
|
188
|
+
|
|
189
|
+
### ImproperlyConfigured for USER_META_MODEL
|
|
190
|
+
|
|
191
|
+
Error example:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
WORKFLOWS['USER_META_MODEL'] must be a dotted path like 'myapp.models.UserMeta'.
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Fix:
|
|
198
|
+
|
|
199
|
+
- Set `WORKFLOWS["USER_META_MODEL"]` to a valid dotted import path.
|
|
200
|
+
- Verify the target model is importable by Django at runtime.
|
|
201
|
+
|
|
202
|
+
### UserMeta field errors
|
|
203
|
+
|
|
204
|
+
If you see attribute errors around verification state, confirm your user meta model provides:
|
|
205
|
+
|
|
206
|
+
- `verify_code`
|
|
207
|
+
- `verify_time`
|
|
208
|
+
- `attempts`
|
|
209
|
+
|
|
210
|
+
### Mailgun not sending
|
|
211
|
+
|
|
212
|
+
Check:
|
|
213
|
+
|
|
214
|
+
- `ENABLE_MAILGUN=true`
|
|
215
|
+
- `MAILGUN_API_KEY`
|
|
216
|
+
- `MAILGUN_DOMAIN`
|
|
217
|
+
- `MAILGUN_COMPANY_NAME`
|
|
218
|
+
|
|
219
|
+
### No static BCC recipients applied
|
|
220
|
+
|
|
221
|
+
This is expected unless you set `MAILGUN_BCC_RECIPIENTS`.
|
|
222
|
+
|
|
223
|
+
## Release
|
|
224
|
+
|
|
225
|
+
Create a release tag:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
./release.sh 0.1.0
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
After release, update the package version in your consuming application's dependency files.
|
|
232
|
+
|
|
233
|
+
Tag pushes like `v1.2.3` trigger [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which publishes to PyPI.
|
|
234
|
+
|
|
235
|
+
## Publishing To PyPI (Maintainer Steps)
|
|
236
|
+
|
|
237
|
+
1. Check whether the target package name is available.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
curl -I https://pypi.org/pypi/BmorricalDjangoWorkflows/json
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
If this returns 404, the name is usually available.
|
|
244
|
+
|
|
245
|
+
2. Create a PyPI account: https://pypi.org/account/register/
|
|
246
|
+
|
|
247
|
+
3. Create a PyPI API token: PyPI Account -> Account settings -> API tokens.
|
|
248
|
+
|
|
249
|
+
4. Add repository secret in GitHub:
|
|
250
|
+
|
|
251
|
+
- Name: `PYPI_API_TOKEN`
|
|
252
|
+
- Value: your PyPI token (starts with `pypi-`)
|
|
253
|
+
|
|
254
|
+
5. Bump and tag a release:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
./release.sh 1.2.3
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
6. Confirm the workflow run succeeded and the package appears on PyPI.
|
|
261
|
+
|
|
262
|
+
7. Update consuming applications:
|
|
263
|
+
|
|
264
|
+
```txt
|
|
265
|
+
BmorricalDjangoWorkflows==1.2.3
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
If upload fails because the name is already taken, change `name=` in [setup.py](setup.py), bump version, and release again.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
VERSION
|
|
5
|
+
setup.py
|
|
6
|
+
BmorricalDjangoWorkflows.egg-info/PKG-INFO
|
|
7
|
+
BmorricalDjangoWorkflows.egg-info/SOURCES.txt
|
|
8
|
+
BmorricalDjangoWorkflows.egg-info/dependency_links.txt
|
|
9
|
+
BmorricalDjangoWorkflows.egg-info/requires.txt
|
|
10
|
+
BmorricalDjangoWorkflows.egg-info/top_level.txt
|
|
11
|
+
django_workflows/__init__.py
|
|
12
|
+
django_workflows/services/__init__.py
|
|
13
|
+
django_workflows/services/mailgun.py
|
|
14
|
+
django_workflows/users/__init__.py
|
|
15
|
+
django_workflows/users/services/__init__.py
|
|
16
|
+
django_workflows/users/services/auth_flow.py
|
|
17
|
+
tests/__init__.py
|
|
18
|
+
tests/test_auth_flow.py
|
|
19
|
+
tests/test_mailgun.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: BmorricalDjangoWorkflows
|
|
3
|
+
Version: 2.0.2
|
|
4
|
+
Summary: Reusable Django Workflows
|
|
5
|
+
Home-page: https://github.com/Bmorrical/django-workflows
|
|
6
|
+
Author: Bradley Morrical
|
|
7
|
+
Classifier: Programming Language :: Python :: 3
|
|
8
|
+
Classifier: Framework :: Django
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: Django>=4.0
|
|
13
|
+
Requires-Dist: djangorestframework>=3.14
|
|
14
|
+
Requires-Dist: requests>=2.31.0
|
|
15
|
+
Dynamic: author
|
|
16
|
+
Dynamic: classifier
|
|
17
|
+
Dynamic: description
|
|
18
|
+
Dynamic: description-content-type
|
|
19
|
+
Dynamic: home-page
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
Dynamic: requires-dist
|
|
22
|
+
Dynamic: requires-python
|
|
23
|
+
Dynamic: summary
|
|
24
|
+
|
|
25
|
+
# django-workflows
|
|
26
|
+
|
|
27
|
+
Reusable Django service helpers for common account flows:
|
|
28
|
+
|
|
29
|
+
- Registration and verification-code email flow
|
|
30
|
+
- Forgot-password code flow
|
|
31
|
+
- Reset-code validation and lockout handling
|
|
32
|
+
- Mailgun email utility with recipient validation
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
Install from PyPI:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pip install BmorricalDjangoWorkflows==1.2.3
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
In `requirements.txt`, pin it directly:
|
|
43
|
+
|
|
44
|
+
```txt
|
|
45
|
+
BmorricalDjangoWorkflows==1.2.3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Note: distribution name is `BmorricalDjangoWorkflows`, while imports remain under `django_workflows`.
|
|
49
|
+
|
|
50
|
+
## Host Project Requirements
|
|
51
|
+
|
|
52
|
+
This package expects the host Django project to provide:
|
|
53
|
+
|
|
54
|
+
- A Django user model available through `django.contrib.auth.get_user_model()`
|
|
55
|
+
- A user meta model referenced by `WORKFLOWS["USER_META_MODEL"]`
|
|
56
|
+
- A user manager `create_user(...)` method that accepts `username`, because this package explicitly sets `username=email`
|
|
57
|
+
|
|
58
|
+
The user meta model should include at least:
|
|
59
|
+
|
|
60
|
+
- `user` relation
|
|
61
|
+
- `verify_code` field
|
|
62
|
+
- `verify_time` field
|
|
63
|
+
- `attempts` field
|
|
64
|
+
|
|
65
|
+
Optional (used if present):
|
|
66
|
+
|
|
67
|
+
- `force_password_reset`
|
|
68
|
+
|
|
69
|
+
## Django Settings
|
|
70
|
+
|
|
71
|
+
Add a `WORKFLOWS` dict in your Django settings.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
WORKFLOWS = {
|
|
75
|
+
# Required in most projects unless your model path matches the default.
|
|
76
|
+
"USER_META_MODEL": "users.models_user_meta.UserMeta",
|
|
77
|
+
|
|
78
|
+
# Optional settings with defaults shown.
|
|
79
|
+
"COMPANY_NAME": "My Company",
|
|
80
|
+
"ENABLE_MAILGUN": False,
|
|
81
|
+
"RESET_CODE_TTL_MINUTES": 10,
|
|
82
|
+
"MAX_VERIFY_ATTEMPTS": 3,
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Notes:
|
|
87
|
+
|
|
88
|
+
- `USER_META_MODEL` must be a dotted import path such as `myapp.models.UserMeta`.
|
|
89
|
+
- If `ENABLE_MAILGUN` is true, configure the Mailgun environment variables used by the mail service.
|
|
90
|
+
|
|
91
|
+
## Mailgun Environment Variables
|
|
92
|
+
|
|
93
|
+
When mail sending is enabled, set:
|
|
94
|
+
|
|
95
|
+
- `MAILGUN_COMPANY_NAME`
|
|
96
|
+
- `MAILGUN_API_KEY`
|
|
97
|
+
- `MAILGUN_DOMAIN`
|
|
98
|
+
- `ENABLE_MAILGUN=true`
|
|
99
|
+
|
|
100
|
+
Optional:
|
|
101
|
+
|
|
102
|
+
- `MAILGUN_BCC_RECIPIENTS` as a comma-separated list
|
|
103
|
+
|
|
104
|
+
Example:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
MAILGUN_BCC_RECIPIENTS="audit@example.com,ops@example.com"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
If `MAILGUN_BCC_RECIPIENTS` is not set, no static BCC recipients are added.
|
|
111
|
+
|
|
112
|
+
## Example Usage
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from django_workflows.users.services.auth_flow import (
|
|
116
|
+
register_user_and_send_verification_email,
|
|
117
|
+
send_forgot_password_code,
|
|
118
|
+
verify_reset_code,
|
|
119
|
+
change_password,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
result = register_user_and_send_verification_email(
|
|
123
|
+
email="person@example.com",
|
|
124
|
+
first_name="First",
|
|
125
|
+
last_name="Last",
|
|
126
|
+
password="example-password",
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
forgot = send_forgot_password_code("person@example.com")
|
|
130
|
+
|
|
131
|
+
verify = verify_reset_code(email="person@example.com", code="AB12CD")
|
|
132
|
+
|
|
133
|
+
changed = change_password(
|
|
134
|
+
email="person@example.com",
|
|
135
|
+
password="new-password",
|
|
136
|
+
password_verify="new-password",
|
|
137
|
+
)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Direct Mailgun Usage
|
|
141
|
+
|
|
142
|
+
Attachment tuple shape:
|
|
143
|
+
|
|
144
|
+
- `(filename, file_bytes_or_file_object, mimetype)`
|
|
145
|
+
|
|
146
|
+
Example attachment entry:
|
|
147
|
+
|
|
148
|
+
- `("report.pdf", pdf_bytes, "application/pdf")`
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from django_workflows.services.mailgun import send_mailgun_email
|
|
152
|
+
|
|
153
|
+
response = send_mailgun_email(
|
|
154
|
+
to=["primary@example.com", "secondary@example.com"],
|
|
155
|
+
subject="Welcome",
|
|
156
|
+
html="<p>Thanks for joining.</p>",
|
|
157
|
+
cc="manager@example.com",
|
|
158
|
+
bcc=["audit@example.com"],
|
|
159
|
+
attachments=[("report.pdf", pdf_bytes, "application/pdf")],
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
# Optional: explicit runtime override for enablement
|
|
163
|
+
send_mailgun_email(
|
|
164
|
+
to="user@example.com",
|
|
165
|
+
subject="Dry run",
|
|
166
|
+
html="<p>This will not send.</p>",
|
|
167
|
+
enabled=False,
|
|
168
|
+
)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Local Development
|
|
172
|
+
|
|
173
|
+
Run tests:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
make test
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Run tests with coverage:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
make test-coverage
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
CI runs tests on push and pull requests using [`.github/workflows/tests.yml`](.github/workflows/tests.yml).
|
|
186
|
+
|
|
187
|
+
## Troubleshooting
|
|
188
|
+
|
|
189
|
+
### ImproperlyConfigured for USER_META_MODEL
|
|
190
|
+
|
|
191
|
+
Error example:
|
|
192
|
+
|
|
193
|
+
```text
|
|
194
|
+
WORKFLOWS['USER_META_MODEL'] must be a dotted path like 'myapp.models.UserMeta'.
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Fix:
|
|
198
|
+
|
|
199
|
+
- Set `WORKFLOWS["USER_META_MODEL"]` to a valid dotted import path.
|
|
200
|
+
- Verify the target model is importable by Django at runtime.
|
|
201
|
+
|
|
202
|
+
### UserMeta field errors
|
|
203
|
+
|
|
204
|
+
If you see attribute errors around verification state, confirm your user meta model provides:
|
|
205
|
+
|
|
206
|
+
- `verify_code`
|
|
207
|
+
- `verify_time`
|
|
208
|
+
- `attempts`
|
|
209
|
+
|
|
210
|
+
### Mailgun not sending
|
|
211
|
+
|
|
212
|
+
Check:
|
|
213
|
+
|
|
214
|
+
- `ENABLE_MAILGUN=true`
|
|
215
|
+
- `MAILGUN_API_KEY`
|
|
216
|
+
- `MAILGUN_DOMAIN`
|
|
217
|
+
- `MAILGUN_COMPANY_NAME`
|
|
218
|
+
|
|
219
|
+
### No static BCC recipients applied
|
|
220
|
+
|
|
221
|
+
This is expected unless you set `MAILGUN_BCC_RECIPIENTS`.
|
|
222
|
+
|
|
223
|
+
## Release
|
|
224
|
+
|
|
225
|
+
Create a release tag:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
./release.sh 0.1.0
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
After release, update the package version in your consuming application's dependency files.
|
|
232
|
+
|
|
233
|
+
Tag pushes like `v1.2.3` trigger [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which publishes to PyPI.
|
|
234
|
+
|
|
235
|
+
## Publishing To PyPI (Maintainer Steps)
|
|
236
|
+
|
|
237
|
+
1. Check whether the target package name is available.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
curl -I https://pypi.org/pypi/BmorricalDjangoWorkflows/json
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
If this returns 404, the name is usually available.
|
|
244
|
+
|
|
245
|
+
2. Create a PyPI account: https://pypi.org/account/register/
|
|
246
|
+
|
|
247
|
+
3. Create a PyPI API token: PyPI Account -> Account settings -> API tokens.
|
|
248
|
+
|
|
249
|
+
4. Add repository secret in GitHub:
|
|
250
|
+
|
|
251
|
+
- Name: `PYPI_API_TOKEN`
|
|
252
|
+
- Value: your PyPI token (starts with `pypi-`)
|
|
253
|
+
|
|
254
|
+
5. Bump and tag a release:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
./release.sh 1.2.3
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
6. Confirm the workflow run succeeded and the package appears on PyPI.
|
|
261
|
+
|
|
262
|
+
7. Update consuming applications:
|
|
263
|
+
|
|
264
|
+
```txt
|
|
265
|
+
BmorricalDjangoWorkflows==1.2.3
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
If upload fails because the name is already taken, change `name=` in [setup.py](setup.py), bump version, and release again.
|