educommon 3.13.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.
Files changed (220) hide show
  1. educommon/__init__.py +0 -1
  2. educommon/about/ui/actions.py +16 -30
  3. educommon/about/ui/ui.py +3 -12
  4. educommon/about/utils.py +6 -5
  5. educommon/async_task/__init__.py +0 -1
  6. educommon/async_task/actions.py +18 -13
  7. educommon/async_task/apps.py +4 -0
  8. educommon/async_task/locker.py +2 -5
  9. educommon/async_task/migrations/0001_initial.py +55 -9
  10. educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
  11. educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
  12. educommon/async_task/models.py +9 -6
  13. educommon/async_task/tasks.py +11 -7
  14. educommon/async_task/ui.py +16 -35
  15. educommon/async_tasks/__init__.py +0 -1
  16. educommon/async_tasks/apps.py +4 -0
  17. educommon/async_tasks/locks.py +11 -21
  18. educommon/async_tasks/migrations/0001_initial.py +68 -8
  19. educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
  20. educommon/async_tasks/models.py +9 -29
  21. educommon/async_tasks/tasks.py +25 -54
  22. educommon/audit_log/__init__.py +1 -0
  23. educommon/audit_log/actions.py +27 -36
  24. educommon/audit_log/app_meta.py +7 -4
  25. educommon/audit_log/apps.py +44 -29
  26. educommon/audit_log/constants.py +7 -4
  27. educommon/audit_log/error_log/actions.py +1 -3
  28. educommon/audit_log/helpers.py +2 -4
  29. educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
  30. educommon/audit_log/migrations/0001_initial.py +91 -16
  31. educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
  32. educommon/audit_log/migrations/0003_logproxy.py +1 -3
  33. educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
  34. educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
  35. educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
  36. educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
  37. educommon/audit_log/migrations/0008_table_logged.py +0 -1
  38. educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
  39. educommon/audit_log/models.py +36 -42
  40. educommon/audit_log/permissions.py +11 -9
  41. educommon/audit_log/proxies.py +12 -23
  42. educommon/audit_log/ui.py +18 -15
  43. educommon/audit_log/utils/__init__.py +28 -60
  44. educommon/audit_log/utils/operations.py +16 -2
  45. educommon/auth/__init__.py +0 -3
  46. educommon/auth/rbac/__init__.py +2 -4
  47. educommon/auth/rbac/actions.py +148 -145
  48. educommon/auth/rbac/app_meta.py +9 -6
  49. educommon/auth/rbac/backends/base.py +2 -8
  50. educommon/auth/rbac/backends/caching.py +27 -37
  51. educommon/auth/rbac/backends/simple.py +1 -4
  52. educommon/auth/rbac/checker.py +1 -3
  53. educommon/auth/rbac/management/commands/rbac.py +6 -11
  54. educommon/auth/rbac/manager.py +18 -47
  55. educommon/auth/rbac/migrations/0001_initial.py +73 -12
  56. educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
  57. educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
  58. educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
  59. educommon/auth/rbac/models.py +63 -68
  60. educommon/auth/rbac/permissions.py +6 -7
  61. educommon/auth/rbac/ui.py +83 -84
  62. educommon/auth/rbac/utils.py +10 -11
  63. educommon/auth/rbac/validators.py +4 -5
  64. educommon/auth/simple_auth/__init__.py +1 -5
  65. educommon/auth/simple_auth/actions.py +79 -92
  66. educommon/auth/simple_auth/app_meta.py +2 -9
  67. educommon/auth/simple_auth/checkers.py +3 -3
  68. educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
  69. educommon/auth/simple_auth/validators.py +0 -1
  70. educommon/contingent/actions.py +7 -7
  71. educommon/contingent/app_meta.py +1 -4
  72. educommon/contingent/base.py +10 -15
  73. educommon/contingent/catalogs.py +424 -540
  74. educommon/contingent/contingent_plugin/actions.py +4 -15
  75. educommon/contingent/contingent_plugin/apps.py +10 -4
  76. educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
  77. educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
  78. educommon/contingent/contingent_plugin/model_views.py +2 -12
  79. educommon/contingent/contingent_plugin/models.py +2 -7
  80. educommon/contingent/contingent_plugin/observer.py +14 -13
  81. educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
  82. educommon/contingent/contingent_plugin/storage.py +8 -7
  83. educommon/contingent/contingent_plugin/utils.py +6 -6
  84. educommon/django/db/fields.py +72 -86
  85. educommon/django/db/migration/__init__.py +3 -7
  86. educommon/django/db/migration/operations.py +29 -51
  87. educommon/django/db/mixins/__init__.py +16 -10
  88. educommon/django/db/mixins/date_interval.py +47 -75
  89. educommon/django/db/mixins/validation.py +26 -26
  90. educommon/django/db/model_view/__init__.py +18 -22
  91. educommon/django/db/models.py +9 -8
  92. educommon/django/db/observer.py +9 -27
  93. educommon/django/db/partitioning/__init__.py +66 -92
  94. educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
  95. educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
  96. educommon/django/db/partitioning/management/commands/split_table.py +18 -13
  97. educommon/django/db/routers.py +6 -15
  98. educommon/django/db/signals.py +4 -2
  99. educommon/django/db/utils.py +14 -19
  100. educommon/django/db/validators/__init__.py +1 -0
  101. educommon/django/db/validators/simple.py +72 -100
  102. educommon/django/storages/atcfs/api.py +39 -53
  103. educommon/django/storages/atcfs/app_meta.py +1 -1
  104. educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
  105. educommon/django/storages/atcfs/models.py +0 -3
  106. educommon/django/storages/atcfs/monkey_patching.py +18 -12
  107. educommon/django/storages/atcfs/storage.py +14 -23
  108. educommon/extjs/fields/input_params.py +15 -45
  109. educommon/importer/XLSReader.py +143 -241
  110. educommon/importer/__init__.py +86 -4
  111. educommon/importer/api.py +53 -84
  112. educommon/importer/constants.py +4 -14
  113. educommon/importer/loggers.py +16 -26
  114. educommon/importer/proxy.py +131 -176
  115. educommon/importer/proxy_import.py +11 -12
  116. educommon/importer/report.py +4 -6
  117. educommon/importer/ui.py +32 -26
  118. educommon/importer/validators.py +4 -7
  119. educommon/integration_entities/helpers.py +14 -18
  120. educommon/ioc/__init__.py +3 -6
  121. educommon/logger/loggers.py +10 -14
  122. educommon/m3/__init__.py +20 -38
  123. educommon/m3/extensions/__init__.py +1 -0
  124. educommon/m3/extensions/listeners/__init__.py +22 -38
  125. educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
  126. educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
  127. educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
  128. educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
  129. educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
  130. educommon/m3/extensions/ui.py +15 -33
  131. educommon/m3/transaction_context.py +17 -19
  132. educommon/objectpack/actions.py +70 -88
  133. educommon/objectpack/apps.py +5 -0
  134. educommon/objectpack/filters.py +9 -15
  135. educommon/objectpack/ui.py +59 -77
  136. educommon/report/__init__.py +9 -5
  137. educommon/report/actions.py +29 -32
  138. educommon/report/constructor/__init__.py +5 -8
  139. educommon/report/constructor/app_meta.py +1 -3
  140. educommon/report/constructor/apps.py +1 -0
  141. educommon/report/constructor/base.py +33 -80
  142. educommon/report/constructor/builders/excel/_base.py +138 -286
  143. educommon/report/constructor/builders/excel/_header.py +2 -9
  144. educommon/report/constructor/builders/excel/product.py +13 -34
  145. educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
  146. educommon/report/constructor/config.py +2 -0
  147. educommon/report/constructor/editor/actions.py +101 -215
  148. educommon/report/constructor/editor/ui.py +71 -93
  149. educommon/report/constructor/exceptions.py +6 -12
  150. educommon/report/constructor/migrations/0001_initial.py +36 -44
  151. educommon/report/constructor/migrations/0002_report_filters.py +86 -72
  152. educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
  153. educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
  154. educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
  155. educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
  156. educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
  157. educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
  158. educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
  159. educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
  160. educommon/report/constructor/mixins.py +14 -15
  161. educommon/report/constructor/models.py +76 -124
  162. educommon/report/constructor/utils.py +3 -8
  163. educommon/report/constructor/validators.py +1 -3
  164. educommon/report/reporter.py +25 -43
  165. educommon/report/utils.py +14 -40
  166. educommon/rest/actions.py +7 -11
  167. educommon/rest/context.py +6 -16
  168. educommon/rest/controllers.py +10 -10
  169. educommon/rest/mixins.py +29 -27
  170. educommon/secure_media/app_meta.py +9 -9
  171. educommon/utils/__init__.py +3 -2
  172. educommon/utils/caching.py +1 -3
  173. educommon/utils/conversion.py +1 -3
  174. educommon/utils/crypto.py +1 -2
  175. educommon/utils/date.py +13 -26
  176. educommon/utils/db/__init__.py +17 -26
  177. educommon/utils/db/postgresql.py +1 -4
  178. educommon/utils/fonts/__init__.py +3 -4
  179. educommon/utils/licence/__init__.py +5 -16
  180. educommon/utils/misc.py +9 -18
  181. educommon/utils/object_grid.py +55 -62
  182. educommon/utils/phone_number/modelfields.py +1 -3
  183. educommon/utils/phone_number/phone_number.py +5 -8
  184. educommon/utils/phone_number/validators.py +8 -23
  185. educommon/utils/plugins.py +15 -28
  186. educommon/utils/registry.py +2 -1
  187. educommon/utils/seqtools.py +1 -3
  188. educommon/utils/serializer.py +9 -16
  189. educommon/utils/storage.py +3 -2
  190. educommon/utils/system.py +1 -3
  191. educommon/utils/system_app/management/commands/delete_objects.py +17 -34
  192. educommon/utils/ui.py +87 -84
  193. educommon/utils/xml/__init__.py +2 -7
  194. educommon/utils/xml/resolver.py +1 -0
  195. educommon/ws_log/actions.py +31 -76
  196. educommon/ws_log/base.py +6 -20
  197. educommon/ws_log/migrations/0001_initial.py +25 -8
  198. educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
  199. educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
  200. educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
  201. educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
  202. educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
  203. educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
  204. educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
  205. educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
  206. educommon/ws_log/models.py +21 -35
  207. educommon/ws_log/provider.py +2 -1
  208. educommon/ws_log/report.py +8 -13
  209. educommon/ws_log/smev/applications.py +12 -27
  210. educommon/ws_log/smev/exceptions.py +2 -3
  211. educommon/ws_log/ui.py +32 -32
  212. educommon/ws_log/utils.py +1 -3
  213. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/METADATA +26 -14
  214. educommon-3.13.2.dist-info/RECORD +354 -0
  215. educommon/utils/patches.py +0 -27
  216. educommon/version.conf +0 -11
  217. educommon-3.13.0.dist-info/RECORD +0 -357
  218. educommon-3.13.0.dist-info/dependency_links.txt +0 -1
  219. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +0 -0
  220. {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
@@ -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, null=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
- super(Role, self).simple_clean(errors)
165
+ """Проверка бизнес-логики роли.
165
166
 
166
- if (self.pk and not self.can_be_assigned and
167
- self.userrole_set.exists()):
168
- errors['can_be_assigned'].append(
169
- 'Есть пользователи, которым назначана роль "{}" '.format(
170
- self.name
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
- def safe_delete(self):
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
- super(RoleUserType, self).simple_clean(errors)
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
- ).exclude(
317
+ )
318
+ .exclude(
320
319
  id=instance.pk,
321
- ).exists() and
322
- instance.permission.name == PERM__ROLE__EDIT
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
- Role, related_name='+', on_delete=models.CASCADE
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
- super(RoleParent, self).simple_clean(errors)
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), str(self.role),
417
+ str(self.user),
418
+ str(self.role),
423
419
  )
424
420
 
425
- def interval_intersected_error_message(self, others=None):
426
- return (
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
- super(UserRole, self).simple_clean(errors)
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 and
443
- self.role_id and
444
- self.content_type_id and
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
- (PERM__ROLE__EDIT,
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(RolesTree, self).__init__(*args, **kwargs)
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
- self.top_bar.button_delete_from_role,
110
- self.top_bar.button_delete,
111
- ))
112
- self.top_bar.delete_menu = ExtToolbarMenu(
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
- self.top_bar.add_menu
123
- )
124
- self.new_child_index = self.top_bar.add_menu.menu.items.index(
125
- self.top_bar.button_new_child
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
- super(RolesListWindow, self)._init_components()
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
- super(RolesListWindow, self).set_params(params)
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
- super(RoleSelectWindow, self)._init_components()
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
- super(RoleSelectWindow, self)._do_layout()
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
- super(RoleSelectWindow, self).set_params(params)
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
- mark_safe(self.label_message.text.format(params['role'].name))
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
- super(PermissionsChangeTab, self).init_components(win)
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
- super(PermissionsChangeTab, self).do_layout(win, tab)
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
- super(PermissionsChangeTab, self).set_params(win, params)
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(ResultPermissionsTree, self).__init__()
347
-
348
- ColumnsConstructor.from_config((
349
- dict(
350
- data_index='title',
351
- header='Наименование',
352
- ),
353
- dict(
354
- data_index='description',
355
- hidden=True,
356
- ),
357
- dict(
358
- data_index='source',
359
- header='Источник',
360
- ),
361
- )).configure_grid(self)
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
- super(ResultPermissionsTab, self).init_components(win)
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
- super(ResultPermissionsTab, self).do_layout(win, tab)
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
- self.tree__result_permissions,
401
- self.panel__description,
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
- super(RoleAddWindow, self)._init_components()
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
- super(RoleAddWindow, self)._do_layout()
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
- super(RoleAddWindow, self).set_params(params)
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
- super(RoleEditWindow, self).set_params(params)
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
  # -----------------------------------------------------------------------------