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.
Files changed (221) 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 +149 -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.2.dist-info/METADATA +57 -0
  214. educommon-3.13.2.dist-info/RECORD +354 -0
  215. {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +1 -1
  216. educommon/utils/patches.py +0 -27
  217. educommon/version.conf +0 -11
  218. educommon-3.12.0.dist-info/METADATA +0 -47
  219. educommon-3.12.0.dist-info/RECORD +0 -357
  220. educommon-3.12.0.dist-info/dependency_links.txt +0 -1
  221. {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  """Паки и экшены для окна реестра "Роли"."""
2
+
2
3
  import json
3
4
  from collections import (
4
5
  defaultdict,
@@ -101,12 +102,11 @@ from educommon.m3 import (
101
102
 
102
103
 
103
104
  def _get_role(role_id):
105
+ """Возвращает объект роли по ID или выбрасывает исключение."""
104
106
  try:
105
107
  return Role.objects.get(pk=role_id)
106
108
  except Role.DoesNotExist:
107
- raise ApplicationLogicException(
108
- 'Роль ID:{} не существует'.format(role_id)
109
- )
109
+ raise ApplicationLogicException('Роль ID:{} не существует'.format(role_id))
110
110
 
111
111
 
112
112
  class RolesTreeRowsAction(ObjectRowsAction):
@@ -143,14 +143,15 @@ class RolesTreeRowsAction(ObjectRowsAction):
143
143
 
144
144
  def prepare_object(self, obj):
145
145
  """Сохранение данных роли в словарь перед сериализацией в JSON."""
146
- data = super(RolesTreeRowsAction, self).prepare_object(obj)
146
+ data = super().prepare_object(obj)
147
147
 
148
148
  data['leaf'] = self.is_leaf(obj)
149
149
 
150
150
  return data
151
151
 
152
152
  def run(self, *args, **kwargs):
153
- result = super(RolesTreeRowsAction, self).run(*args, **kwargs)
153
+ """Тело Action, вызывается при обработке запроса к серверу."""
154
+ result = super().run(*args, **kwargs)
154
155
 
155
156
  data = result.data.get('rows', [])
156
157
 
@@ -161,10 +162,15 @@ class AddRoleToRoleWindowAction(ObjectSelectWindowAction):
161
162
  """Отображение окна добавления одной роли в другую."""
162
163
 
163
164
  def create_window(self):
165
+ """Метод инстанцирует окно."""
164
166
  self.win = ui.RoleSelectWindow()
165
167
 
166
168
  def set_window_params(self):
167
- super(AddRoleToRoleWindowAction, self).set_window_params()
169
+ """Метод заполняет словарь self.win_params, который будет передан в окно.
170
+
171
+ Этот словарь выступает как шина передачи данных от Actions/Packs к окну.
172
+ """
173
+ super().set_window_params()
168
174
 
169
175
  self.win_params['pack'] = self.parent
170
176
 
@@ -178,6 +184,7 @@ class AddRoleToRoleAction(BaseAction):
178
184
 
179
185
  @convert_validation_error_to(ApplicationLogicException)
180
186
  def run(self, request, context):
187
+ """Тело Action, вызывается при обработке запроса к серверу."""
181
188
  role_parent = RoleParent(
182
189
  role=_get_role(getattr(context, self.parent.id_param_name)),
183
190
  parent=_get_role(context.parent_id),
@@ -192,15 +199,13 @@ class DeleteRoleFromRoleAction(BaseAction):
192
199
  """Удаление одной роли из другой."""
193
200
 
194
201
  def run(self, request, context):
202
+ """Тело Action, вызывается при обработке запроса к серверу."""
195
203
  try:
196
204
  role_parent = RoleParent.objects.get(
197
- role=_get_role(getattr(context, self.parent.id_param_name)),
198
- parent_id=context.parent_id
205
+ role=_get_role(getattr(context, self.parent.id_param_name)), parent_id=context.parent_id
199
206
  )
200
207
  except RoleParent.DoesNotExist:
201
- raise ApplicationLogicException(
202
- 'Выбранная роль должна являться вложенной ролью.'
203
- )
208
+ raise ApplicationLogicException('Выбранная роль должна являться вложенной ролью.')
204
209
 
205
210
  role_parent.delete()
206
211
 
@@ -228,7 +233,7 @@ class Pack(TreeObjectPack):
228
233
  column_name_on_select = 'name'
229
234
 
230
235
  def __init__(self):
231
- super(Pack, self).__init__()
236
+ super().__init__()
232
237
 
233
238
  self.replace_action('rows_action', RolesTreeRowsAction())
234
239
 
@@ -236,30 +241,36 @@ class Pack(TreeObjectPack):
236
241
  self.add_role_to_role_action = AddRoleToRoleAction()
237
242
  self.delete_role_from_role_action = DeleteRoleFromRoleAction()
238
243
 
239
- self.actions.extend((
240
- self.add_role_to_role_window_action,
241
- self.add_role_to_role_action,
242
- self.delete_role_from_role_action,
243
- ))
244
+ self.actions.extend(
245
+ (
246
+ self.add_role_to_role_window_action,
247
+ self.add_role_to_role_action,
248
+ self.delete_role_from_role_action,
249
+ )
250
+ )
244
251
  # ---------------------------------------------------------------------
245
252
  # Настройка разрешений для экшенов пака.
246
253
  self.need_check_permission = True
247
254
  self.perm_code = PERM_GROUP__ROLE
248
255
 
249
- for action in (self.autocomplete_action,
250
- self.list_window_action,
251
- self.multi_select_window_action,
252
- self.rows_action,
253
- self.select_window_action,
254
- self.edit_window_action):
256
+ for action in (
257
+ self.autocomplete_action,
258
+ self.list_window_action,
259
+ self.multi_select_window_action,
260
+ self.rows_action,
261
+ self.select_window_action,
262
+ self.edit_window_action,
263
+ ):
255
264
  action.perm_code = 'view'
256
265
 
257
- for action in (self.new_window_action,
258
- self.save_action,
259
- self.delete_action,
260
- self.add_role_to_role_window_action,
261
- self.add_role_to_role_action,
262
- self.delete_role_from_role_action):
266
+ for action in (
267
+ self.new_window_action,
268
+ self.save_action,
269
+ self.delete_action,
270
+ self.add_role_to_role_window_action,
271
+ self.add_role_to_role_action,
272
+ self.delete_role_from_role_action,
273
+ ):
263
274
  action.perm_code = 'edit'
264
275
  # ---------------------------------------------------------------------
265
276
 
@@ -270,11 +281,10 @@ class Pack(TreeObjectPack):
270
281
  )
271
282
 
272
283
  def declare_context(self, action):
273
- result = super(Pack, self).declare_context(action)
284
+ """Декларирует контекст для экшна."""
285
+ result = super().declare_context(action)
274
286
 
275
- if action in (self.rows_action,
276
- self.add_role_to_role_window_action,
277
- self.add_role_to_role_action):
287
+ if action in (self.rows_action, self.add_role_to_role_window_action, self.add_role_to_role_action):
278
288
  result[self.id_param_name] = dict(type='int')
279
289
 
280
290
  if action is self.rows_action:
@@ -297,27 +307,22 @@ class Pack(TreeObjectPack):
297
307
  return result
298
308
 
299
309
  def get_rows_query(self, request, context):
310
+ """Возвращает выборку из БД для получения списка данных."""
300
311
  request_params = get_request_params(request)
301
312
  if request_params.get('filter'):
302
- return super(Pack, self).get_rows_query(request, context)
313
+ return super().get_rows_query(request, context)
303
314
 
304
315
  current_role_id = getattr(context, self.id_param_name)
305
316
 
306
317
  if request_params.get('filter', False):
307
- result = super(Pack, self).get_rows_query(
308
- request, context
309
- )
318
+ result = super().get_rows_query(request, context)
310
319
  elif current_role_id < 0:
311
320
  # Вывод корневых ролей
312
- result = self.model.objects.exclude(
313
- pk__in=RoleParent.objects.values('role').distinct()
314
- )
321
+ result = self.model.objects.exclude(pk__in=RoleParent.objects.values('role').distinct())
315
322
  else:
316
323
  # Вывод ролей, вложенных в указанную роль
317
324
  result = self.model.objects.filter(
318
- pk__in=RoleParent.objects.filter(
319
- parent=current_role_id
320
- ).values('role').distinct()
325
+ pk__in=RoleParent.objects.filter(parent=current_role_id).values('role').distinct()
321
326
  )
322
327
 
323
328
  if context.select_mode and context.role_id is not None:
@@ -328,20 +333,15 @@ class Pack(TreeObjectPack):
328
333
  try:
329
334
  role = Role.objects.get(pk=context.role_id)
330
335
  except Role.DoesNotExist:
331
- raise ApplicationLogicException(
332
- 'Роль ID:{} не найдена'.format(context.role_id)
333
- )
336
+ raise ApplicationLogicException('Роль ID:{} не найдена'.format(context.role_id))
334
337
 
335
- result = result.exclude(
336
- pk__in=set([role.id]) | set(r.id for r in role.subroles)
337
- )
338
+ result = result.exclude(pk__in=set([role.id]) | set(r.id for r in role.subroles))
338
339
 
339
340
  return result
340
341
 
341
342
  def get_list_window_params(self, params, request, context):
342
- params = super(Pack, self).get_list_window_params(
343
- params, request, context
344
- )
343
+ """Возвращает словарь параметров, которые будут переданы окну списка."""
344
+ params = super().get_list_window_params(params, request, context)
345
345
 
346
346
  if not params['is_select_mode']:
347
347
  params['width'] = 700
@@ -352,9 +352,8 @@ class Pack(TreeObjectPack):
352
352
  return params
353
353
 
354
354
  def get_edit_window_params(self, params, request, context):
355
- params = super(Pack, self).get_edit_window_params(
356
- params, request, context
357
- )
355
+ """Возвращает словарь параметров, которые будут переданы окну редактирования."""
356
+ params = super().get_edit_window_params(params, request, context)
358
357
 
359
358
  params['roles_pack'] = self
360
359
  params['partitions_pack'] = get_pack(PartitionsPack)
@@ -368,21 +367,13 @@ class Pack(TreeObjectPack):
368
367
  params['show_user_types'] = True
369
368
  params['user_types'] = tuple(
370
369
  (u_type.id, u_type.name)
371
- for u_type in (
372
- ContentType.objects.get_for_models(
373
- *rbac_config.user_types
374
- ).values()
375
- )
370
+ for u_type in (ContentType.objects.get_for_models(*rbac_config.user_types).values())
376
371
  )
377
372
  if not params['create_new']:
378
- params['user_type_ids'] = tuple(
379
- params['object'].user_types.values_list('pk', flat=True)
380
- )
373
+ params['user_type_ids'] = tuple(params['object'].user_types.values_list('pk', flat=True))
381
374
 
382
375
  if not params['create_new']:
383
- params['permission_ids'] = list(
384
- params['object'].permissions.values_list('pk', flat=True)
385
- )
376
+ params['permission_ids'] = list(params['object'].permissions.values_list('pk', flat=True))
386
377
 
387
378
  params['can_edit'] = rbac.has_access(self.save_action, request)
388
379
  if not params['can_edit']:
@@ -413,33 +404,25 @@ class Pack(TreeObjectPack):
413
404
  )
414
405
  # Проверка, есть ли пользователи с удаляемыми типами
415
406
  if types_to_delete and user_roles_to_delete.exists():
416
- related_content_types = ContentType.objects.filter(
417
- pk__in=types_to_delete
418
- )
407
+ related_content_types = ContentType.objects.filter(pk__in=types_to_delete)
419
408
  raise ApplicationLogicException(
420
409
  'Невозможно отменить назначение роли для пользователей '
421
410
  'типа {}, т.к. данная роль уже назначена {} '
422
411
  'пользователей.'.format(
423
- ', '.join(
424
- '"{}"'.format(ct.name) for ct in related_content_types
425
- ),
426
- 'этому типу'
427
- if len(types_to_delete) == 1 else 'этим типам',
412
+ ', '.join('"{}"'.format(ct.name) for ct in related_content_types),
413
+ 'этому типу' if len(types_to_delete) == 1 else 'этим типам',
428
414
  )
429
415
  )
430
416
  # Удаление лишних типов пользователей
431
- RoleUserType.objects.filter(
432
- role=role, user_type__in=types_to_delete
433
- ).delete()
417
+ RoleUserType.objects.filter(role=role, user_type__in=types_to_delete).delete()
434
418
  # Добавление новых типов пользователей
435
419
  for user_type_id in new_user_types - old_user_types:
436
- RoleUserType.objects.create(
437
- role=role, user_type_id=user_type_id
438
- )
420
+ RoleUserType.objects.create(role=role, user_type_id=user_type_id)
439
421
 
440
422
  @convert_validation_error_to(ValidationError)
441
423
  @atomic
442
424
  def save_row(self, obj, create_new, request, context):
425
+ """Сохраняет объект."""
443
426
  # При отключении флага удаляются все связи с типами пользователей
444
427
  if not (create_new or obj.can_be_assigned):
445
428
  RoleUserType.objects.filter(role=obj).delete()
@@ -454,9 +437,7 @@ class Pack(TreeObjectPack):
454
437
  try:
455
438
  parent = Role.objects.get(pk=context.parent_id)
456
439
  except Role.DoesNotExist:
457
- raise ApplicationLogicException(
458
- 'Роль ID:{} не существует.'.format(context.parent_id)
459
- )
440
+ raise ApplicationLogicException('Роль ID:{} не существует.'.format(context.parent_id))
460
441
 
461
442
  RoleParent.objects.create(role=obj, parent=parent)
462
443
  else:
@@ -472,9 +453,7 @@ class Pack(TreeObjectPack):
472
453
 
473
454
  # Добавление новых прав в роль
474
455
  for permission_id in new_permissions - old_permissions:
475
- RolePermission.objects.get_or_create(
476
- role=obj, permission_id=permission_id
477
- )
456
+ RolePermission.objects.get_or_create(role=obj, permission_id=permission_id)
478
457
 
479
458
 
480
459
  class Partition(VirtualModel):
@@ -488,6 +467,12 @@ class Partition(VirtualModel):
488
467
 
489
468
  @classmethod
490
469
  def _get_ids(cls):
470
+ """Метод получения ID и названий разделов системы.
471
+
472
+ Метод возвращает iterable, или callable, возвращаюший iterable,
473
+ для каждого элемента которого (iterable) будет инстанцирован объект класса
474
+ (каждый эл-т итератора передаётся в конструктор).
475
+ """
491
476
  if not hasattr(cls, 'data'):
492
477
  cls.data = []
493
478
  for i, title in enumerate(sorted(rbac.partitions)):
@@ -514,7 +499,7 @@ class PartitionsPack(ObjectPack):
514
499
  allow_paging = False
515
500
 
516
501
  def __init__(self):
517
- super(PartitionsPack, self).__init__()
502
+ super().__init__()
518
503
  # ---------------------------------------------------------------------
519
504
 
520
505
  self.need_check_permission = True
@@ -552,18 +537,17 @@ class PermissionsPack(ObjectPack):
552
537
  allow_paging = False
553
538
 
554
539
  def __init__(self):
555
- super(PermissionsPack, self).__init__()
556
- # ---------------------------------------------------------------------
540
+ super().__init__()
557
541
 
558
542
  self.need_check_permission = True
559
543
  self.perm_code = PERM_GROUP__ROLE
560
544
 
561
545
  for action in self.actions:
562
546
  action.perm_code = 'view'
563
- # ---------------------------------------------------------------------
564
547
 
565
548
  def declare_context(self, action):
566
- result = super(PermissionsPack, self).declare_context(action)
549
+ """Декларирует контекст для экшна"""
550
+ result = super().declare_context(action)
567
551
 
568
552
  if action is self.rows_action:
569
553
  result['partition_id'] = dict(type='int')
@@ -571,70 +555,71 @@ class PermissionsPack(ObjectPack):
571
555
  return result
572
556
 
573
557
  def prepare_row(self, obj, request, context):
574
- result = super(PermissionsPack, self).prepare_row(
575
- obj, request, context
576
- )
558
+ """Установка дополнительных атрибутов объекта."""
559
+ result = super().prepare_row(obj, request, context)
577
560
 
578
- permission_names = (
579
- rbac.get_dependent_permissions(obj.name) - rbac.hidden_permissions
561
+ permission_names = rbac.get_dependent_permissions(obj.name) - rbac.hidden_permissions
562
+ result.dependencies = json.dumps(
563
+ sorted(get_permission_full_title(dependency) for dependency in permission_names)
580
564
  )
581
- result.dependencies = json.dumps(sorted(
582
- get_permission_full_title(dependency)
583
- for dependency in permission_names
584
- ))
585
565
 
586
566
  return result
587
567
 
588
568
  def get_rows_query(self, request, context):
569
+ """Возвращает выборку из БД для получения списка данных."""
589
570
  # Определение название раздела по его id.
590
571
  try:
591
- partition = PartitionsPack.model.objects.get(
592
- id=context.partition_id
593
- ).title
572
+ partition = PartitionsPack.model.objects.get(id=context.partition_id).title
594
573
  except PartitionsPack.model.DoesNotExists:
595
- raise ApplicationLogicException(
596
- 'Раздел {} не существует'.format(context.partition_id)
574
+ raise ApplicationLogicException('Раздел {} не существует'.format(context.partition_id))
575
+
576
+ query = (
577
+ super()
578
+ .get_rows_query(request, context)
579
+ .filter(
580
+ # Условия для выборки разрешений только из раздела partition.
581
+ reduce(or_, (Q(name__startswith=code + '/') for code in rbac.partitions[partition])),
582
+ hidden=False,
597
583
  )
598
-
599
- query = super(PermissionsPack, self).get_rows_query(
600
- request, context
601
- ).filter(
602
- # Условия для выборки разрешений только из раздела partition.
603
- reduce(or_, (
604
- Q(name__startswith=code + '/')
605
- for code in rbac.partitions[partition]
606
- )),
607
- hidden=False,
608
- ).annotate(title_with_group=Case(
609
- # Добавление названия группы к названию разрешения.
610
- output_field=CharField(),
611
- *(
612
- When(
613
- name__startswith=group + '/',
614
- then=Concat(
615
- Value(title + ' - ' if title else ''),
616
- F('title'),
617
- )
584
+ .annotate(
585
+ title_with_group=Case(
586
+ # Добавление названия группы к названию разрешения.
587
+ output_field=CharField(),
588
+ *(
589
+ When(
590
+ name__startswith=group + '/',
591
+ then=Concat(
592
+ Value(title + ' - ' if title else ''),
593
+ F('title'),
594
+ ),
595
+ )
596
+ for group, title in rbac.groups.items()
597
+ ),
618
598
  )
619
- for group, title in rbac.groups.items()
620
599
  )
621
- ))
600
+ )
622
601
 
623
602
  return query
603
+
604
+
624
605
  # -----------------------------------------------------------------------------
625
606
 
607
+
626
608
  def _get_group_name(perm_name):
627
609
  """Возвращает имя группы разрешения."""
628
610
  return perm_name.split('/')[0]
629
611
 
612
+
630
613
  def _get_group_title(perm_name):
631
614
  """Возвращает название группы разрешений."""
632
615
  group_name = _get_group_name(perm_name)
633
616
  group_title = rbac.groups[group_name]
617
+
634
618
  return group_title
635
619
 
636
620
 
637
621
  def _get_partition_title(perm_name):
622
+ """Возвращает название раздела, к которому относится разрешение."""
638
623
  group_name = perm_name.split('/')[0]
639
624
 
640
625
  for title, names in rbac.partitions.items():
@@ -648,6 +633,10 @@ class ResultPermissionsAction(BaseAction):
648
633
  """Возвращает данные для грида "Итоговые разрешения"."""
649
634
 
650
635
  def _get_nested_roles(self, role_id):
636
+ """Возвращает все вложенные роли для заданной роли.
637
+
638
+ Строит рекурсивное множество дочерних ролей, включая вложенные на любой глубине.
639
+ """
651
640
  role_children = defaultdict(set)
652
641
  query = RoleParent.objects.values_list('parent', 'role')
653
642
 
@@ -667,10 +656,9 @@ class ResultPermissionsAction(BaseAction):
667
656
  return get_nested_roles(role_id)
668
657
 
669
658
  def _get_nested_roles_permissions(self, role_id):
659
+ """Возвращает разрешения, назначенные вложенным ролям заданной роли."""
670
660
  query = Permission.objects.filter(
671
- pk__in=RolePermission.objects.filter(
672
- role_id__in=self._get_nested_roles(role_id)
673
- ).values('permission'),
661
+ pk__in=RolePermission.objects.filter(role_id__in=self._get_nested_roles(role_id)).values('permission'),
674
662
  hidden=False,
675
663
  ).values_list('name', 'title', 'description')
676
664
 
@@ -685,17 +673,19 @@ class ResultPermissionsAction(BaseAction):
685
673
  )
686
674
 
687
675
  def _get_dependent_permissions(self, permission_ids):
676
+ """Возвращает разрешения, от которых зависят указанные разрешения.
677
+
678
+ Исключает скрытые разрешения и формирует структуру для отображения
679
+ в интерфейсе.
680
+ """
688
681
  permissions_by_id = {
689
682
  pk: (name, title, description)
690
683
  for pk, name, title, description in Permission.objects.filter(
691
684
  hidden=False,
692
- ).values_list(
693
- 'pk', 'name', 'title', 'description'
694
- )
685
+ ).values_list('pk', 'name', 'title', 'description')
695
686
  }
696
687
  permissions_by_name = {
697
- name: (pk, title, description)
698
- for pk, (name, title, description) in permissions_by_id.items()
688
+ name: (pk, title, description) for pk, (name, title, description) in permissions_by_id.items()
699
689
  }
700
690
 
701
691
  for perm_id in permission_ids:
@@ -719,6 +709,7 @@ class ResultPermissionsAction(BaseAction):
719
709
  )
720
710
 
721
711
  def _get_role_permissions(self, permission_ids):
712
+ """Возвращает основные разрешения, явно назначенные роли."""
722
713
  query = Permission.objects.filter(
723
714
  pk__in=permission_ids,
724
715
  hidden=False,
@@ -736,6 +727,15 @@ class ResultPermissionsAction(BaseAction):
736
727
  )
737
728
 
738
729
  def run(self, request, context):
730
+ """Обрабатывает запрос на получение итоговых разрешений роли.
731
+
732
+ Комбинирует разрешения:
733
+ - явно назначенные роли;
734
+ - зависимые разрешения;
735
+ - разрешения вложенных ролей.
736
+
737
+ Возвращает данные, сгруппированные по разделам и группам.
738
+ """
739
739
  perm_names = set()
740
740
 
741
741
  data = defaultdict(lambda: defaultdict(list))
@@ -751,11 +751,13 @@ class ResultPermissionsAction(BaseAction):
751
751
  partition_title = perm_data['partition']
752
752
  group_title = perm_data['group']
753
753
 
754
- data[partition_title][group_title].append(dict(
755
- title=perm_data['title'],
756
- description=perm_data['description'],
757
- source=perm_data['source'],
758
- ))
754
+ data[partition_title][group_title].append(
755
+ dict(
756
+ title=perm_data['title'],
757
+ description=perm_data['description'],
758
+ source=perm_data['source'],
759
+ )
760
+ )
759
761
 
760
762
  return PreJsonResult(data)
761
763
 
@@ -764,14 +766,12 @@ class ResultPermissionsPack(BasePack):
764
766
  """Набор действий для грида "Итоговые разрешения" окна редактирования."""
765
767
 
766
768
  def __init__(self):
767
- super(ResultPermissionsPack, self).__init__()
769
+ super().__init__()
768
770
  # ---------------------------------------------------------------------
769
771
 
770
772
  self.result_permissions_action = ResultPermissionsAction()
771
773
 
772
- self.actions.extend((
773
- self.result_permissions_action,
774
- ))
774
+ self.actions.extend((self.result_permissions_action,))
775
775
  # ---------------------------------------------------------------------
776
776
 
777
777
  self.need_check_permission = True
@@ -782,11 +782,14 @@ class ResultPermissionsPack(BasePack):
782
782
  # ---------------------------------------------------------------------
783
783
 
784
784
  def declare_context(self, action):
785
- result = super(ResultPermissionsPack, self).declare_context(action)
785
+ """Декларация контекста для экшна."""
786
+ result = super().declare_context(action)
786
787
 
787
788
  if action is self.result_permissions_action:
788
789
  result[get_pack_id(Pack)] = dict(type='int_or_none', default=None)
789
790
  result['role_permissions'] = dict(type='int_list', default=())
790
791
 
791
792
  return result
793
+
794
+
792
795
  # -----------------------------------------------------------------------------
@@ -1,4 +1,5 @@
1
1
  """Инициализация приложения в M3."""
2
+
2
3
  from educommon import (
3
4
  ioc,
4
5
  )
@@ -9,9 +10,11 @@ from educommon.auth.rbac import (
9
10
 
10
11
  def register_actions():
11
12
  """Регистрация паков приложения в контроллере."""
12
- ioc.get('auth_controller').extend_packs((
13
- actions.Pack(),
14
- actions.PartitionsPack(),
15
- actions.PermissionsPack(),
16
- actions.ResultPermissionsPack(),
17
- ))
13
+ ioc.get('auth_controller').extend_packs(
14
+ (
15
+ actions.Pack(),
16
+ actions.PartitionsPack(),
17
+ actions.PermissionsPack(),
18
+ actions.ResultPermissionsPack(),
19
+ )
20
+ )
@@ -19,10 +19,7 @@ class BackendBase(metaclass=ABCMeta):
19
19
 
20
20
  :rtype: bool
21
21
  """
22
- return (
23
- action.parent.need_check_permission or
24
- action.need_check_permission
25
- )
22
+ return action.parent.need_check_permission or action.need_check_permission
26
23
 
27
24
  def _get_current_user(self, request):
28
25
  """Возвращает текущего пользователя.
@@ -37,10 +34,7 @@ class BackendBase(metaclass=ABCMeta):
37
34
  :rtype: tuple
38
35
  """
39
36
  if action.sub_permissions:
40
- result = tuple(
41
- action.get_perm_code(sub_perm)
42
- for sub_perm in action.sub_permissions
43
- )
37
+ result = tuple(action.get_perm_code(sub_perm) for sub_perm in action.sub_permissions)
44
38
  else:
45
39
  result = (action.get_perm_code(),)
46
40