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,4 +1,5 @@
1
1
  """Валидаторы для простых (текстовых, числовых и т.п.) полей модели Django."""
2
+
2
3
  import re
3
4
  from datetime import (
4
5
  datetime,
@@ -50,12 +51,13 @@ class SNILSValidator(RegexValidator):
50
51
  содержит значение, несоответствующее формату СНИЛС, либо контрольное
51
52
  число некорректно.
52
53
  """
54
+
53
55
  regex = _snils_re.pattern
54
56
  message = 'СНИЛС должен быть в формате ###-###-### ##'
55
57
  flags = _snils_re.flags
56
58
 
57
59
  def __call__(self, value):
58
- super(SNILSValidator, self).__call__(value)
60
+ super().__call__(value)
59
61
  snils_checksum_validator(value)
60
62
 
61
63
 
@@ -71,8 +73,7 @@ def snils_checksum_validator(value):
71
73
  if summa > 101:
72
74
  summa %= 101
73
75
 
74
- if (summa < 100 and summa != checksum or
75
- summa in (100, 101) and checksum != 0):
76
+ if summa < 100 and summa != checksum or summa in (100, 101) and checksum != 0:
76
77
  raise ValidationError('не пройдена проверка контрольного числа')
77
78
 
78
79
 
@@ -81,6 +82,7 @@ regex_snils_validator = SNILSValidator()
81
82
 
82
83
  # для совместимости со старым валидатором-функцией
83
84
  def snils_validator(value):
85
+ """Проверка корректности СНИЛС с помощью регулярного выражения и контрольной суммы."""
84
86
  value = str(value)
85
87
 
86
88
  regex_snils_validator(value)
@@ -95,6 +97,7 @@ is_snils_valid = partial(validate_value, validator=snils_validator)
95
97
 
96
98
 
97
99
  def _check_inn_checksum(coefficients, numbers, checksum):
100
+ """Проверка контрольного числа ИНН с использованием весовых коэффициентов."""
98
101
  summa = sum(c * n for c, n in zip(coefficients, numbers))
99
102
  if summa % 11 % 10 != checksum:
100
103
  raise ValidationError('Не пройдена проверка контрольного числа')
@@ -114,9 +117,7 @@ def inn10_validator(value):
114
117
  if len(value) != 10 or not value.isdigit():
115
118
  raise ValidationError('ИНН должен быть 10-ти значным числом')
116
119
 
117
- _check_inn_checksum((2, 4, 10, 3, 5, 9, 4, 6, 8),
118
- (int(ch) for ch in value[:-1]),
119
- int(value[-1]))
120
+ _check_inn_checksum((2, 4, 10, 3, 5, 9, 4, 6, 8), (int(ch) for ch in value[:-1]), int(value[-1]))
120
121
 
121
122
 
122
123
  def inn12_validator(value):
@@ -133,13 +134,9 @@ def inn12_validator(value):
133
134
  if len(value) != 12 or not value.isdigit():
134
135
  raise ValidationError('ИНН должен быть 12-ти значным числом')
135
136
 
136
- _check_inn_checksum((7, 2, 4, 10, 3, 5, 9, 4, 6, 8),
137
- (int(ch) for ch in value[:-2]),
138
- int(value[-2]))
137
+ _check_inn_checksum((7, 2, 4, 10, 3, 5, 9, 4, 6, 8), (int(ch) for ch in value[:-2]), int(value[-2]))
139
138
 
140
- _check_inn_checksum((3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8),
141
- (int(ch) for ch in value[:-1]),
142
- int(value[-1]))
139
+ _check_inn_checksum((3, 7, 2, 4, 10, 3, 5, 9, 4, 6, 8), (int(ch) for ch in value[:-1]), int(value[-1]))
143
140
 
144
141
 
145
142
  def inn_validator(value):
@@ -206,19 +203,13 @@ def checksum_pr_50_1_024(value):
206
203
  Если в случае повторного расчета остаток от деления вновь сохраняется
207
204
  равным 10, то значение контрольного числа проставляется равным 0.
208
205
  """
209
- summa = sum(
210
- int(digit) * weight
211
- for digit, weight in zip(value, cycle(list(range(1, 11))))
212
- )
206
+ summa = sum(int(digit) * weight for digit, weight in zip(value, cycle(list(range(1, 11)))))
213
207
 
214
208
  remainder = summa % 11
215
209
  if remainder < 10:
216
210
  result = remainder
217
211
  else:
218
- summa = sum(
219
- int(digit) * weight
220
- for digit, weight in zip(value, cycle(list(range(3, 13))))
221
- )
212
+ summa = sum(int(digit) * weight for digit, weight in zip(value, cycle(list(range(3, 13)))))
222
213
  remainder = summa % 11
223
214
  if remainder < 10:
224
215
  result = remainder
@@ -249,9 +240,7 @@ def okato_validator(value):
249
240
  raise ValidationError('Не пройдена проверка контрольного числа')
250
241
 
251
242
  elif value_length not in (2, 5, 8, 11):
252
- raise ValidationError(
253
- 'Код ОКАТО должен состоять из 2, 5, 8 или 11 цифр'
254
- )
243
+ raise ValidationError('Код ОКАТО должен состоять из 2, 5, 8 или 11 цифр')
255
244
 
256
245
 
257
246
  is_okato_valid = partial(validate_value, validator=okato_validator)
@@ -269,9 +258,7 @@ def oktmo_validator(value):
269
258
 
270
259
  value_length = len(value)
271
260
  if value_length not in (2, 5, 8, 11):
272
- raise ValidationError(
273
- 'ОКТМО не может состоять из {} цифр'.format(value_length)
274
- )
261
+ raise ValidationError('ОКТМО не может состоять из {} цифр'.format(value_length))
275
262
 
276
263
 
277
264
  is_oktmo_valid = partial(validate_value, validator=oktmo_validator)
@@ -304,7 +291,7 @@ def _check_ogrn_checksum(value):
304
291
  """
305
292
  value_length = len(value) # количество цифр в ОГРН
306
293
  divisor = value_length - 2 # делитель для вычисления контрольного числа
307
- number = int(value[:value_length - 1]) # ОГРН
294
+ number = int(value[: value_length - 1]) # ОГРН
308
295
  control_number = int(value[-1]) # контрольное число
309
296
 
310
297
  if number % divisor % 10 != control_number:
@@ -312,16 +299,17 @@ def _check_ogrn_checksum(value):
312
299
 
313
300
 
314
301
  def _ogrn_validator(value, valid_length, title):
302
+ """Общая логика для проверки ОГРН и ОГРНИП.
303
+
304
+ Проверяет длину и контрольное число.
305
+ """
315
306
  value = str(value)
316
307
 
317
308
  if not value.isdigit():
318
309
  raise ValidationError('ОГРН должен состоять только из цифр')
319
310
  if len(value) not in valid_length:
320
311
  raise ValidationError(
321
- '{} должен состоять из {} цифр!'.format(
322
- title,
323
- ' или '.join(str(l) for l in valid_length)
324
- )
312
+ '{} должен состоять из {} цифр!'.format(title, ' или '.join(str(length) for length in valid_length))
325
313
  )
326
314
 
327
315
  _check_ogrn_checksum(value)
@@ -373,9 +361,7 @@ def okved_validator(value):
373
361
 
374
362
  value_length = len(value)
375
363
  if value_length < 2 or 6 < value_length:
376
- raise ValidationError(
377
- 'Код ОКВЭД не может состоять из {} цифр'.format(value_length)
378
- )
364
+ raise ValidationError('Код ОКВЭД не может состоять из {} цифр'.format(value_length))
379
365
 
380
366
 
381
367
  is_okved_valid = partial(validate_value, validator=okved_validator)
@@ -434,26 +420,18 @@ def validate_file_mime_type(file, allowed_mime_types):
434
420
  file.seek(0, 0)
435
421
  file_mime_type = magic.from_buffer(file.read(), mime=True)
436
422
  if file_mime_type not in allowed_mime_types:
437
- raise ValidationError(
438
- 'Mime type файла не соотвествует допустимым в системе'
439
- )
423
+ raise ValidationError('Mime type файла не соотвествует допустимым в системе')
440
424
 
441
425
 
442
426
  @deconstructible
443
427
  class FileMimeTypeValidator:
444
428
  """Валидатор для FileField модели проверяющий mimetype файла."""
445
429
 
446
- message = (
447
- 'Mime type файла не допустим для загрузки в системе.'
448
- )
430
+ message = 'Mime type файла не допустим для загрузки в системе.'
449
431
  code = 'invalid_mimetype'
450
432
 
451
433
  def __init__(self, allowed_extensions, message=None, code=None):
452
- self.allowed_extensions = [
453
- allowed_extension.lower()
454
- for allowed_extension
455
- in allowed_extensions
456
- ]
434
+ self.allowed_extensions = [allowed_extension.lower() for allowed_extension in allowed_extensions]
457
435
 
458
436
  self.allowed_mime_types = set(
459
437
  get_mime_type_for_extension(extension)
@@ -545,7 +523,6 @@ class OptionalFieldValidator(IModelValidator):
545
523
 
546
524
 
547
525
  class RequiredBooleanValidator(OptionalFieldValidator):
548
-
549
526
  """Валидатор обязательного поля ``BooleanField``.
550
527
 
551
528
  Пример:
@@ -554,7 +531,9 @@ class RequiredBooleanValidator(OptionalFieldValidator):
554
531
 
555
532
  class Model(BaseModel):
556
533
  accept_rules = models.BooleanField(...)
557
- validators = [RequiredBooleanValidator('accept_rules'),]
534
+ validators = [
535
+ RequiredBooleanValidator('accept_rules'),
536
+ ]
558
537
  """
559
538
 
560
539
  def __init__(self, field_name, **kwargs):
@@ -562,7 +541,7 @@ class RequiredBooleanValidator(OptionalFieldValidator):
562
541
 
563
542
  :param str field_name: имя валидируемого поля
564
543
  """
565
- super(RequiredBooleanValidator, self).__init__(field_name, **kwargs)
544
+ super().__init__(field_name, **kwargs)
566
545
  self.empty_values = (False,)
567
546
 
568
547
  def _need_check(self, instance):
@@ -589,9 +568,12 @@ class RequiredFieldValidator(OptionalFieldValidator):
589
568
  # должно быть обязательным
590
569
  employee = models.ForeignKey(
591
570
  'employee.Employee',
592
- null=True, blank=True,
571
+ null=True,
572
+ blank=True,
593
573
  )
594
- validators = [RequiredFieldValidator('employee'),]
574
+ validators = [
575
+ RequiredFieldValidator('employee'),
576
+ ]
595
577
  """
596
578
 
597
579
  def _need_check(self, instance):
@@ -607,7 +589,6 @@ class RequiredFieldValidator(OptionalFieldValidator):
607
589
 
608
590
 
609
591
  class UnchangeableFieldValidator(IModelValidator):
610
-
611
592
  """Валидатор неизменяемого поля.
612
593
 
613
594
  При редактировании объекта, если изменяется поле ``field_name``,
@@ -619,7 +600,9 @@ class UnchangeableFieldValidator(IModelValidator):
619
600
 
620
601
  class Model(BaseModel):
621
602
  type = models.BooleanField(...)
622
- validators = [UnchangeableFieldValidator('type'),]
603
+ validators = [
604
+ UnchangeableFieldValidator('type'),
605
+ ]
623
606
 
624
607
  """
625
608
 
@@ -642,12 +625,9 @@ class UnchangeableFieldValidator(IModelValidator):
642
625
 
643
626
  :rtype: str
644
627
  """
645
- verbose_name = instance._meta.get_field(
646
- self.field_name
647
- ).verbose_name
648
- return 'Поле "{}" не доступно для редактирования.'.format(
649
- verbose_name
650
- )
628
+ verbose_name = instance._meta.get_field(self.field_name).verbose_name
629
+
630
+ return 'Поле "{}" не доступно для редактирования.'.format(verbose_name)
651
631
 
652
632
  def clean(self, instance, errors):
653
633
  """Проверка редактирования поля ``field_name``.
@@ -669,7 +649,6 @@ class UnchangeableFieldValidator(IModelValidator):
669
649
 
670
650
 
671
651
  class DuplicationValidator(IModelValidator):
672
-
673
652
  """Валидатор уникальности объекта.
674
653
 
675
654
  Используется для объектов, уникальность которых нельзя проверить
@@ -734,11 +713,8 @@ class DuplicationValidator(IModelValidator):
734
713
 
735
714
  :rtype: str
736
715
  """
737
- return (
738
- 'В системе уже существует {} с такими же значениями полей {}.'
739
- ).format(
740
- instance._meta.verbose_name,
741
- ', '.join(self._get_field_names(instance))
716
+ return ('В системе уже существует {} с такими же значениями полей {}.').format(
717
+ instance._meta.verbose_name, ', '.join(self._get_field_names(instance))
742
718
  )
743
719
 
744
720
  def _get_base_query(self, instance):
@@ -762,9 +738,7 @@ class DuplicationValidator(IModelValidator):
762
738
  :type errors: collections.OrderedDict
763
739
  """
764
740
  original = get_original_object(instance)
765
- query = self._get_base_query(instance).filter(
766
- self._get_duplication_params(instance)
767
- )
741
+ query = self._get_base_query(instance).filter(self._get_duplication_params(instance))
768
742
 
769
743
  if original:
770
744
  query = query.exclude(id=instance.id)
@@ -774,12 +748,10 @@ class DuplicationValidator(IModelValidator):
774
748
 
775
749
 
776
750
  class SingleErrorDecimalValidator(DecimalValidator):
777
-
778
751
  """Кастомный класс валидации Decimal поля модели."""
779
752
 
780
753
  def __init__(self, max_digits, decimal_places):
781
- super(SingleErrorDecimalValidator, self).__init__(
782
- max_digits, decimal_places)
754
+ super().__init__(max_digits, decimal_places)
783
755
  self.max_whole_digits = max_digits - decimal_places
784
756
 
785
757
  def __call__(self, value):
@@ -808,8 +780,11 @@ class SingleErrorDecimalValidator(DecimalValidator):
808
780
  code='max_decimal_places',
809
781
  params={'max': self.decimal_places},
810
782
  )
811
- if (self.max_digits is not None and self.decimal_places is not None and
812
- whole_digits > (self.max_digits - self.decimal_places)):
783
+ if (
784
+ self.max_digits is not None
785
+ and self.decimal_places is not None
786
+ and whole_digits > (self.max_digits - self.decimal_places)
787
+ ):
813
788
  raise ValidationError(
814
789
  self.messages['max_whole_digits'],
815
790
  code='max_whole_digits',
@@ -821,13 +796,14 @@ class SingleErrorDecimalValidator(DecimalValidator):
821
796
  # Валидаторы персональных данных
822
797
  # =============================================================================
823
798
 
799
+
824
800
  class FIOValidator(RegexValidator):
825
801
  regex = r'(^$)|(^[a-zA-Zа-яА-ЯёЁ]([\s-]?[a-zA-Zа-яА-ЯёЁ])*$)'
826
802
 
827
803
 
828
- def date_range_validator(minimum=None, maximum=None,
829
- range_message=None, min_message=None,
830
- max_message=None, date_format='%d.%m.%Y'):
804
+ def date_range_validator(
805
+ minimum=None, maximum=None, range_message=None, min_message=None, max_message=None, date_format='%d.%m.%Y'
806
+ ):
831
807
  """Валидатор даты. Возвращает функцию, в которую должен быть помещен один
832
808
  аргумент: проверяемое значение
833
809
  :param minimum: значение, меньше которого value быть не должно;
@@ -857,11 +833,9 @@ def date_range_validator(minimum=None, maximum=None,
857
833
  :return: функция, в которую передается проверяемое значение и которая ведет
858
834
  себя как обычный валидатор поля Django
859
835
  """
860
- assert minimum is not None or maximum is not None, (
861
- 'Необходимо определелить границы для валидатора дат')
836
+ assert minimum is not None or maximum is not None, 'Необходимо определелить границы для валидатора дат'
862
837
 
863
- range_message = (range_message or (
864
- 'Значение %(val)s не входит в диапазон %(min)s-%(max)s'))
838
+ range_message = range_message or ('Значение %(val)s не входит в диапазон %(min)s-%(max)s')
865
839
  min_message = min_message or 'Значение %(val)s меньше, чем %(min)s'
866
840
  max_message = max_message or 'Значение %(val)s больше %(max)s'
867
841
 
@@ -876,8 +850,9 @@ def date_range_validator(minimum=None, maximum=None,
876
850
  max_date = maximum or datetime.max.date()
877
851
  date_format = date_format
878
852
 
879
- return partial(_date_range_validator, min_date=min_date, max_date=max_date,
880
- message=message, date_format=date_format)
853
+ return partial(
854
+ _date_range_validator, min_date=min_date, max_date=max_date, message=message, date_format=date_format
855
+ )
881
856
 
882
857
 
883
858
  def _date_range_validator(value, min_date, max_date, message, date_format):
@@ -895,12 +870,14 @@ def _date_range_validator(value, min_date, max_date, message, date_format):
895
870
  :raises ValidationError
896
871
  """
897
872
  # должны быть все аргументы
898
- assert all([
899
- min_date is not None,
900
- max_date is not None,
901
- message is not None,
902
- date_format is not None,
903
- ]), 'Все аргументы должны быть указаны (см. сигнатуру функции)'
873
+ assert all(
874
+ [
875
+ min_date is not None,
876
+ max_date is not None,
877
+ message is not None,
878
+ date_format is not None,
879
+ ]
880
+ ), 'Все аргументы должны быть указаны (см. сигнатуру функции)'
904
881
 
905
882
  if isinstance(value, datetime):
906
883
  value = value.date()
@@ -915,9 +892,7 @@ def _date_range_validator(value, min_date, max_date, message, date_format):
915
892
  }
916
893
 
917
894
  if not _min <= value <= _max:
918
- raise ValidationError(
919
- message % message_values
920
- )
895
+ raise ValidationError(message % message_values)
921
896
 
922
897
 
923
898
  class HouseValidator(RegexValidator):
@@ -935,10 +910,8 @@ class HouseValidator(RegexValidator):
935
910
  то регулярку нужно будет расширить до
936
911
  '^(?=.{,20}$)([0-9IVXА-ЯЁа-яё"/_,.-]{1,} ?){1,}\b$'
937
912
  """
938
- regex = re.compile(
939
- r'^(?=.{,12}$)([0-9а-яё"/_,.-]{1,} ?){1,}\b$',
940
- re.IGNORECASE | re.UNICODE
941
- )
913
+
914
+ regex = re.compile(r'^(?=.{,12}$)([0-9а-яё"/_,.-]{1,} ?){1,}\b$', re.IGNORECASE | re.UNICODE)
942
915
  message = 'Неверно указан номер дома'
943
916
 
944
917
 
@@ -946,6 +919,7 @@ regex_house_validator = HouseValidator()
946
919
 
947
920
 
948
921
  def house_validator(value):
922
+ """Функция для валидации номера дома."""
949
923
  value = str(value)
950
924
 
951
925
  regex_house_validator(value)
@@ -956,6 +930,7 @@ is_house_number_valid = partial(validate_value, validator=house_validator)
956
930
 
957
931
  class BuildingValidator(RegexValidator):
958
932
  """Валидатор номера корпуса дома."""
933
+
959
934
  regex = re.compile(r'^[0-9а-яё/_.-]{0,10}$', re.IGNORECASE | re.UNICODE)
960
935
  message = 'Неверно указан корпус дома'
961
936
 
@@ -978,6 +953,7 @@ regex_doc_type_validator = DocumentTypeValidator()
978
953
 
979
954
 
980
955
  def doc_type_validator(value):
956
+ """Функция для валидации строки с типом документа."""
981
957
  value = str(value)
982
958
 
983
959
  regex_doc_type_validator(value)
@@ -997,14 +973,10 @@ class PassportNumberValidator(RegexValidator):
997
973
 
998
974
 
999
975
  class DocumentSeriesValidator(RegexValidator):
1000
- regex = (
1001
- r'(^$)|(^[a-zA-Zа-яА-ЯёЁ\d]([\s|\-|\.|\,|\\|\/]?[a-zA-Zа-яА-ЯёЁ\d])*$)'
1002
- )
976
+ regex = r'(^$)|(^[a-zA-Zа-яА-ЯёЁ\d]([\s|\-|\.|\,|\\|\/]?[a-zA-Zа-яА-ЯёЁ\d])*$)'
1003
977
  message = 'Неверно задана серия документа'
1004
978
 
1005
979
 
1006
980
  class DocumentNumberValidator(RegexValidator):
1007
- regex = (
1008
- r'(^$)|(^[a-zA-Zа-яА-ЯёЁ\d]([\s|\-|\.|\,|\\|\/]?[a-zA-Zа-яА-ЯёЁ\d])*$)'
1009
- )
981
+ regex = r'(^$)|(^[a-zA-Zа-яА-ЯёЁ\d]([\s|\-|\.|\,|\\|\/]?[a-zA-Zа-яА-ЯёЁ\d])*$)'
1010
982
  message = 'Неверно задан номер документа'
@@ -17,32 +17,33 @@ from educommon.django.storages.atcfs.exceptions import (
17
17
 
18
18
 
19
19
  class AtcfsApi:
20
- """
21
- Класс для работы с запросами к ATCFS
22
- """
20
+ """Класс для работы с запросами к ATCFS."""
23
21
 
24
22
  def _build_url(self, *args):
25
- """
26
- Функция составления полного урла.
23
+ """Функция составления полного урла.
24
+
27
25
  :param args: составные части пути
28
26
  :return: фбсолютный урл
29
27
  """
30
28
  chunks = (settings.URL,) + args
31
29
  url = '/'.join(chunks)
30
+
32
31
  return url
33
32
 
34
33
  def _get_credential_headers(self):
35
- """
36
- Метод генерации данных для аутентификации на сервере ATCFS.
34
+ """Метод генерации данных для аутентификации на сервере ATCFS.
35
+
37
36
  :return: словарь с необходимыми для атунетификации полями
38
37
  """
39
38
  request_id = str(uuid.uuid4())
40
- sign = '{vis_id}_{vis_user}_{request_id}_{secret_key}'.format(**{
41
- 'vis_id': settings.VIS_ID,
42
- 'vis_user': settings.VIS_USER,
43
- 'request_id': request_id,
44
- 'secret_key': settings.SECRET_KEY,
45
- })
39
+ sign = '{vis_id}_{vis_user}_{request_id}_{secret_key}'.format(
40
+ **{
41
+ 'vis_id': settings.VIS_ID,
42
+ 'vis_user': settings.VIS_USER,
43
+ 'request_id': request_id,
44
+ 'secret_key': settings.SECRET_KEY,
45
+ }
46
+ )
46
47
  sign = hashlib.md5(sign).hexdigest()
47
48
  headers = {
48
49
  'AtcFs-VisId': settings.VIS_ID,
@@ -50,11 +51,12 @@ class AtcfsApi:
50
51
  'AtcFs-RequestId': request_id,
51
52
  'AtcFs-Sign': sign,
52
53
  }
54
+
53
55
  return headers
54
56
 
55
57
  def _send_request(self, method, url, headers=None, params=None, data=None):
56
- """
57
- Отправка запроса
58
+ """Отправка запроса.
59
+
58
60
  :param method: get|post|delete
59
61
  :param url: URL, на который отправляется запрос
60
62
  :param headers: дополнительные заголовки
@@ -71,18 +73,18 @@ class AtcfsApi:
71
73
  headers=full_headers,
72
74
  params=params,
73
75
  data=data,
74
- timeout=(settings.CONNECT_TIMEOUT, None)
76
+ timeout=(settings.CONNECT_TIMEOUT, None),
75
77
  )
76
78
  except (
77
79
  requests.exceptions.ConnectionError,
78
80
  requests.exceptions.ConnectTimeout,
79
- requests.packages.urllib3.exceptions.ConnectTimeoutError
81
+ requests.packages.urllib3.exceptions.ConnectTimeoutError,
80
82
  ):
81
83
  raise AtcfsUnavailable()
82
84
 
83
85
  def upload_file(self, name, content):
84
- """
85
- Загрузка файла на сервер ATCFS
86
+ """Загрузка файла на сервер ATCFS.
87
+
86
88
  :param name: название файла
87
89
  :param content: содержимое файла
88
90
  :return: идентификатор файла на сервере ATCFS
@@ -91,34 +93,24 @@ class AtcfsApi:
91
93
  headers = {'Content-Type': 'application/octet-stream'}
92
94
  params = {'fileName': name}
93
95
  data = content
94
- response = self._send_request(
95
- method='post',
96
- url=url,
97
- headers=headers,
98
- params=params,
99
- data=data
100
- )
96
+ response = self._send_request(method='post', url=url, headers=headers, params=params, data=data)
101
97
  if response.status_code != 201:
102
98
  raise Exception(response.text)
103
99
  ident = response.text
100
+
104
101
  return ident
105
102
 
106
103
  def download_file(self, ident):
107
- """
108
- Загружаем файл с сервера в память.
104
+ """Загружаем файл с сервера в память.
105
+
109
106
  :param ident: идентификатор файла
110
107
  :return: тюпл название и содержимое
111
108
  """
112
109
  url = self._build_url(settings.FILES_PATH, ident)
113
- response = self._send_request(
114
- method='get',
115
- url=url
116
- )
110
+ response = self._send_request(method='get', url=url)
117
111
  if response.status_code != 200:
118
112
  raise Exception(response.text)
119
- _, params = cgi.parse_header(
120
- response.headers.get('Content-Disposition')
121
- )
113
+ _, params = cgi.parse_header(response.headers.get('Content-Disposition'))
122
114
  file_name = params['filename*']
123
115
  try:
124
116
  file_name = re.findall(r'UTF-8\'\'(.*)', file_name)[0]
@@ -126,49 +118,42 @@ class AtcfsApi:
126
118
  except IndexError:
127
119
  pass
128
120
  file_content = response.content
121
+
129
122
  return file_name, file_content
130
123
 
131
124
  def delete_file(self, ident):
132
- """
133
- Удаление файла на сервере ATCFS
125
+ """Удаление файла на сервере ATCFS.
126
+
134
127
  :param ident: идентификатор файла
135
128
  """
136
129
  url = self._build_url(settings.FILES_PATH, ident)
137
- response = self._send_request(
138
- method='delete',
139
- url=url
140
- )
130
+ response = self._send_request(method='delete', url=url)
141
131
  if response.status_code != 200:
142
132
  raise Exception(response.text)
143
133
 
144
134
  def get_file_url(self, ident):
145
- """
146
- Получить прямую ссылку на файл.
135
+ """Получить прямую ссылку на файл.
136
+
147
137
  :param ident: идентификатор файла
148
138
  :return: url
149
139
  """
150
140
  url = self._build_url(settings.TMP_FILE_LINK_PATH, ident)
151
- response = self._send_request(
152
- method='get',
153
- url=url
154
- )
141
+ response = self._send_request(method='get', url=url)
155
142
  if response.status_code != 200:
156
143
  raise Exception(response.text)
157
144
  tmp_ident = response.text
158
145
  file_url = self._build_url(settings.TMP_FILES_PATH, tmp_ident)
146
+
159
147
  return file_url
160
148
 
161
149
  def get_file_info(self, ident):
162
- """
163
- Получить информацию о файле.
150
+ """Получить информацию о файле.
151
+
164
152
  :param ident: идентификатор файла
165
153
  :return: словарь с названием файла и его размером
166
154
  """
167
155
  url = self._build_url(settings.FILE_INFO_PATH, ident)
168
- response = self._send_request(
169
- method='get',
170
- url=url
171
- )
156
+ response = self._send_request(method='get', url=url)
172
157
  if response.status_code != 200:
173
158
  raise Exception(response.text)
174
159
  file_json = response.json()
@@ -176,4 +161,5 @@ class AtcfsApi:
176
161
  'name': file_json['fileName'],
177
162
  'size': file_json['size'],
178
163
  }
164
+
179
165
  return file_info
@@ -11,7 +11,7 @@ def register_urlpatterns():
11
11
  re_path(
12
12
  r'^atcfs_unavailable/$',
13
13
  TemplateView.as_view(template_name='atcfs_unavailable.html'),
14
- name='atcfs_unavailable'
14
+ name='atcfs_unavailable',
15
15
  ),
16
16
  ]
17
17