micro-users 1.8.3__tar.gz → 1.9.0__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.
Files changed (53) hide show
  1. {micro_users-1.8.3 → micro_users-1.9.0}/PKG-INFO +26 -19
  2. {micro_users-1.8.3 → micro_users-1.9.0}/README.md +26 -19
  3. {micro_users-1.8.3 → micro_users-1.9.0}/micro_users.egg-info/PKG-INFO +26 -19
  4. {micro_users-1.8.3 → micro_users-1.9.0}/micro_users.egg-info/SOURCES.txt +4 -1
  5. {micro_users-1.8.3 → micro_users-1.9.0}/pyproject.toml +1 -1
  6. {micro_users-1.8.3 → micro_users-1.9.0}/setup.py +1 -1
  7. micro_users-1.9.0/users/context_processors.py +9 -0
  8. {micro_users-1.8.3 → micro_users-1.9.0}/users/filters.py +8 -8
  9. {micro_users-1.8.3 → micro_users-1.9.0}/users/forms.py +42 -29
  10. micro_users-1.8.3/users/migrations/0003_scope_alter_customuser_options_and_more.py → micro_users-1.9.0/users/migrations/0003_scope_scopesettings_alter_customuser_options_and_more.py +12 -1
  11. {micro_users-1.8.3 → micro_users-1.9.0}/users/models.py +18 -0
  12. micro_users-1.9.0/users/static/users/css/login.css +273 -0
  13. micro_users-1.9.0/users/static/users/js/manage_users.js +189 -0
  14. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/js/permissions.js +7 -0
  15. micro_users-1.9.0/users/templates/users/manage_users.html +133 -0
  16. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/partials/scope_actions.html +2 -2
  17. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/partials/scope_form.html +3 -3
  18. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/partials/scope_manager.html +2 -2
  19. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/partials/user_actions.html +2 -1
  20. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/profile/profile.html +6 -6
  21. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/profile/profile_edit.html +8 -8
  22. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/user_activity_log.html +8 -2
  23. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/user_detail.html +1 -1
  24. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/widgets/grouped_permissions.html +1 -1
  25. {micro_users-1.8.3 → micro_users-1.9.0}/users/urls.py +1 -0
  26. micro_users-1.9.0/users/utils.py +14 -0
  27. {micro_users-1.8.3 → micro_users-1.9.0}/users/views.py +43 -4
  28. micro_users-1.8.3/users/static/users/css/login.css +0 -184
  29. micro_users-1.8.3/users/templates/users/manage_users.html +0 -158
  30. {micro_users-1.8.3 → micro_users-1.9.0}/LICENSE +0 -0
  31. {micro_users-1.8.3 → micro_users-1.9.0}/MANIFEST.in +0 -0
  32. {micro_users-1.8.3 → micro_users-1.9.0}/micro_users.egg-info/dependency_links.txt +0 -0
  33. {micro_users-1.8.3 → micro_users-1.9.0}/micro_users.egg-info/requires.txt +0 -0
  34. {micro_users-1.8.3 → micro_users-1.9.0}/micro_users.egg-info/top_level.txt +0 -0
  35. {micro_users-1.8.3 → micro_users-1.9.0}/setup.cfg +0 -0
  36. {micro_users-1.8.3 → micro_users-1.9.0}/users/__init__.py +0 -0
  37. {micro_users-1.8.3 → micro_users-1.9.0}/users/admin.py +0 -0
  38. {micro_users-1.8.3 → micro_users-1.9.0}/users/apps.py +0 -0
  39. {micro_users-1.8.3 → micro_users-1.9.0}/users/middleware.py +0 -0
  40. {micro_users-1.8.3 → micro_users-1.9.0}/users/migrations/0001_initial.py +0 -0
  41. {micro_users-1.8.3 → micro_users-1.9.0}/users/migrations/0002_alter_useractivitylog_action.py +0 -0
  42. {micro_users-1.8.3 → micro_users-1.9.0}/users/migrations/__init__.py +0 -0
  43. {micro_users-1.8.3 → micro_users-1.9.0}/users/signals.py +0 -0
  44. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/img/default_profile.webp +0 -0
  45. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/img/login_logo.webp +0 -0
  46. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/css/detail.css +0 -0
  47. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/css/permissions.css +0 -0
  48. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/css/profile.css +0 -0
  49. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/css/style.css +0 -0
  50. {micro_users-1.8.3 → micro_users-1.9.0}/users/static/users/js/login.js +0 -0
  51. {micro_users-1.8.3 → micro_users-1.9.0}/users/tables.py +0 -0
  52. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/registration/login.html +0 -0
  53. {micro_users-1.8.3 → micro_users-1.9.0}/users/templates/users/user_form.html +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: micro_users
3
- Version: 1.8.3
3
+ Version: 1.9.0
4
4
  Summary: Arabic Django user management app with abstract user, permissions, and activity logging
5
5
  Home-page: https://github.com/debeski/micro-users
6
6
  Author: DeBeski
@@ -92,12 +92,27 @@ MIDDLEWARE = [
92
92
  ]
93
93
  ```
94
94
 
95
- 3. Set custom user model in `settings.py`:
95
+ 3. Add Context Processor in `settings.py` (Optional, for `scope_enabled` variable in templates):
96
+ ```python
97
+ TEMPLATES = [
98
+ {
99
+ # ...
100
+ 'OPTIONS': {
101
+ 'context_processors': [
102
+ # ...
103
+ 'users.context_processors.scope_settings', # Add this line
104
+ ],
105
+ },
106
+ },
107
+ ]
108
+ ```
109
+
110
+ 4. Set custom user model in `settings.py`:
96
111
  ```python
97
112
  AUTH_USER_MODEL = 'users.CustomUser'
98
113
  ```
99
114
 
100
- 4. Include URLs in your main project folder `urls.py`:
115
+ 5. Include URLs in your main project folder `urls.py`:
101
116
  ```python
102
117
  urlpatterns = [
103
118
  ...
@@ -105,7 +120,7 @@ urlpatterns = [
105
120
  ]
106
121
  ```
107
122
 
108
- 5. Run migrations:
123
+ 6. Run migrations:
109
124
  ```bash
110
125
  python manage.py migrate users
111
126
  ```
@@ -168,21 +183,6 @@ users/
168
183
  ### Replacing Login Logo
169
184
  To replace the default login logo, simply place your own `login_logo.webp` image in your project's static directory at `static/img/login_logo.webp`.
170
185
 
171
- ### Theme Configuration
172
- You can configure the login page colors by defining `MICRO_USERS_THEME` in your project's `settings.py`. This dictionary overrides the default CSS variables.
173
-
174
- ```python
175
- MICRO_USERS_THEME = {
176
- 'right_bg': '#474745',
177
- 'left_bg': 'white',
178
- 'selection_bg': '#dbdbdb',
179
- 'gradient_start': '#a2a2a7',
180
- 'gradient_end': '#474745',
181
- # Additional keys supported:
182
- # 'selection_moz_bg', 'left_shadow', 'right_shadow', 'right_text',
183
- # 'label_color', 'input_text', 'submit_color', 'submit_focus', 'submit_active'
184
- }
185
- ```
186
186
 
187
187
  ## Version History
188
188
 
@@ -215,3 +215,10 @@ MICRO_USERS_THEME = {
215
215
  | v1.8.1 | • **UI Refinement**: Swapped `Email` and `Phone` positions across all forms, tables, and detail views<br>• **Field Logic**: Set `Email` and `Phone` as optional (not required) for all users<br>• **Security**: Added `manage_staff` custom permission to restrict `is_staff` management to authorized managers only<br>• **Bug Fix**: Reserved `manage_staff` assignment power strictly for Superusers and fixed UI grouping for custom permissions |
216
216
  | v1.8.2 | • **Login UX**: Enhanced login flow with auto-focus on username and improved "Enter to Submit" handling |
217
217
  | v1.8.3 | • **CSP Compliance**: Added `nonce` attribute support to all inline and external script tags (Login, Permissions, Manage Users) for Content Security Policy compliance |
218
+ | v1.8.4 | • **Strict CSP**: Refactored inline JS event handlers to use Event Listeners, fully resolving CSP violation errors |
219
+ | v1.8.5 | • **Optional Scopes**: Added ability for Superusers to toggle Scope system ON/OFF via User Management interface |
220
+ | v1.8.6 | • **Strict CSP Repair**: Fixed remaining inline event handlers in User Management pages (`manage_users`, `scope_form`) that were violating CSP directives, moving all logic to external `manage_users.js` |
221
+ | v1.8.7 | • Fixed a couple of template tab title mismatches |
222
+ | v1.8.8 | • Fixed a couple of template content title mismatches and classes |
223
+ | v1.8.9 | • Fixed migrations |
224
+ | v1.9.0 | • **UI Overhaul**: Unified all buttons, and clssses to conform to themes, rounded corners, and improved spacing |
@@ -60,12 +60,27 @@ MIDDLEWARE = [
60
60
  ]
61
61
  ```
62
62
 
63
- 3. Set custom user model in `settings.py`:
63
+ 3. Add Context Processor in `settings.py` (Optional, for `scope_enabled` variable in templates):
64
+ ```python
65
+ TEMPLATES = [
66
+ {
67
+ # ...
68
+ 'OPTIONS': {
69
+ 'context_processors': [
70
+ # ...
71
+ 'users.context_processors.scope_settings', # Add this line
72
+ ],
73
+ },
74
+ },
75
+ ]
76
+ ```
77
+
78
+ 4. Set custom user model in `settings.py`:
64
79
  ```python
65
80
  AUTH_USER_MODEL = 'users.CustomUser'
66
81
  ```
67
82
 
68
- 4. Include URLs in your main project folder `urls.py`:
83
+ 5. Include URLs in your main project folder `urls.py`:
69
84
  ```python
70
85
  urlpatterns = [
71
86
  ...
@@ -73,7 +88,7 @@ urlpatterns = [
73
88
  ]
74
89
  ```
75
90
 
76
- 5. Run migrations:
91
+ 6. Run migrations:
77
92
  ```bash
78
93
  python manage.py migrate users
79
94
  ```
@@ -136,21 +151,6 @@ users/
136
151
  ### Replacing Login Logo
137
152
  To replace the default login logo, simply place your own `login_logo.webp` image in your project's static directory at `static/img/login_logo.webp`.
138
153
 
139
- ### Theme Configuration
140
- You can configure the login page colors by defining `MICRO_USERS_THEME` in your project's `settings.py`. This dictionary overrides the default CSS variables.
141
-
142
- ```python
143
- MICRO_USERS_THEME = {
144
- 'right_bg': '#474745',
145
- 'left_bg': 'white',
146
- 'selection_bg': '#dbdbdb',
147
- 'gradient_start': '#a2a2a7',
148
- 'gradient_end': '#474745',
149
- # Additional keys supported:
150
- # 'selection_moz_bg', 'left_shadow', 'right_shadow', 'right_text',
151
- # 'label_color', 'input_text', 'submit_color', 'submit_focus', 'submit_active'
152
- }
153
- ```
154
154
 
155
155
  ## Version History
156
156
 
@@ -182,4 +182,11 @@ MICRO_USERS_THEME = {
182
182
  | v1.8.0 | • **Permissions UI**: Complete redesign with App/Model-based grouping and hierarchical checkboxes<br>• **Aesthetics**: Applied modern glassmorphism theme to permission cards with interactive toggles<br>• **Security**: Implemented 3-level security logic (GM, SM, User) and "invisible" Superuser protection<br>• **Foolproofing**: Added self-editing protection for staff and scope enforcement for managers<br>• **Localization**: Fully translated system auth labels and metadata to Arabic |
183
183
  | v1.8.1 | • **UI Refinement**: Swapped `Email` and `Phone` positions across all forms, tables, and detail views<br>• **Field Logic**: Set `Email` and `Phone` as optional (not required) for all users<br>• **Security**: Added `manage_staff` custom permission to restrict `is_staff` management to authorized managers only<br>• **Bug Fix**: Reserved `manage_staff` assignment power strictly for Superusers and fixed UI grouping for custom permissions |
184
184
  | v1.8.2 | • **Login UX**: Enhanced login flow with auto-focus on username and improved "Enter to Submit" handling |
185
- | v1.8.3 | • **CSP Compliance**: Added `nonce` attribute support to all inline and external script tags (Login, Permissions, Manage Users) for Content Security Policy compliance |
185
+ | v1.8.3 | • **CSP Compliance**: Added `nonce` attribute support to all inline and external script tags (Login, Permissions, Manage Users) for Content Security Policy compliance |
186
+ | v1.8.4 | • **Strict CSP**: Refactored inline JS event handlers to use Event Listeners, fully resolving CSP violation errors |
187
+ | v1.8.5 | • **Optional Scopes**: Added ability for Superusers to toggle Scope system ON/OFF via User Management interface |
188
+ | v1.8.6 | • **Strict CSP Repair**: Fixed remaining inline event handlers in User Management pages (`manage_users`, `scope_form`) that were violating CSP directives, moving all logic to external `manage_users.js` |
189
+ | v1.8.7 | • Fixed a couple of template tab title mismatches |
190
+ | v1.8.8 | • Fixed a couple of template content title mismatches and classes |
191
+ | v1.8.9 | • Fixed migrations |
192
+ | v1.9.0 | • **UI Overhaul**: Unified all buttons, and clssses to conform to themes, rounded corners, and improved spacing |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: micro-users
3
- Version: 1.8.3
3
+ Version: 1.9.0
4
4
  Summary: Arabic Django user management app with abstract user, permissions, and activity logging
5
5
  Home-page: https://github.com/debeski/micro-users
6
6
  Author: DeBeski
@@ -92,12 +92,27 @@ MIDDLEWARE = [
92
92
  ]
93
93
  ```
94
94
 
95
- 3. Set custom user model in `settings.py`:
95
+ 3. Add Context Processor in `settings.py` (Optional, for `scope_enabled` variable in templates):
96
+ ```python
97
+ TEMPLATES = [
98
+ {
99
+ # ...
100
+ 'OPTIONS': {
101
+ 'context_processors': [
102
+ # ...
103
+ 'users.context_processors.scope_settings', # Add this line
104
+ ],
105
+ },
106
+ },
107
+ ]
108
+ ```
109
+
110
+ 4. Set custom user model in `settings.py`:
96
111
  ```python
97
112
  AUTH_USER_MODEL = 'users.CustomUser'
98
113
  ```
99
114
 
100
- 4. Include URLs in your main project folder `urls.py`:
115
+ 5. Include URLs in your main project folder `urls.py`:
101
116
  ```python
102
117
  urlpatterns = [
103
118
  ...
@@ -105,7 +120,7 @@ urlpatterns = [
105
120
  ]
106
121
  ```
107
122
 
108
- 5. Run migrations:
123
+ 6. Run migrations:
109
124
  ```bash
110
125
  python manage.py migrate users
111
126
  ```
@@ -168,21 +183,6 @@ users/
168
183
  ### Replacing Login Logo
169
184
  To replace the default login logo, simply place your own `login_logo.webp` image in your project's static directory at `static/img/login_logo.webp`.
170
185
 
171
- ### Theme Configuration
172
- You can configure the login page colors by defining `MICRO_USERS_THEME` in your project's `settings.py`. This dictionary overrides the default CSS variables.
173
-
174
- ```python
175
- MICRO_USERS_THEME = {
176
- 'right_bg': '#474745',
177
- 'left_bg': 'white',
178
- 'selection_bg': '#dbdbdb',
179
- 'gradient_start': '#a2a2a7',
180
- 'gradient_end': '#474745',
181
- # Additional keys supported:
182
- # 'selection_moz_bg', 'left_shadow', 'right_shadow', 'right_text',
183
- # 'label_color', 'input_text', 'submit_color', 'submit_focus', 'submit_active'
184
- }
185
- ```
186
186
 
187
187
  ## Version History
188
188
 
@@ -215,3 +215,10 @@ MICRO_USERS_THEME = {
215
215
  | v1.8.1 | • **UI Refinement**: Swapped `Email` and `Phone` positions across all forms, tables, and detail views<br>• **Field Logic**: Set `Email` and `Phone` as optional (not required) for all users<br>• **Security**: Added `manage_staff` custom permission to restrict `is_staff` management to authorized managers only<br>• **Bug Fix**: Reserved `manage_staff` assignment power strictly for Superusers and fixed UI grouping for custom permissions |
216
216
  | v1.8.2 | • **Login UX**: Enhanced login flow with auto-focus on username and improved "Enter to Submit" handling |
217
217
  | v1.8.3 | • **CSP Compliance**: Added `nonce` attribute support to all inline and external script tags (Login, Permissions, Manage Users) for Content Security Policy compliance |
218
+ | v1.8.4 | • **Strict CSP**: Refactored inline JS event handlers to use Event Listeners, fully resolving CSP violation errors |
219
+ | v1.8.5 | • **Optional Scopes**: Added ability for Superusers to toggle Scope system ON/OFF via User Management interface |
220
+ | v1.8.6 | • **Strict CSP Repair**: Fixed remaining inline event handlers in User Management pages (`manage_users`, `scope_form`) that were violating CSP directives, moving all logic to external `manage_users.js` |
221
+ | v1.8.7 | • Fixed a couple of template tab title mismatches |
222
+ | v1.8.8 | • Fixed a couple of template content title mismatches and classes |
223
+ | v1.8.9 | • Fixed migrations |
224
+ | v1.9.0 | • **UI Overhaul**: Unified all buttons, and clssses to conform to themes, rounded corners, and improved spacing |
@@ -11,6 +11,7 @@ micro_users.egg-info/top_level.txt
11
11
  users/__init__.py
12
12
  users/admin.py
13
13
  users/apps.py
14
+ users/context_processors.py
14
15
  users/filters.py
15
16
  users/forms.py
16
17
  users/middleware.py
@@ -18,10 +19,11 @@ users/models.py
18
19
  users/signals.py
19
20
  users/tables.py
20
21
  users/urls.py
22
+ users/utils.py
21
23
  users/views.py
22
24
  users/migrations/0001_initial.py
23
25
  users/migrations/0002_alter_useractivitylog_action.py
24
- users/migrations/0003_scope_alter_customuser_options_and_more.py
26
+ users/migrations/0003_scope_scopesettings_alter_customuser_options_and_more.py
25
27
  users/migrations/__init__.py
26
28
  users/static/img/default_profile.webp
27
29
  users/static/img/login_logo.webp
@@ -31,6 +33,7 @@ users/static/users/css/permissions.css
31
33
  users/static/users/css/profile.css
32
34
  users/static/users/css/style.css
33
35
  users/static/users/js/login.js
36
+ users/static/users/js/manage_users.js
34
37
  users/static/users/js/permissions.js
35
38
  users/templates/registration/login.html
36
39
  users/templates/users/manage_users.html
@@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
8
8
 
9
9
  [project]
10
10
  name = "micro_users"
11
- version = "1.8.3"
11
+ version = "1.9.0"
12
12
  description = "Arabic Django user management app with abstract user, permissions, and activity logging"
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.11"
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
5
5
 
6
6
  setup(
7
7
  name="micro_users",
8
- version="1.8.3",
8
+ version="1.9.0",
9
9
  author="DeBeski",
10
10
  author_email="debeski1@gmail.com",
11
11
  description="Arabic django user management app with abstract user, permissions, and activity logging",
@@ -0,0 +1,9 @@
1
+ from .utils import is_scope_enabled
2
+
3
+ def scope_settings(request):
4
+ """
5
+ Context processor to add scope settings to all templates.
6
+ """
7
+ return {
8
+ 'scope_enabled': is_scope_enabled()
9
+ }
@@ -6,7 +6,7 @@ from crispy_forms.helper import FormHelper
6
6
  from crispy_forms.layout import Layout, Row, Column, Field, HTML, Hidden
7
7
  from django.db.models import Q
8
8
  from django.apps import apps # Import apps
9
-
9
+ from users.utils import is_scope_enabled
10
10
  User = get_user_model() # Use custom user model
11
11
 
12
12
  class UserFilter(django_filters.FilterSet):
@@ -34,8 +34,8 @@ class UserFilter(django_filters.FilterSet):
34
34
  self.form.helper.layout.append(
35
35
  Row(
36
36
  Column(Field('keyword', placeholder="البحث"), css_class='form-group col-auto flex-fill'),
37
- Column(HTML('<button type="submit" class="btn btn-secondary w-100"><i class="bi bi-search bi-font text-light me-2"></i>بحـــث</button>'), css_class='col-auto text-center'),
38
- Column(HTML(f'{{% if request.GET and request.GET.keys|length > 1 %}} <a href="{clear_url}" class="btn btn-warning bi-font">clear</a> {{% endif %}}'), css_class='form-group col-auto text-center'),
37
+ Column(HTML('<button type="submit" class="btn btn-secondary rounded-pill w-100"><i class="bi bi-search bi-font text-light me-2"></i>بحـــث</button>'), css_class='col-auto text-center'),
38
+ Column(HTML(f'{{% if request.GET and request.GET.keys|length > 1 %}} <a href="{clear_url}" class="btn btn-warning rounded-pill bi-font">clear</a> {{% endif %}}'), css_class='form-group col-auto text-center'),
39
39
  css_class='form-row'
40
40
  ),
41
41
  )
@@ -104,9 +104,9 @@ class UserActivityLogFilter(django_filters.FilterSet):
104
104
  row_fields = [
105
105
  Column(Field('keyword', placeholder="البحث"), css_class='form-group col-auto flex-fill'),
106
106
  ]
107
-
108
- if not (self.request and self.request.user.scope):
109
- row_fields.append(Column(Field('scope', placeholder="النطاق", dir="rtl"), css_class='form-group col-auto'))
107
+ if is_scope_enabled():
108
+ if not (self.request and self.request.user.scope):
109
+ row_fields.append(Column(Field('scope', placeholder="النطاق", dir="rtl"), css_class='form-group col-auto'))
110
110
 
111
111
  # Prepare clear button URL with sort parameter if exists
112
112
  clear_url = '{% url "user_activity_log" %}'
@@ -122,8 +122,8 @@ class UserActivityLogFilter(django_filters.FilterSet):
122
122
  ),
123
123
  css_class='col-auto flex-fill'
124
124
  ),
125
- Column(HTML('<button type="submit" class="btn btn-secondary w-100"><i class="bi bi-search bi-font text-light me-2"></i>بحـــث</button>'), css_class='col-auto text-center'),
126
- Column(HTML(f'{{% if request.GET and request.GET.keys|length > 1 %}} <a href="{clear_url}" class="btn btn-warning bi-font">clear</a> {{% endif %}}'), css_class='form-group col-auto text-center'),
125
+ Column(HTML('<button type="submit" class="btn btn-secondary rounded-pill w-100"><i class="bi bi-search bi-font text-light me-2"></i>بحـــث</button>'), css_class='col-auto text-center'),
126
+ Column(HTML(f'{{% if request.GET and request.GET.keys|length > 1 %}} <a href="{clear_url}" class="btn btn-warning rounded-pill bi-font">clear</a> {{% endif %}}'), css_class='form-group col-auto text-center'),
127
127
  ])
128
128
 
129
129
  self.form.helper.layout.append(Row(*row_fields, css_class='form-row'))
@@ -5,7 +5,7 @@ from django.contrib.auth.models import Permission as Permissions
5
5
  from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm, SetPasswordForm
6
6
  from django.contrib.auth import get_user_model
7
7
  from crispy_forms.helper import FormHelper
8
- from crispy_forms.layout import Layout, Field, Div, HTML, Submit
8
+ from crispy_forms.layout import Layout, Field, Div, HTML, Submit, Row
9
9
  from crispy_forms.bootstrap import FormActions
10
10
  from PIL import Image
11
11
  from django.core.exceptions import ValidationError
@@ -165,6 +165,12 @@ class CustomUserCreationForm(UserCreationForm):
165
165
  user_perms = self.user.user_permissions.all() | Permissions.objects.filter(group__user=self.user)
166
166
  self.fields['permissions'].queryset = self.fields['permissions'].queryset.filter(id__in=user_perms.values_list('id', flat=True))
167
167
 
168
+ ScopeSettings = apps.get_model('users', 'ScopeSettings')
169
+ if not ScopeSettings.load().is_enabled:
170
+ self.fields['scope'].disabled = True
171
+ self.fields['scope'].widget = forms.HiddenInput()
172
+ self.fields['scope'].required = False
173
+
168
174
  if self.user and not self.user.is_superuser and self.user.scope:
169
175
  self.fields['scope'].initial = self.user.scope
170
176
  self.fields['scope'].disabled = True
@@ -187,14 +193,15 @@ class CustomUserCreationForm(UserCreationForm):
187
193
  self.fields["email"].label = "البريد الإلكتروني"
188
194
  self.fields["first_name"].label = "الاسم"
189
195
  self.fields["last_name"].label = "اللقب"
190
- self.fields["is_staff"].label = "صلاحيات انشاء و تعديل المستخدمين"
196
+ self.fields["is_staff"].label = "صلاحيات انشاء و تعديل المستخدمين (مسؤول)"
191
197
  self.fields["password1"].label = "كلمة المرور"
192
198
  self.fields["password2"].label = "تأكيد كلمة المرور"
193
199
  self.fields["is_active"].label = "تفعيل الحساب"
194
200
 
195
201
  # Help Texts
196
- self.fields["username"].help_text = "اسم المستخدم يجب أن يكون فريدًا، 50 حرفًا أو أقل. فقط حروف، أرقام و @ . + - _"
202
+ self.fields["username"].help_text = "اسم المستخدم يجب أن يكون فريدًا، 20 حرفًا أو أقل. فقط حروف، أرقام و @ . + - _"
197
203
  self.fields["email"].help_text = "أدخل عنوان البريد الإلكتروني الصحيح"
204
+ self.fields["phone"].help_text = "أدخل رقم الهاتف الصحيح بالصيغة الاتية 09XXXXXXXX"
198
205
  self.fields["is_staff"].help_text = "يحدد ما إذا كان بإمكان المستخدم الوصول إلى قسم ادارة المستخدمين."
199
206
  self.fields["is_active"].help_text = "يحدد ما إذا كان يجب اعتبار هذا الحساب نشطًا."
200
207
  self.fields["password1"].help_text = "كلمة المرور يجب ألا تكون مشابهة لمعلوماتك الشخصية، وأن تحتوي على 8 أحرف على الأقل، وألا تكون شائعة أو رقمية بالكامل.."
@@ -203,21 +210,21 @@ class CustomUserCreationForm(UserCreationForm):
203
210
  # Use Crispy Forms Layout helper
204
211
  self.helper = FormHelper()
205
212
  self.helper.layout = Layout(
206
- "username",
207
- "phone",
208
- "password1",
209
- "password2",
213
+ Row(Field("username", css_class="form-control")),
214
+ Row(Field("password1", css_class="form-control")),
215
+ Row(Field("password2", css_class="form-control")),
210
216
  HTML("<hr>"),
211
- Div(
212
- Div(Field("first_name", css_class="col-md-6"), css_class="col-md-6"),
213
- Div(Field("last_name", css_class="col-md-6"), css_class="col-md-6"),
217
+ Row(
218
+ Div(Field("first_name", css_class="form-control"), css_class="col-md-6"),
219
+ Div(Field("last_name", css_class="form-control"), css_class="col-md-6"),
214
220
  css_class="row"
215
221
  ),
216
- Div(
217
- Div(Field("email", css_class="col-md-6"), css_class="col-md-6"),
218
- Div(Field("scope", css_class="col-md-6"), css_class="col-md-6"),
222
+ Row(
223
+ Div(Field("phone", css_class="form-control"), css_class="col-md-6"),
224
+ Div(Field("email", css_class="form-control"), css_class="col-md-6"),
219
225
  css_class="row"
220
226
  ),
227
+ Row(Field("scope", css_class="form-control")),
221
228
  HTML("<hr>"),
222
229
  Field("permissions", css_class="col-12"),
223
230
  "is_staff",
@@ -225,7 +232,7 @@ class CustomUserCreationForm(UserCreationForm):
225
232
  FormActions(
226
233
  HTML(
227
234
  """
228
- <button type="submit" class="btn btn-success">
235
+ <button type="submit" class="btn btn-success rounded-pill">
229
236
  <i class="bi bi-person-plus-fill text-light me-1 h4"></i>
230
237
  إضافة
231
238
  </button>
@@ -233,7 +240,7 @@ class CustomUserCreationForm(UserCreationForm):
233
240
  ),
234
241
  HTML(
235
242
  """
236
- <a href="{% url 'manage_users' %}" class="btn btn-secondary">
243
+ <a href="{% url 'manage_users' %}" class="btn btn-danger rounded-pill">
237
244
  <i class="bi bi-arrow-return-left text-light me-1 h4"></i> إلغـــاء
238
245
  </a>
239
246
  """
@@ -288,11 +295,11 @@ class CustomUserChangeForm(UserChangeForm):
288
295
  self.fields["email"].label = "البريد الإلكتروني"
289
296
  self.fields["first_name"].label = "الاسم الاول"
290
297
  self.fields["last_name"].label = "اللقب"
291
- self.fields["is_staff"].label = "صلاحيات انشاء و تعديل المستخدمين"
298
+ self.fields["is_staff"].label = "صلاحيات انشاء و تعديل المستخدمين (مسؤول)"
292
299
  self.fields["is_active"].label = "الحساب مفعل"
293
300
 
294
301
  # Help Texts
295
- self.fields["username"].help_text = "اسم المستخدم يجب أن يكون فريدًا، 50 حرفًا أو أقل. فقط حروف، أرقام و @ . + - _"
302
+ self.fields["username"].help_text = "اسم المستخدم يجب أن يكون فريدًا، 20 حرفًا أو أقل. فقط حروف، أرقام و @ . + - _"
296
303
  self.fields["email"].help_text = "أدخل عنوان البريد الإلكتروني الصحيح"
297
304
  self.fields["is_staff"].help_text = "يحدد ما إذا كان بإمكان المستخدم الوصول إلى قسم ادارة المستخدمين."
298
305
  self.fields["is_active"].help_text = "يحدد ما إذا كان يجب اعتبار هذا الحساب نشطًا. قم بإلغاء تحديد هذا الخيار بدلاً من الحذف."
@@ -300,6 +307,12 @@ class CustomUserChangeForm(UserChangeForm):
300
307
  if user_instance:
301
308
  self.fields["permissions"].initial = user_instance.user_permissions.all()
302
309
 
310
+ ScopeSettings = apps.get_model('users', 'ScopeSettings')
311
+ if not ScopeSettings.load().is_enabled:
312
+ self.fields['scope'].disabled = True
313
+ self.fields['scope'].widget = forms.HiddenInput()
314
+ self.fields['scope'].required = False
315
+
303
316
  # --- Foolproofing & Role-based logic ---
304
317
  if self.user and not self.user.is_superuser:
305
318
  # 1. Self-Editing Protection (Prevents accidental demotion)
@@ -335,19 +348,19 @@ class CustomUserChangeForm(UserChangeForm):
335
348
  self.helper = FormHelper()
336
349
  self.helper.form_tag = False
337
350
  self.helper.layout = Layout(
338
- "username",
339
- "phone",
351
+ Row(Field("username", css_class="form-control")),
340
352
  HTML("<hr>"),
341
- Div(
342
- Div(Field("first_name", css_class="col-md-6"), css_class="col-md-6"),
343
- Div(Field("last_name", css_class="col-md-6"), css_class="col-md-6"),
353
+ Row(
354
+ Div(Field("first_name", css_class="form-control"), css_class="col-md-6"),
355
+ Div(Field("last_name", css_class="form-control"), css_class="col-md-6"),
344
356
  css_class="row"
345
357
  ),
346
- Div(
347
- Div(Field("email", css_class="col-md-6"), css_class="col-md-6"),
348
- Div(Field("scope", css_class="col-md-6"), css_class="col-md-6"),
358
+ Row(
359
+ Div(Field("phone", css_class="form-control"), css_class="col-md-6"),
360
+ Div(Field("email", css_class="form-control"), css_class="col-md-6"),
349
361
  css_class="row"
350
362
  ),
363
+ Row(Field("scope", css_class="form-control")),
351
364
  HTML("<hr>"),
352
365
  Field("permissions", css_class="col-12"),
353
366
  "is_staff",
@@ -355,7 +368,7 @@ class CustomUserChangeForm(UserChangeForm):
355
368
  FormActions(
356
369
  HTML(
357
370
  """
358
- <button type="submit" class="btn btn-success">
371
+ <button type="submit" class="btn btn-success rounded-pill">
359
372
  <i class="bi bi-person-plus-fill text-light me-1 h4"></i>
360
373
  تحديث
361
374
  </button>
@@ -363,14 +376,14 @@ class CustomUserChangeForm(UserChangeForm):
363
376
  ),
364
377
  HTML(
365
378
  """
366
- <a href="{% url 'manage_users' %}" class="btn btn-secondary">
379
+ <a href="{% url 'manage_users' %}" class="btn btn-danger rounded-pill">
367
380
  <i class="bi bi-arrow-return-left text-light me-1 h4"></i> إلغـــاء
368
381
  </a>
369
382
  """
370
383
  ),
371
384
  HTML(
372
385
  """
373
- <button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#resetPasswordModal">
386
+ <button type="button" class="btn btn-warning rounded-pill" data-bs-toggle="modal" data-bs-target="#resetPasswordModal">
374
387
  <i class="bi bi-key-fill text-light me-1 h4"></i> إعادة تعيين كلمة المرور
375
388
  </button>
376
389
  """
@@ -405,7 +418,7 @@ class ResetPasswordForm(SetPasswordForm):
405
418
  Field('new_password2', css_class='col-md-12'),
406
419
  css_class='row'
407
420
  ),
408
- Submit('submit', 'تغيير كلمة المرور', css_class='btn btn-primary'),
421
+ Submit('submit', 'تغيير كلمة المرور', css_class='btn btn-danger rounded-pill'),
409
422
  )
410
423
 
411
424
  def save(self, commit=True):
@@ -1,4 +1,4 @@
1
- # Generated by Django 5.2.8 on 2026-01-27 23:46
1
+ # Generated by Django 5.2.8 on 2026-02-02 20:03
2
2
 
3
3
  import django.db.models.deletion
4
4
  from django.db import migrations, models
@@ -22,6 +22,17 @@ class Migration(migrations.Migration):
22
22
  'verbose_name_plural': 'النطاقات',
23
23
  },
24
24
  ),
25
+ migrations.CreateModel(
26
+ name='ScopeSettings',
27
+ fields=[
28
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
29
+ ('is_enabled', models.BooleanField(default=False, verbose_name='تفعيل النطاقات')),
30
+ ],
31
+ options={
32
+ 'verbose_name': 'إعدادات النطاق',
33
+ 'verbose_name_plural': 'إعدادات النطاق',
34
+ },
35
+ ),
25
36
  migrations.AlterModelOptions(
26
37
  name='customuser',
27
38
  options={'permissions': [('manage_staff', 'صلاحية إنشاء مسؤول')], 'verbose_name': 'مستخدم', 'verbose_name_plural': 'المستخدمين'},
@@ -14,6 +14,24 @@ class Scope(models.Model):
14
14
  class Meta:
15
15
  verbose_name = "نطاق"
16
16
  verbose_name_plural = "النطاقات"
17
+ class ScopeSettings(models.Model):
18
+ is_enabled = models.BooleanField(default=False, verbose_name="تفعيل النطاقات")
19
+
20
+ class Meta:
21
+ verbose_name = "إعدادات النطاق"
22
+ verbose_name_plural = "إعدادات النطاق"
23
+
24
+ def save(self, *args, **kwargs):
25
+ self.pk = 1
26
+ super(ScopeSettings, self).save(*args, **kwargs)
27
+
28
+ @classmethod
29
+ def load(cls):
30
+ obj, created = cls.objects.get_or_create(pk=1)
31
+ return obj
32
+
33
+ def __str__(self):
34
+ return "إعدادات النطاق"
17
35
 
18
36
  class CustomUser(AbstractUser):
19
37
  phone = models.CharField(max_length=15, blank=True, null=True, verbose_name="رقم الهاتف")