educommon 3.12.0__py3-none-any.whl → 3.13.2__py3-none-any.whl
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.
- educommon/__init__.py +0 -1
- educommon/about/ui/actions.py +16 -30
- educommon/about/ui/ui.py +3 -12
- educommon/about/utils.py +6 -5
- educommon/async_task/__init__.py +0 -1
- educommon/async_task/actions.py +18 -13
- educommon/async_task/apps.py +4 -0
- educommon/async_task/locker.py +2 -5
- educommon/async_task/migrations/0001_initial.py +55 -9
- educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
- educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
- educommon/async_task/models.py +9 -6
- educommon/async_task/tasks.py +11 -7
- educommon/async_task/ui.py +16 -35
- educommon/async_tasks/__init__.py +0 -1
- educommon/async_tasks/apps.py +4 -0
- educommon/async_tasks/locks.py +11 -21
- educommon/async_tasks/migrations/0001_initial.py +68 -8
- educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
- educommon/async_tasks/models.py +9 -29
- educommon/async_tasks/tasks.py +25 -54
- educommon/audit_log/__init__.py +1 -0
- educommon/audit_log/actions.py +27 -36
- educommon/audit_log/app_meta.py +7 -4
- educommon/audit_log/apps.py +44 -29
- educommon/audit_log/constants.py +7 -4
- educommon/audit_log/error_log/actions.py +1 -3
- educommon/audit_log/helpers.py +2 -4
- educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
- educommon/audit_log/migrations/0001_initial.py +91 -16
- educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
- educommon/audit_log/migrations/0003_logproxy.py +1 -3
- educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
- educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
- educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
- educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
- educommon/audit_log/migrations/0008_table_logged.py +0 -1
- educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
- educommon/audit_log/models.py +36 -42
- educommon/audit_log/permissions.py +11 -9
- educommon/audit_log/proxies.py +12 -23
- educommon/audit_log/ui.py +18 -15
- educommon/audit_log/utils/__init__.py +28 -60
- educommon/audit_log/utils/operations.py +16 -2
- educommon/auth/__init__.py +0 -3
- educommon/auth/rbac/__init__.py +2 -4
- educommon/auth/rbac/actions.py +148 -145
- educommon/auth/rbac/app_meta.py +9 -6
- educommon/auth/rbac/backends/base.py +2 -8
- educommon/auth/rbac/backends/caching.py +27 -37
- educommon/auth/rbac/backends/simple.py +1 -4
- educommon/auth/rbac/checker.py +1 -3
- educommon/auth/rbac/management/commands/rbac.py +6 -11
- educommon/auth/rbac/manager.py +18 -47
- educommon/auth/rbac/migrations/0001_initial.py +73 -12
- educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
- educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
- educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
- educommon/auth/rbac/models.py +63 -68
- educommon/auth/rbac/permissions.py +6 -7
- educommon/auth/rbac/ui.py +83 -84
- educommon/auth/rbac/utils.py +10 -11
- educommon/auth/rbac/validators.py +4 -5
- educommon/auth/simple_auth/__init__.py +1 -5
- educommon/auth/simple_auth/actions.py +79 -92
- educommon/auth/simple_auth/app_meta.py +2 -9
- educommon/auth/simple_auth/checkers.py +3 -3
- educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
- educommon/auth/simple_auth/validators.py +0 -1
- educommon/contingent/actions.py +7 -7
- educommon/contingent/app_meta.py +1 -4
- educommon/contingent/base.py +10 -15
- educommon/contingent/catalogs.py +424 -540
- educommon/contingent/contingent_plugin/actions.py +4 -15
- educommon/contingent/contingent_plugin/apps.py +10 -4
- educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
- educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
- educommon/contingent/contingent_plugin/model_views.py +2 -12
- educommon/contingent/contingent_plugin/models.py +2 -7
- educommon/contingent/contingent_plugin/observer.py +14 -13
- educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
- educommon/contingent/contingent_plugin/storage.py +8 -7
- educommon/contingent/contingent_plugin/utils.py +6 -6
- educommon/django/db/fields.py +72 -86
- educommon/django/db/migration/__init__.py +3 -7
- educommon/django/db/migration/operations.py +29 -51
- educommon/django/db/mixins/__init__.py +16 -10
- educommon/django/db/mixins/date_interval.py +47 -75
- educommon/django/db/mixins/validation.py +26 -26
- educommon/django/db/model_view/__init__.py +18 -22
- educommon/django/db/models.py +9 -8
- educommon/django/db/observer.py +9 -27
- educommon/django/db/partitioning/__init__.py +66 -92
- educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
- educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
- educommon/django/db/partitioning/management/commands/split_table.py +18 -13
- educommon/django/db/routers.py +6 -15
- educommon/django/db/signals.py +149 -2
- educommon/django/db/utils.py +14 -19
- educommon/django/db/validators/__init__.py +1 -0
- educommon/django/db/validators/simple.py +72 -100
- educommon/django/storages/atcfs/api.py +39 -53
- educommon/django/storages/atcfs/app_meta.py +1 -1
- educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
- educommon/django/storages/atcfs/models.py +0 -3
- educommon/django/storages/atcfs/monkey_patching.py +18 -12
- educommon/django/storages/atcfs/storage.py +14 -23
- educommon/extjs/fields/input_params.py +15 -45
- educommon/importer/XLSReader.py +143 -241
- educommon/importer/__init__.py +86 -4
- educommon/importer/api.py +53 -84
- educommon/importer/constants.py +4 -14
- educommon/importer/loggers.py +16 -26
- educommon/importer/proxy.py +131 -176
- educommon/importer/proxy_import.py +11 -12
- educommon/importer/report.py +4 -6
- educommon/importer/ui.py +32 -26
- educommon/importer/validators.py +4 -7
- educommon/integration_entities/helpers.py +14 -18
- educommon/ioc/__init__.py +3 -6
- educommon/logger/loggers.py +10 -14
- educommon/m3/__init__.py +20 -38
- educommon/m3/extensions/__init__.py +1 -0
- educommon/m3/extensions/listeners/__init__.py +22 -38
- educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
- educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
- educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
- educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
- educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
- educommon/m3/extensions/ui.py +15 -33
- educommon/m3/transaction_context.py +17 -19
- educommon/objectpack/actions.py +70 -88
- educommon/objectpack/apps.py +5 -0
- educommon/objectpack/filters.py +9 -15
- educommon/objectpack/ui.py +59 -77
- educommon/report/__init__.py +9 -5
- educommon/report/actions.py +29 -32
- educommon/report/constructor/__init__.py +5 -8
- educommon/report/constructor/app_meta.py +1 -3
- educommon/report/constructor/apps.py +1 -0
- educommon/report/constructor/base.py +33 -80
- educommon/report/constructor/builders/excel/_base.py +138 -286
- educommon/report/constructor/builders/excel/_header.py +2 -9
- educommon/report/constructor/builders/excel/product.py +13 -34
- educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
- educommon/report/constructor/config.py +2 -0
- educommon/report/constructor/editor/actions.py +101 -215
- educommon/report/constructor/editor/ui.py +71 -93
- educommon/report/constructor/exceptions.py +6 -12
- educommon/report/constructor/migrations/0001_initial.py +36 -44
- educommon/report/constructor/migrations/0002_report_filters.py +86 -72
- educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
- educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
- educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
- educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
- educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
- educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
- educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
- educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
- educommon/report/constructor/mixins.py +14 -15
- educommon/report/constructor/models.py +76 -124
- educommon/report/constructor/utils.py +3 -8
- educommon/report/constructor/validators.py +1 -3
- educommon/report/reporter.py +25 -43
- educommon/report/utils.py +14 -40
- educommon/rest/actions.py +7 -11
- educommon/rest/context.py +6 -16
- educommon/rest/controllers.py +10 -10
- educommon/rest/mixins.py +29 -27
- educommon/secure_media/app_meta.py +9 -9
- educommon/utils/__init__.py +3 -2
- educommon/utils/caching.py +1 -3
- educommon/utils/conversion.py +1 -3
- educommon/utils/crypto.py +1 -2
- educommon/utils/date.py +13 -26
- educommon/utils/db/__init__.py +17 -26
- educommon/utils/db/postgresql.py +1 -4
- educommon/utils/fonts/__init__.py +3 -4
- educommon/utils/licence/__init__.py +5 -16
- educommon/utils/misc.py +9 -18
- educommon/utils/object_grid.py +55 -62
- educommon/utils/phone_number/modelfields.py +1 -3
- educommon/utils/phone_number/phone_number.py +5 -8
- educommon/utils/phone_number/validators.py +8 -23
- educommon/utils/plugins.py +15 -28
- educommon/utils/registry.py +2 -1
- educommon/utils/seqtools.py +1 -3
- educommon/utils/serializer.py +9 -16
- educommon/utils/storage.py +3 -2
- educommon/utils/system.py +1 -3
- educommon/utils/system_app/management/commands/delete_objects.py +17 -34
- educommon/utils/ui.py +87 -84
- educommon/utils/xml/__init__.py +2 -7
- educommon/utils/xml/resolver.py +1 -0
- educommon/ws_log/actions.py +31 -76
- educommon/ws_log/base.py +6 -20
- educommon/ws_log/migrations/0001_initial.py +25 -8
- educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
- educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
- educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
- educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
- educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
- educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
- educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
- educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
- educommon/ws_log/models.py +21 -35
- educommon/ws_log/provider.py +2 -1
- educommon/ws_log/report.py +8 -13
- educommon/ws_log/smev/applications.py +12 -27
- educommon/ws_log/smev/exceptions.py +2 -3
- educommon/ws_log/ui.py +32 -32
- educommon/ws_log/utils.py +1 -3
- educommon-3.13.2.dist-info/METADATA +57 -0
- educommon-3.13.2.dist-info/RECORD +354 -0
- {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +1 -1
- educommon/utils/patches.py +0 -27
- educommon/version.conf +0 -11
- educommon-3.12.0.dist-info/METADATA +0 -47
- educommon-3.12.0.dist-info/RECORD +0 -357
- educommon-3.12.0.dist-info/dependency_links.txt +0 -1
- {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
educommon/auth/rbac/models.py
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# pylint: disable=no-init
|
2
2
|
"""Модели для хранения данных системы авторизации RBAC."""
|
3
|
+
|
3
4
|
from django.contrib.contenttypes.models import (
|
4
5
|
ContentType,
|
5
6
|
)
|
6
7
|
from django.core.exceptions import (
|
7
8
|
NON_FIELD_ERRORS,
|
8
|
-
FieldDoesNotExist,
|
9
9
|
ValidationError,
|
10
10
|
)
|
11
11
|
from django.db import (
|
@@ -77,7 +77,8 @@ class Permission(BaseModel):
|
|
77
77
|
title = models.CharField(
|
78
78
|
'Название',
|
79
79
|
max_length=200,
|
80
|
-
blank=True,
|
80
|
+
blank=True,
|
81
|
+
null=True,
|
81
82
|
)
|
82
83
|
description = models.TextField(
|
83
84
|
'Описание',
|
@@ -161,17 +162,21 @@ class Role(CascadeDeleteMixin, BaseModel):
|
|
161
162
|
return result
|
162
163
|
|
163
164
|
def simple_clean(self, errors):
|
164
|
-
|
165
|
+
"""Проверка бизнес-логики роли.
|
165
166
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
Запрещает отключение флага `can_be_assigned`, если роль уже назначена пользователям.
|
168
|
+
"""
|
169
|
+
super().simple_clean(errors)
|
170
|
+
|
171
|
+
if self.pk and not self.can_be_assigned and self.userrole_set.exists():
|
172
|
+
errors['can_be_assigned'].append('Есть пользователи, которым назначана роль "{}" '.format(self.name))
|
173
|
+
|
174
|
+
def safe_delete(self) -> bool:
|
175
|
+
"""Безопасное удаление роли и связанных с ней связей.
|
173
176
|
|
174
|
-
|
177
|
+
Удаляет связи роли с разрешениями и родителями. Если возникает
|
178
|
+
ошибка целостности, возвращает False.
|
179
|
+
"""
|
175
180
|
# safe_delete неправильно работает внутри транзакций, из-за этого
|
176
181
|
# при вызове commit() валится IntegrityError, который надо обрабатывать
|
177
182
|
# вручную.
|
@@ -221,23 +226,22 @@ class RoleUserType(BaseModel):
|
|
221
226
|
verbose_name_plural = 'Типы пользователей ролей'
|
222
227
|
|
223
228
|
def simple_clean(self, errors):
|
224
|
-
|
229
|
+
"""Проверка соответствия типа пользователя и роли.
|
230
|
+
|
231
|
+
Запрещает назначение роли пользователям, если:
|
232
|
+
- роль не может быть назначена;
|
233
|
+
- тип пользователя не входит в допустимые типы.
|
234
|
+
"""
|
235
|
+
super().simple_clean(errors)
|
225
236
|
|
226
237
|
from educommon.auth.rbac.config import (
|
227
238
|
rbac_config,
|
228
239
|
)
|
229
240
|
|
230
241
|
if not self.role.can_be_assigned:
|
231
|
-
errors['role'].append(
|
232
|
-
'Роль "{}" не может назначаться пользователям'.format(
|
233
|
-
self.role.name
|
234
|
-
)
|
235
|
-
)
|
242
|
+
errors['role'].append('Роль "{}" не может назначаться пользователям'.format(self.role.name))
|
236
243
|
|
237
|
-
if (
|
238
|
-
rbac_config.user_types and
|
239
|
-
self.user_type.model_class() not in rbac_config.user_types
|
240
|
-
):
|
244
|
+
if rbac_config.user_types and self.user_type.model_class() not in rbac_config.user_types:
|
241
245
|
errors['role'].append(
|
242
246
|
'Роль "{}" не может быть назначена типу "{}".'.format(
|
243
247
|
self.role.name,
|
@@ -266,16 +270,11 @@ class RoleUserType(BaseModel):
|
|
266
270
|
|
267
271
|
if instance.user_types.exists():
|
268
272
|
errors[NON_FIELD_ERRORS].append(
|
269
|
-
'Для снятия флага "Может быть назначена пользователя", '
|
270
|
-
'необходимо отвязать все типы пользователей.'
|
273
|
+
'Для снятия флага "Может быть назначена пользователя", необходимо отвязать все типы пользователей.'
|
271
274
|
)
|
272
275
|
|
273
276
|
|
274
|
-
post_clean.connect(
|
275
|
-
receiver=RoleUserType.clean_role,
|
276
|
-
sender=Role,
|
277
|
-
dispatch_uid='RoleUserType.clean_role'
|
278
|
-
)
|
277
|
+
post_clean.connect(receiver=RoleUserType.clean_role, sender=Role, dispatch_uid='RoleUserType.clean_role')
|
279
278
|
|
280
279
|
|
281
280
|
class RolePermission(BaseModel):
|
@@ -302,8 +301,7 @@ class RolePermission(BaseModel):
|
|
302
301
|
db_table = 'rbac_role_permissions'
|
303
302
|
|
304
303
|
def __str__(self):
|
305
|
-
return 'Роль: {}; Разрешение: {}'.format(
|
306
|
-
self.role.name, self.permission.title)
|
304
|
+
return 'Роль: {}; Разрешение: {}'.format(self.role.name, self.permission.title)
|
307
305
|
|
308
306
|
|
309
307
|
@receiver(pre_delete, sender=RolePermission)
|
@@ -316,10 +314,12 @@ def protect_role_edit_permission(instance, **kwargs):
|
|
316
314
|
if (
|
317
315
|
not RolePermission.objects.filter(
|
318
316
|
permission__name=PERM__ROLE__EDIT,
|
319
|
-
)
|
317
|
+
)
|
318
|
+
.exclude(
|
320
319
|
id=instance.pk,
|
321
|
-
)
|
322
|
-
|
320
|
+
)
|
321
|
+
.exists()
|
322
|
+
and instance.permission.name == PERM__ROLE__EDIT
|
323
323
|
):
|
324
324
|
raise ApplicationLogicException(
|
325
325
|
'Роль "{role}" является единственной ролью в Cистеме, в которой '
|
@@ -327,8 +327,7 @@ def protect_role_edit_permission(instance, **kwargs):
|
|
327
327
|
'возможность настройки ролей, поэтому удаление из неё этого '
|
328
328
|
'разрешения невозможно. Для удаления разрешения "{permission}" '
|
329
329
|
'из роли "{role}" сначала назначьте данное разрешение любой '
|
330
|
-
'другой роли в системе.'
|
331
|
-
.format(
|
330
|
+
'другой роли в системе.'.format(
|
332
331
|
role=instance.role.name,
|
333
332
|
permission=get_permission_full_title(instance.permission.name),
|
334
333
|
)
|
@@ -338,25 +337,24 @@ def protect_role_edit_permission(instance, **kwargs):
|
|
338
337
|
class RoleParent(BaseModel):
|
339
338
|
"""M2M-модель "Вложенная роль"."""
|
340
339
|
|
341
|
-
parent = models.ForeignKey(
|
342
|
-
|
343
|
-
)
|
344
|
-
role = models.ForeignKey(
|
345
|
-
Role, related_name='+', on_delete=models.CASCADE
|
346
|
-
)
|
340
|
+
parent = models.ForeignKey(Role, related_name='+', on_delete=models.CASCADE)
|
341
|
+
role = models.ForeignKey(Role, related_name='+', on_delete=models.CASCADE)
|
347
342
|
|
348
343
|
cascade_delete_for = (parent, role)
|
349
344
|
display_related_error = False
|
350
345
|
|
351
346
|
def simple_clean(self, errors):
|
352
|
-
|
347
|
+
"""Валидация вложенности роли.
|
348
|
+
|
349
|
+
Проверяет:
|
350
|
+
- роль не может быть вложена сама в себя;
|
351
|
+
- отсутствие циклов в иерархии ролей.
|
352
|
+
"""
|
353
|
+
super().simple_clean(errors)
|
353
354
|
|
354
355
|
if self.parent.id == self.role.id:
|
355
|
-
errors['parent'].append(
|
356
|
-
'Роль не может содержать сама себя'
|
357
|
-
)
|
356
|
+
errors['parent'].append('Роль не может содержать сама себя')
|
358
357
|
|
359
|
-
# ---------------------------------------------------------------------
|
360
358
|
# Проверка отсутствия цикла
|
361
359
|
query = RoleParent.objects.all()
|
362
360
|
if self.pk:
|
@@ -373,12 +371,9 @@ class RoleParent(BaseModel):
|
|
373
371
|
check(self.role, self.parent)
|
374
372
|
except ValidationError as error:
|
375
373
|
errors['parent'].extend(error.messages)
|
376
|
-
# ---------------------------------------------------------------------
|
377
374
|
|
378
375
|
def __str__(self):
|
379
|
-
return 'RoleParent({} --> {})'.format(
|
380
|
-
str(self.role), str(self.parent)
|
381
|
-
)
|
376
|
+
return 'RoleParent({} --> {})'.format(str(self.role), str(self.parent))
|
382
377
|
|
383
378
|
class Meta:
|
384
379
|
unique_together = ('parent', 'role')
|
@@ -419,37 +414,37 @@ class UserRole(DateIntervalMixin, BaseModel, metaclass=UserRoleMeta):
|
|
419
414
|
|
420
415
|
def __str__(self):
|
421
416
|
return 'UserRole({} --> {})'.format(
|
422
|
-
str(self.user),
|
417
|
+
str(self.user),
|
418
|
+
str(self.role),
|
423
419
|
)
|
424
420
|
|
425
|
-
def interval_intersected_error_message(self, others=None):
|
426
|
-
|
427
|
-
|
428
|
-
'интервале дат.'.format(self.role.name)
|
429
|
-
)
|
421
|
+
def interval_intersected_error_message(self, others=None) -> str:
|
422
|
+
"""Сообщение об ошибке при пересечении интервалов действия роли."""
|
423
|
+
return 'Роль "{}" уже назначена этому пользователю в указанном интервале дат.'.format(self.role.name)
|
430
424
|
|
431
425
|
def simple_clean(self, errors):
|
432
|
-
|
426
|
+
"""Валидация бизнес-логики при назначении роли пользователю.
|
427
|
+
|
428
|
+
Проверяет:
|
429
|
+
- возможность назначения роли;
|
430
|
+
- доступность роли для указанного типа пользователя.
|
431
|
+
"""
|
432
|
+
super().simple_clean(errors)
|
433
433
|
|
434
434
|
if not self.role.can_be_assigned:
|
435
|
-
errors['role'].append(
|
436
|
-
'Роль "{}" не может быть назначена пользователю'.format(
|
437
|
-
self.role.name
|
438
|
-
)
|
439
|
-
)
|
435
|
+
errors['role'].append('Роль "{}" не может быть назначена пользователю'.format(self.role.name))
|
440
436
|
|
441
437
|
if (
|
442
|
-
config.rbac_config.user_types
|
443
|
-
self.role_id
|
444
|
-
self.content_type_id
|
445
|
-
not RoleUserType.objects.filter(
|
438
|
+
config.rbac_config.user_types
|
439
|
+
and self.role_id
|
440
|
+
and self.content_type_id
|
441
|
+
and not RoleUserType.objects.filter(
|
446
442
|
role_id=self.role_id,
|
447
443
|
user_type_id=self.content_type_id,
|
448
444
|
).exists()
|
449
445
|
):
|
450
446
|
errors['role'].append(
|
451
|
-
'Роль "{}" не доступна для назначения '
|
452
|
-
'пользователям типа "{}".'.format(
|
447
|
+
'Роль "{}" не доступна для назначения пользователям типа "{}".'.format(
|
453
448
|
self.role.name,
|
454
449
|
self.content_type.name,
|
455
450
|
)
|
@@ -6,13 +6,12 @@ PERM__ROLE__EDIT = PERM_ROLE_EDIT = PERM_GROUP__ROLE + '/edit'
|
|
6
6
|
|
7
7
|
|
8
8
|
permissions = (
|
9
|
-
(PERM__ROLE__VIEW,
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
'разрешения.'),
|
9
|
+
(PERM__ROLE__VIEW, 'Просмотр ролей', 'Разрешает просмотр имеющихся в системе ролей.'),
|
10
|
+
(
|
11
|
+
PERM__ROLE__EDIT,
|
12
|
+
'Редактирование ролей',
|
13
|
+
'Разрешает создавать/изменять/удалять роли и назначать ролям разрешения.',
|
14
|
+
),
|
16
15
|
)
|
17
16
|
# -----------------------------------------------------------------------------
|
18
17
|
|
educommon/auth/rbac/ui.py
CHANGED
@@ -79,7 +79,7 @@ class RolesTree(BaseObjectTree):
|
|
79
79
|
"""
|
80
80
|
|
81
81
|
def __init__(self, *args, **kwargs):
|
82
|
-
super(
|
82
|
+
super().__init__(*args, **kwargs)
|
83
83
|
|
84
84
|
# Меню "Добавить"
|
85
85
|
self.top_bar.button_add_to_role = ExtContextMenuItem(
|
@@ -87,9 +87,7 @@ class RolesTree(BaseObjectTree):
|
|
87
87
|
icon_cls='add_item',
|
88
88
|
handler='topBarAddToRole',
|
89
89
|
)
|
90
|
-
self.top_bar.add_menu.menu.items.append(
|
91
|
-
self.top_bar.button_add_to_role
|
92
|
-
)
|
90
|
+
self.top_bar.add_menu.menu.items.append(self.top_bar.button_add_to_role)
|
93
91
|
|
94
92
|
# Меню "Удалить"
|
95
93
|
self.top_bar.items.remove(self.top_bar.button_delete)
|
@@ -105,49 +103,43 @@ class RolesTree(BaseObjectTree):
|
|
105
103
|
)
|
106
104
|
|
107
105
|
menu = ExtContextMenu()
|
108
|
-
menu.items.extend(
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
icon_cls="delete_item",
|
114
|
-
menu=menu,
|
115
|
-
text='Удалить'
|
106
|
+
menu.items.extend(
|
107
|
+
(
|
108
|
+
self.top_bar.button_delete_from_role,
|
109
|
+
self.top_bar.button_delete,
|
110
|
+
)
|
116
111
|
)
|
112
|
+
self.top_bar.delete_menu = ExtToolbarMenu(icon_cls='delete_item', menu=menu, text='Удалить')
|
117
113
|
self.top_bar.items.append(self.top_bar.delete_menu)
|
118
114
|
|
119
115
|
# Передаем индексы, так как некорректно
|
120
116
|
# формируется client_id для данных элементов.
|
121
|
-
self.add_menu_index = self.top_bar.items.index(
|
122
|
-
|
123
|
-
)
|
124
|
-
self.
|
125
|
-
|
126
|
-
)
|
127
|
-
self.add_to_role_index = self.top_bar.add_menu.menu.items.index(
|
128
|
-
self.top_bar.button_add_to_role
|
129
|
-
)
|
130
|
-
self.delete_menu_index = self.top_bar.items.index(
|
131
|
-
self.top_bar.delete_menu
|
132
|
-
)
|
133
|
-
self.delete_from_role_index = menu.items.index(
|
134
|
-
self.top_bar.button_delete_from_role
|
135
|
-
)
|
117
|
+
self.add_menu_index = self.top_bar.items.index(self.top_bar.add_menu)
|
118
|
+
self.new_child_index = self.top_bar.add_menu.menu.items.index(self.top_bar.button_new_child)
|
119
|
+
self.add_to_role_index = self.top_bar.add_menu.menu.items.index(self.top_bar.button_add_to_role)
|
120
|
+
self.delete_menu_index = self.top_bar.items.index(self.top_bar.delete_menu)
|
121
|
+
self.delete_from_role_index = menu.items.index(self.top_bar.button_delete_from_role)
|
136
122
|
|
137
123
|
|
138
124
|
class RolesListWindow(BaseListWindow):
|
139
125
|
"""Окно для отображения иерархии ролей."""
|
140
126
|
|
141
127
|
def _init_components(self):
|
142
|
-
|
128
|
+
"""Метод создаёт визуальные компоненты, отражающие поля модели.
|
129
|
+
|
130
|
+
Не определяет расположение компонентов в окне.
|
131
|
+
"""
|
132
|
+
super()._init_components()
|
143
133
|
|
144
134
|
self.grid = RolesTree()
|
145
135
|
|
146
136
|
def set_params(self, params):
|
147
|
-
|
137
|
+
"""Метод принимает словарь, содержащий параметры окна, передаваемые в окно слоем экшенов."""
|
138
|
+
super().set_params(params)
|
139
|
+
|
148
140
|
template = 'rbac/roles-list-window.js'
|
149
141
|
self.pack = params['pack']
|
150
|
-
|
142
|
+
|
151
143
|
# Включение/отключение элементов окна в зависимости от прав доступа
|
152
144
|
if not params['can_edit']:
|
153
145
|
template = 'rbac/roles-view-list-window.js'
|
@@ -155,10 +147,7 @@ class RolesListWindow(BaseListWindow):
|
|
155
147
|
self.grid.action_new = None
|
156
148
|
|
157
149
|
# Отключение контролов для изменения ролей
|
158
|
-
for control in (
|
159
|
-
self.grid.top_bar.button_edit,
|
160
|
-
self.grid.context_menu_row.menuitem_edit
|
161
|
-
):
|
150
|
+
for control in (self.grid.top_bar.button_edit, self.grid.context_menu_row.menuitem_edit):
|
162
151
|
control.text = 'Просмотр'
|
163
152
|
control.icon_cls = Icons.APPLICATION_VIEW_DETAIL
|
164
153
|
|
@@ -166,7 +155,7 @@ class RolesListWindow(BaseListWindow):
|
|
166
155
|
self.grid.action_delete = None
|
167
156
|
self.grid.url_delete = None
|
168
157
|
self.grid.top_bar.items.remove(self.grid.top_bar.delete_menu)
|
169
|
-
|
158
|
+
|
170
159
|
self.template_globals = template
|
171
160
|
|
172
161
|
|
@@ -174,7 +163,8 @@ class RoleSelectWindow(BaseTreeSelectWindow):
|
|
174
163
|
"""Окно выбора роли, в которую будет добавлена указанная роль."""
|
175
164
|
|
176
165
|
def _init_components(self):
|
177
|
-
|
166
|
+
"""Создание компонентов."""
|
167
|
+
super()._init_components()
|
178
168
|
|
179
169
|
self.label_message = ExtLabel(
|
180
170
|
text='Выберите роль, в которую будет добавлена роль "{}":',
|
@@ -183,14 +173,16 @@ class RoleSelectWindow(BaseTreeSelectWindow):
|
|
183
173
|
)
|
184
174
|
|
185
175
|
def _do_layout(self):
|
186
|
-
|
176
|
+
"""Метод располагает уже созданные визуальные компоненты на окне."""
|
177
|
+
super()._do_layout()
|
187
178
|
|
188
179
|
self.layout = 'border'
|
189
180
|
|
190
181
|
self.items.insert(0, self.label_message)
|
191
182
|
|
192
183
|
def set_params(self, params):
|
193
|
-
|
184
|
+
"""Установка параметров окна."""
|
185
|
+
super().set_params(params)
|
194
186
|
|
195
187
|
self.title = 'Добавление одной роли в другую'
|
196
188
|
|
@@ -203,9 +195,9 @@ class RoleSelectWindow(BaseTreeSelectWindow):
|
|
203
195
|
self.grid.action_context = ActionContext()
|
204
196
|
self.grid.action_context.role_id = params['role'].id
|
205
197
|
|
206
|
-
self.label_message.text = (
|
207
|
-
|
208
|
-
|
198
|
+
self.label_message.text = mark_safe(self.label_message.text.format(params['role'].name))
|
199
|
+
|
200
|
+
|
209
201
|
# -----------------------------------------------------------------------------
|
210
202
|
|
211
203
|
|
@@ -216,7 +208,7 @@ def _make_user_type_field(name='user_type_ids', **kwargs):
|
|
216
208
|
hide_edit_trigger=False,
|
217
209
|
hide_trigger=False,
|
218
210
|
hide_dict_select_trigger=False,
|
219
|
-
**kwargs
|
211
|
+
**kwargs,
|
220
212
|
)
|
221
213
|
field.name = name
|
222
214
|
|
@@ -239,7 +231,8 @@ class PermissionsChangeTab(ObjectTab):
|
|
239
231
|
)
|
240
232
|
|
241
233
|
def init_components(self, win):
|
242
|
-
|
234
|
+
"""Создаются компоненты, но не задаётся расположение."""
|
235
|
+
super().init_components(win)
|
243
236
|
|
244
237
|
self.field__user_types = _make_user_type_field()
|
245
238
|
self.container__top = ExtPanel(
|
@@ -261,10 +254,10 @@ class PermissionsChangeTab(ObjectTab):
|
|
261
254
|
)
|
262
255
|
|
263
256
|
def do_layout(self, win, tab):
|
264
|
-
|
257
|
+
"""Задаётся расположение компонентов."""
|
258
|
+
super().do_layout(win, tab)
|
265
259
|
|
266
260
|
tab.border = False
|
267
|
-
# ---------------------------------------------------------------------
|
268
261
|
|
269
262
|
win.tab__permissions_change = tab
|
270
263
|
win.field__name = self.field__name
|
@@ -275,7 +268,6 @@ class PermissionsChangeTab(ObjectTab):
|
|
275
268
|
win.container__right = self.container__right
|
276
269
|
win.grid__permissions = self.grid__permissions
|
277
270
|
win.panel__description = self.panel__description
|
278
|
-
# ---------------------------------------------------------------------
|
279
271
|
|
280
272
|
self.container__top.items[:] = (
|
281
273
|
self.field__name,
|
@@ -291,7 +283,6 @@ class PermissionsChangeTab(ObjectTab):
|
|
291
283
|
self.grid__partitions,
|
292
284
|
self.container__right,
|
293
285
|
)
|
294
|
-
# ---------------------------------------------------------------------
|
295
286
|
|
296
287
|
tab.layout = 'border'
|
297
288
|
self.container__top.region = 'north'
|
@@ -312,19 +303,17 @@ class PermissionsChangeTab(ObjectTab):
|
|
312
303
|
self.panel__description.flex = 0
|
313
304
|
self.panel__description.height = 100
|
314
305
|
self.grid__permissions.flex = 1
|
315
|
-
# ---------------------------------------------------------------------
|
316
306
|
|
317
307
|
def set_params(self, win, params):
|
318
|
-
|
308
|
+
"""Установка параметров."""
|
309
|
+
super().set_params(win, params)
|
319
310
|
|
320
311
|
if params.get('show_user_types', False):
|
321
312
|
self.container__top.height += 45
|
322
313
|
self.container__top.label_width = 140
|
323
314
|
self.container__top.items.append(self.field__user_types)
|
324
315
|
|
325
|
-
self.field__user_types.set_store(
|
326
|
-
ExtDataStore(data=params['user_types'])
|
327
|
-
)
|
316
|
+
self.field__user_types.set_store(ExtDataStore(data=params['user_types']))
|
328
317
|
self.field__user_types.value = params.get('user_type_ids', ())
|
329
318
|
|
330
319
|
if params['can_edit']:
|
@@ -343,22 +332,24 @@ class ResultPermissionsTree(ExtTree):
|
|
343
332
|
"""
|
344
333
|
|
345
334
|
def __init__(self, *args, **kwargs):
|
346
|
-
super(
|
347
|
-
|
348
|
-
ColumnsConstructor.from_config(
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
335
|
+
super().__init__()
|
336
|
+
|
337
|
+
ColumnsConstructor.from_config(
|
338
|
+
(
|
339
|
+
dict(
|
340
|
+
data_index='title',
|
341
|
+
header='Наименование',
|
342
|
+
),
|
343
|
+
dict(
|
344
|
+
data_index='description',
|
345
|
+
hidden=True,
|
346
|
+
),
|
347
|
+
dict(
|
348
|
+
data_index='source',
|
349
|
+
header='Источник',
|
350
|
+
),
|
351
|
+
)
|
352
|
+
).configure_grid(self)
|
362
353
|
|
363
354
|
|
364
355
|
class ResultPermissionsTab(WindowTab):
|
@@ -378,7 +369,8 @@ class ResultPermissionsTab(WindowTab):
|
|
378
369
|
title = 'Итоговые разрешения'
|
379
370
|
|
380
371
|
def init_components(self, win):
|
381
|
-
|
372
|
+
"""Создаются компоненты, но не задаётся расположение."""
|
373
|
+
super().init_components(win)
|
382
374
|
|
383
375
|
self.tree__result_permissions = ResultPermissionsTree()
|
384
376
|
|
@@ -389,18 +381,19 @@ class ResultPermissionsTab(WindowTab):
|
|
389
381
|
)
|
390
382
|
|
391
383
|
def do_layout(self, win, tab):
|
392
|
-
|
393
|
-
|
384
|
+
"""Задаётся расположение компонентов."""
|
385
|
+
super().do_layout(win, tab)
|
394
386
|
|
395
387
|
win.tab__result_permissions = tab
|
396
388
|
tab.tree__result_permissions = self.tree__result_permissions
|
397
389
|
tab.panel__description = self.panel__description
|
398
390
|
|
399
|
-
tab.items.extend(
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
391
|
+
tab.items.extend(
|
392
|
+
(
|
393
|
+
self.tree__result_permissions,
|
394
|
+
self.panel__description,
|
395
|
+
)
|
396
|
+
)
|
404
397
|
|
405
398
|
tab.layout = 'vbox'
|
406
399
|
tab.layout_config = dict(
|
@@ -409,7 +402,6 @@ class ResultPermissionsTab(WindowTab):
|
|
409
402
|
self.tree__result_permissions.flex = 1
|
410
403
|
self.panel__description.flex = 0
|
411
404
|
self.panel__description.height = 100
|
412
|
-
# ---------------------------------------------------------------------
|
413
405
|
|
414
406
|
|
415
407
|
class RoleAddWindow(ModelEditWindow):
|
@@ -423,22 +415,26 @@ class RoleAddWindow(ModelEditWindow):
|
|
423
415
|
)
|
424
416
|
|
425
417
|
def _init_components(self):
|
426
|
-
|
418
|
+
"""Метод создаёт визуальные компоненты, отражающие поля модели.
|
419
|
+
|
420
|
+
Не определяет расположение компонентов в окне.
|
421
|
+
"""
|
422
|
+
super()._init_components()
|
427
423
|
self.field__user_types = _make_user_type_field()
|
428
424
|
|
429
425
|
def _do_layout(self):
|
430
|
-
|
426
|
+
"""Метод располагает уже созданные визуальные компоненты на окне."""
|
427
|
+
super()._do_layout()
|
431
428
|
self.form.items.append(self.field__user_types)
|
432
429
|
|
433
430
|
def set_params(self, params):
|
434
|
-
|
431
|
+
"""Метод принимает словарь, содержащий параметры окна, передаваемые в окно слоем экшенов."""
|
432
|
+
super().set_params(params)
|
435
433
|
|
436
434
|
self.template_globals = 'rbac/role-add-window.js'
|
437
435
|
|
438
436
|
if params.get('show_user_types', False):
|
439
|
-
self.field__user_types.set_store(
|
440
|
-
ExtDataStore(data=params['user_types'])
|
441
|
-
)
|
437
|
+
self.field__user_types.set_store(ExtDataStore(data=params['user_types']))
|
442
438
|
|
443
439
|
|
444
440
|
class RoleEditWindow(TabbedEditWindow):
|
@@ -452,7 +448,8 @@ class RoleEditWindow(TabbedEditWindow):
|
|
452
448
|
)
|
453
449
|
|
454
450
|
def set_params(self, params):
|
455
|
-
|
451
|
+
"""Метод принимает словарь, содержащий параметры окна, передаваемые в окно слоем экшенов."""
|
452
|
+
super().set_params(params)
|
456
453
|
|
457
454
|
self.width = 1100
|
458
455
|
self.height = 700
|
@@ -469,4 +466,6 @@ class RoleEditWindow(TabbedEditWindow):
|
|
469
466
|
|
470
467
|
if not params['can_edit']:
|
471
468
|
switch_window_in_read_only_mode(self)
|
469
|
+
|
470
|
+
|
472
471
|
# -----------------------------------------------------------------------------
|