BmorricalDjangoWorkflows 2.1.3__tar.gz → 2.1.4__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.1.3 → bmorricaldjangoworkflows-2.1.4}/BmorricalDjangoWorkflows.egg-info/PKG-INFO +15 -1
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/PKG-INFO +15 -1
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/README.md +14 -0
- bmorricaldjangoworkflows-2.1.4/VERSION +1 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/services/auth_flow.py +33 -5
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/tests/test_auth_flow.py +32 -1
- bmorricaldjangoworkflows-2.1.3/VERSION +0 -1
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/BmorricalDjangoWorkflows.egg-info/SOURCES.txt +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/BmorricalDjangoWorkflows.egg-info/dependency_links.txt +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/BmorricalDjangoWorkflows.egg-info/requires.txt +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/BmorricalDjangoWorkflows.egg-info/top_level.txt +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/LICENSE +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/MANIFEST.in +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/__init__.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/services/__init__.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/services/email.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/__init__.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/services/__init__.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/urls.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/views.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/setup.cfg +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/setup.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/tests/__init__.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/tests/test_email.py +0 -0
- {bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/tests/test_user_views.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BmorricalDjangoWorkflows
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: Reusable Django Workflows
|
|
5
5
|
Home-page: https://github.com/Bmorrical/django-workflows
|
|
6
6
|
Author: Bradley Morrical
|
|
@@ -78,6 +78,7 @@ WORKFLOWS = {
|
|
|
78
78
|
# Optional settings with defaults shown.
|
|
79
79
|
"COMPANY_NAME": "My Company",
|
|
80
80
|
"ENABLE_EMAIL_DELIVERY": False,
|
|
81
|
+
"FORGOT_PASSWORD_URL": "https://app.example.com/forgot-password",
|
|
81
82
|
"RESET_CODE_TTL_MINUTES": 10,
|
|
82
83
|
"MAX_VERIFY_ATTEMPTS": 3,
|
|
83
84
|
}
|
|
@@ -86,8 +87,21 @@ WORKFLOWS = {
|
|
|
86
87
|
Notes:
|
|
87
88
|
|
|
88
89
|
- `USER_META_MODEL` must be a dotted import path such as `myapp.models.UserMeta`.
|
|
90
|
+
- `FORGOT_PASSWORD_URL` is used in the admin-created account email to link users into the host app's forgot-password flow.
|
|
91
|
+
- Host apps will usually source `FORGOT_PASSWORD_URL` from an environment variable in their own settings module.
|
|
89
92
|
- If `ENABLE_EMAIL_DELIVERY` is true, configure the email transport environment variables used by the mail service.
|
|
90
93
|
|
|
94
|
+
Example host-project wiring:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import os
|
|
98
|
+
|
|
99
|
+
WORKFLOWS = {
|
|
100
|
+
"USER_META_MODEL": "users.models_user_meta.UserMeta",
|
|
101
|
+
"FORGOT_PASSWORD_URL": os.getenv("FORGOT_PASSWORD_URL", ""),
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
91
105
|
## Email Delivery Environment Variables
|
|
92
106
|
|
|
93
107
|
When email delivery is enabled, set:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: BmorricalDjangoWorkflows
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.4
|
|
4
4
|
Summary: Reusable Django Workflows
|
|
5
5
|
Home-page: https://github.com/Bmorrical/django-workflows
|
|
6
6
|
Author: Bradley Morrical
|
|
@@ -78,6 +78,7 @@ WORKFLOWS = {
|
|
|
78
78
|
# Optional settings with defaults shown.
|
|
79
79
|
"COMPANY_NAME": "My Company",
|
|
80
80
|
"ENABLE_EMAIL_DELIVERY": False,
|
|
81
|
+
"FORGOT_PASSWORD_URL": "https://app.example.com/forgot-password",
|
|
81
82
|
"RESET_CODE_TTL_MINUTES": 10,
|
|
82
83
|
"MAX_VERIFY_ATTEMPTS": 3,
|
|
83
84
|
}
|
|
@@ -86,8 +87,21 @@ WORKFLOWS = {
|
|
|
86
87
|
Notes:
|
|
87
88
|
|
|
88
89
|
- `USER_META_MODEL` must be a dotted import path such as `myapp.models.UserMeta`.
|
|
90
|
+
- `FORGOT_PASSWORD_URL` is used in the admin-created account email to link users into the host app's forgot-password flow.
|
|
91
|
+
- Host apps will usually source `FORGOT_PASSWORD_URL` from an environment variable in their own settings module.
|
|
89
92
|
- If `ENABLE_EMAIL_DELIVERY` is true, configure the email transport environment variables used by the mail service.
|
|
90
93
|
|
|
94
|
+
Example host-project wiring:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
import os
|
|
98
|
+
|
|
99
|
+
WORKFLOWS = {
|
|
100
|
+
"USER_META_MODEL": "users.models_user_meta.UserMeta",
|
|
101
|
+
"FORGOT_PASSWORD_URL": os.getenv("FORGOT_PASSWORD_URL", ""),
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
91
105
|
## Email Delivery Environment Variables
|
|
92
106
|
|
|
93
107
|
When email delivery is enabled, set:
|
|
@@ -54,6 +54,7 @@ WORKFLOWS = {
|
|
|
54
54
|
# Optional settings with defaults shown.
|
|
55
55
|
"COMPANY_NAME": "My Company",
|
|
56
56
|
"ENABLE_EMAIL_DELIVERY": False,
|
|
57
|
+
"FORGOT_PASSWORD_URL": "https://app.example.com/forgot-password",
|
|
57
58
|
"RESET_CODE_TTL_MINUTES": 10,
|
|
58
59
|
"MAX_VERIFY_ATTEMPTS": 3,
|
|
59
60
|
}
|
|
@@ -62,8 +63,21 @@ WORKFLOWS = {
|
|
|
62
63
|
Notes:
|
|
63
64
|
|
|
64
65
|
- `USER_META_MODEL` must be a dotted import path such as `myapp.models.UserMeta`.
|
|
66
|
+
- `FORGOT_PASSWORD_URL` is used in the admin-created account email to link users into the host app's forgot-password flow.
|
|
67
|
+
- Host apps will usually source `FORGOT_PASSWORD_URL` from an environment variable in their own settings module.
|
|
65
68
|
- If `ENABLE_EMAIL_DELIVERY` is true, configure the email transport environment variables used by the mail service.
|
|
66
69
|
|
|
70
|
+
Example host-project wiring:
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import os
|
|
74
|
+
|
|
75
|
+
WORKFLOWS = {
|
|
76
|
+
"USER_META_MODEL": "users.models_user_meta.UserMeta",
|
|
77
|
+
"FORGOT_PASSWORD_URL": os.getenv("FORGOT_PASSWORD_URL", ""),
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
67
81
|
## Email Delivery Environment Variables
|
|
68
82
|
|
|
69
83
|
When email delivery is enabled, set:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.1.4
|
|
@@ -26,6 +26,7 @@ _ALLOWED_CODE_CHARS = [
|
|
|
26
26
|
]
|
|
27
27
|
_LOG_DEV_CODES_SETTING = "LOG_VERIFICATION_CODES_IN_DEBUG"
|
|
28
28
|
_EMAIL_DELIVERY_ENABLED_SETTING = "ENABLE_EMAIL_DELIVERY"
|
|
29
|
+
_FORGOT_PASSWORD_URL_SETTING = "FORGOT_PASSWORD_URL"
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
def generate_verification_code(*, length: int = 6) -> str:
|
|
@@ -314,6 +315,32 @@ def _get_force_password_reset(user: Any) -> bool:
|
|
|
314
315
|
return False
|
|
315
316
|
|
|
316
317
|
|
|
318
|
+
def _build_admin_setup_email_message(
|
|
319
|
+
*,
|
|
320
|
+
first_name: str,
|
|
321
|
+
last_name: str,
|
|
322
|
+
company_name: str,
|
|
323
|
+
forgot_password_url: Any,
|
|
324
|
+
) -> str:
|
|
325
|
+
forgot_password_instructions = (
|
|
326
|
+
'Use the "Forgot Password" flow to establish your password and login.<br><br>'
|
|
327
|
+
)
|
|
328
|
+
normalized_forgot_password_url = str(forgot_password_url or "").strip()
|
|
329
|
+
|
|
330
|
+
if normalized_forgot_password_url:
|
|
331
|
+
forgot_password_instructions = (
|
|
332
|
+
f'Click the link <a href="{normalized_forgot_password_url}">{normalized_forgot_password_url}</a> to use the '
|
|
333
|
+
'"Forgot Password" flow to establish your password and login.<br><br>'
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
return (
|
|
337
|
+
f"Hello {first_name} {last_name},<br><br>"
|
|
338
|
+
'You have been added as a registered user by an administrator. '
|
|
339
|
+
f"{forgot_password_instructions}"
|
|
340
|
+
f"Thank you!<br><br>{company_name}"
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
|
|
317
344
|
def get_user_details(user: Any) -> dict[str, Any]:
|
|
318
345
|
return {
|
|
319
346
|
"id": user.id,
|
|
@@ -505,6 +532,7 @@ def admin_register_user_and_send_setup_email(
|
|
|
505
532
|
User = get_user_model()
|
|
506
533
|
|
|
507
534
|
company_name = _get_workflow_setting("COMPANY_NAME", "")
|
|
535
|
+
forgot_password_url = _get_workflow_setting(_FORGOT_PASSWORD_URL_SETTING, "")
|
|
508
536
|
enable_email_delivery = _is_enabled(
|
|
509
537
|
_get_workflow_setting(_EMAIL_DELIVERY_ENABLED_SETTING, False)
|
|
510
538
|
)
|
|
@@ -537,11 +565,11 @@ def admin_register_user_and_send_setup_email(
|
|
|
537
565
|
)
|
|
538
566
|
_sync_user_groups(user=user, groups=validated_groups)
|
|
539
567
|
|
|
540
|
-
message = (
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
568
|
+
message = _build_admin_setup_email_message(
|
|
569
|
+
first_name=first_name,
|
|
570
|
+
last_name=last_name,
|
|
571
|
+
company_name=company_name,
|
|
572
|
+
forgot_password_url=forgot_password_url,
|
|
545
573
|
)
|
|
546
574
|
except IntegrityError:
|
|
547
575
|
logger.exception("Admin registration failed due to IntegrityError for email=%s", email)
|
|
@@ -47,6 +47,7 @@ class AuthFlowTests(TestCase):
|
|
|
47
47
|
defaults = {
|
|
48
48
|
"COMPANY_NAME": "Acme Co",
|
|
49
49
|
"ENABLE_EMAIL_DELIVERY": False,
|
|
50
|
+
"FORGOT_PASSWORD_URL": "",
|
|
50
51
|
"RESET_CODE_TTL_MINUTES": 10,
|
|
51
52
|
"MAX_VERIFY_ATTEMPTS": 3,
|
|
52
53
|
}
|
|
@@ -75,6 +76,35 @@ class AuthFlowTests(TestCase):
|
|
|
75
76
|
self.assertIsInstance(password, str)
|
|
76
77
|
self.assertTrue(password)
|
|
77
78
|
|
|
79
|
+
def test_build_admin_setup_email_message_includes_forgot_password_link_when_configured(self):
|
|
80
|
+
message = auth_flow._build_admin_setup_email_message(
|
|
81
|
+
first_name="New",
|
|
82
|
+
last_name="User",
|
|
83
|
+
company_name="Reusable Inc",
|
|
84
|
+
forgot_password_url="https://app.example.com/forgot-password",
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
self.assertIn(
|
|
88
|
+
'Click the link <a href="https://app.example.com/forgot-password">https://app.example.com/forgot-password</a> to use the '
|
|
89
|
+
'"Forgot Password" flow to establish your password and login.<br><br>',
|
|
90
|
+
message,
|
|
91
|
+
)
|
|
92
|
+
self.assertIn("Reusable Inc", message)
|
|
93
|
+
|
|
94
|
+
def test_build_admin_setup_email_message_falls_back_when_url_missing(self):
|
|
95
|
+
message = auth_flow._build_admin_setup_email_message(
|
|
96
|
+
first_name="New",
|
|
97
|
+
last_name="User",
|
|
98
|
+
company_name="Reusable Inc",
|
|
99
|
+
forgot_password_url=" ",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
self.assertIn(
|
|
103
|
+
'Use the "Forgot Password" flow to establish your password and login.<br><br>',
|
|
104
|
+
message,
|
|
105
|
+
)
|
|
106
|
+
self.assertNotIn("href=", message)
|
|
107
|
+
|
|
78
108
|
@patch.object(auth_flow.logger, "isEnabledFor", return_value=True)
|
|
79
109
|
@patch.object(auth_flow.logger, "debug")
|
|
80
110
|
@patch.object(auth_flow, "_get_workflow_setting", return_value=True)
|
|
@@ -757,6 +787,7 @@ class AuthFlowTests(TestCase):
|
|
|
757
787
|
mock_get_setting.side_effect = self._settings_getter(
|
|
758
788
|
ENABLE_EMAIL_DELIVERY=True,
|
|
759
789
|
COMPANY_NAME="Reusable Inc",
|
|
790
|
+
FORGOT_PASSWORD_URL="https://app.example.com/forgot-password",
|
|
760
791
|
)
|
|
761
792
|
mock_send_email.return_value = SimpleNamespace(status_code=200, text="ok")
|
|
762
793
|
|
|
@@ -807,7 +838,7 @@ class AuthFlowTests(TestCase):
|
|
|
807
838
|
self.assertEqual(kwargs["to"], ["new@example.com"])
|
|
808
839
|
self.assertEqual(kwargs["subject"], "Your account has been created")
|
|
809
840
|
self.assertIn(
|
|
810
|
-
'You have been added as a registered user by an administrator.
|
|
841
|
+
'You have been added as a registered user by an administrator. Click the link <a href="https://app.example.com/forgot-password">https://app.example.com/forgot-password</a> to use the "Forgot Password" flow to establish your password and login.',
|
|
811
842
|
kwargs["html"],
|
|
812
843
|
)
|
|
813
844
|
self.assertIn("Reusable Inc", kwargs["html"])
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2.1.3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/services/email.py
RENAMED
|
File without changes
|
{bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/urls.py
RENAMED
|
File without changes
|
{bmorricaldjangoworkflows-2.1.3 → bmorricaldjangoworkflows-2.1.4}/django_workflows/users/views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|