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.
- educommon/__init__.py +0 -1
- educommon/about/ui/actions.py +16 -30
- educommon/about/ui/ui.py +3 -12
- educommon/about/utils.py +6 -5
- educommon/async_task/__init__.py +0 -1
- educommon/async_task/actions.py +18 -13
- educommon/async_task/apps.py +4 -0
- educommon/async_task/locker.py +2 -5
- educommon/async_task/migrations/0001_initial.py +55 -9
- educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
- educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
- educommon/async_task/models.py +9 -6
- educommon/async_task/tasks.py +11 -7
- educommon/async_task/ui.py +16 -35
- educommon/async_tasks/__init__.py +0 -1
- educommon/async_tasks/apps.py +4 -0
- educommon/async_tasks/locks.py +11 -21
- educommon/async_tasks/migrations/0001_initial.py +68 -8
- educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
- educommon/async_tasks/models.py +9 -29
- educommon/async_tasks/tasks.py +25 -54
- educommon/audit_log/__init__.py +1 -0
- educommon/audit_log/actions.py +27 -36
- educommon/audit_log/app_meta.py +7 -4
- educommon/audit_log/apps.py +44 -29
- educommon/audit_log/constants.py +7 -4
- educommon/audit_log/error_log/actions.py +1 -3
- educommon/audit_log/helpers.py +2 -4
- educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
- educommon/audit_log/migrations/0001_initial.py +91 -16
- educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
- educommon/audit_log/migrations/0003_logproxy.py +1 -3
- educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
- educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
- educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
- educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
- educommon/audit_log/migrations/0008_table_logged.py +0 -1
- educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
- educommon/audit_log/models.py +36 -42
- educommon/audit_log/permissions.py +11 -9
- educommon/audit_log/proxies.py +12 -23
- educommon/audit_log/ui.py +18 -15
- educommon/audit_log/utils/__init__.py +28 -60
- educommon/audit_log/utils/operations.py +16 -2
- educommon/auth/__init__.py +0 -3
- educommon/auth/rbac/__init__.py +2 -4
- educommon/auth/rbac/actions.py +148 -145
- educommon/auth/rbac/app_meta.py +9 -6
- educommon/auth/rbac/backends/base.py +2 -8
- educommon/auth/rbac/backends/caching.py +27 -37
- educommon/auth/rbac/backends/simple.py +1 -4
- educommon/auth/rbac/checker.py +1 -3
- educommon/auth/rbac/management/commands/rbac.py +6 -11
- educommon/auth/rbac/manager.py +18 -47
- educommon/auth/rbac/migrations/0001_initial.py +73 -12
- educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
- educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
- educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
- educommon/auth/rbac/models.py +63 -68
- educommon/auth/rbac/permissions.py +6 -7
- educommon/auth/rbac/ui.py +83 -84
- educommon/auth/rbac/utils.py +10 -11
- educommon/auth/rbac/validators.py +4 -5
- educommon/auth/simple_auth/__init__.py +1 -5
- educommon/auth/simple_auth/actions.py +79 -92
- educommon/auth/simple_auth/app_meta.py +2 -9
- educommon/auth/simple_auth/checkers.py +3 -3
- educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
- educommon/auth/simple_auth/validators.py +0 -1
- educommon/contingent/actions.py +7 -7
- educommon/contingent/app_meta.py +1 -4
- educommon/contingent/base.py +10 -15
- educommon/contingent/catalogs.py +424 -540
- educommon/contingent/contingent_plugin/actions.py +4 -15
- educommon/contingent/contingent_plugin/apps.py +10 -4
- educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
- educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
- educommon/contingent/contingent_plugin/model_views.py +2 -12
- educommon/contingent/contingent_plugin/models.py +2 -7
- educommon/contingent/contingent_plugin/observer.py +14 -13
- educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
- educommon/contingent/contingent_plugin/storage.py +8 -7
- educommon/contingent/contingent_plugin/utils.py +6 -6
- educommon/django/db/fields.py +72 -86
- educommon/django/db/migration/__init__.py +3 -7
- educommon/django/db/migration/operations.py +29 -51
- educommon/django/db/mixins/__init__.py +16 -10
- educommon/django/db/mixins/date_interval.py +47 -75
- educommon/django/db/mixins/validation.py +26 -26
- educommon/django/db/model_view/__init__.py +18 -22
- educommon/django/db/models.py +9 -8
- educommon/django/db/observer.py +9 -27
- educommon/django/db/partitioning/__init__.py +66 -92
- educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
- educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
- educommon/django/db/partitioning/management/commands/split_table.py +18 -13
- educommon/django/db/routers.py +6 -15
- educommon/django/db/signals.py +4 -2
- educommon/django/db/utils.py +14 -19
- educommon/django/db/validators/__init__.py +1 -0
- educommon/django/db/validators/simple.py +72 -100
- educommon/django/storages/atcfs/api.py +39 -53
- educommon/django/storages/atcfs/app_meta.py +1 -1
- educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
- educommon/django/storages/atcfs/models.py +0 -3
- educommon/django/storages/atcfs/monkey_patching.py +18 -12
- educommon/django/storages/atcfs/storage.py +14 -23
- educommon/extjs/fields/input_params.py +15 -45
- educommon/importer/XLSReader.py +143 -241
- educommon/importer/__init__.py +86 -4
- educommon/importer/api.py +53 -84
- educommon/importer/constants.py +4 -14
- educommon/importer/loggers.py +16 -26
- educommon/importer/proxy.py +131 -176
- educommon/importer/proxy_import.py +11 -12
- educommon/importer/report.py +4 -6
- educommon/importer/ui.py +32 -26
- educommon/importer/validators.py +4 -7
- educommon/integration_entities/helpers.py +14 -18
- educommon/ioc/__init__.py +3 -6
- educommon/logger/loggers.py +10 -14
- educommon/m3/__init__.py +20 -38
- educommon/m3/extensions/__init__.py +1 -0
- educommon/m3/extensions/listeners/__init__.py +22 -38
- educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
- educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
- educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
- educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
- educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
- educommon/m3/extensions/ui.py +15 -33
- educommon/m3/transaction_context.py +17 -19
- educommon/objectpack/actions.py +70 -88
- educommon/objectpack/apps.py +5 -0
- educommon/objectpack/filters.py +9 -15
- educommon/objectpack/ui.py +59 -77
- educommon/report/__init__.py +9 -5
- educommon/report/actions.py +29 -32
- educommon/report/constructor/__init__.py +5 -8
- educommon/report/constructor/app_meta.py +1 -3
- educommon/report/constructor/apps.py +1 -0
- educommon/report/constructor/base.py +33 -80
- educommon/report/constructor/builders/excel/_base.py +138 -286
- educommon/report/constructor/builders/excel/_header.py +2 -9
- educommon/report/constructor/builders/excel/product.py +13 -34
- educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
- educommon/report/constructor/config.py +2 -0
- educommon/report/constructor/editor/actions.py +101 -215
- educommon/report/constructor/editor/ui.py +71 -93
- educommon/report/constructor/exceptions.py +6 -12
- educommon/report/constructor/migrations/0001_initial.py +36 -44
- educommon/report/constructor/migrations/0002_report_filters.py +86 -72
- educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
- educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
- educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
- educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
- educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
- educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
- educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
- educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
- educommon/report/constructor/mixins.py +14 -15
- educommon/report/constructor/models.py +76 -124
- educommon/report/constructor/utils.py +3 -8
- educommon/report/constructor/validators.py +1 -3
- educommon/report/reporter.py +25 -43
- educommon/report/utils.py +14 -40
- educommon/rest/actions.py +7 -11
- educommon/rest/context.py +6 -16
- educommon/rest/controllers.py +10 -10
- educommon/rest/mixins.py +29 -27
- educommon/secure_media/app_meta.py +9 -9
- educommon/utils/__init__.py +3 -2
- educommon/utils/caching.py +1 -3
- educommon/utils/conversion.py +1 -3
- educommon/utils/crypto.py +1 -2
- educommon/utils/date.py +13 -26
- educommon/utils/db/__init__.py +17 -26
- educommon/utils/db/postgresql.py +1 -4
- educommon/utils/fonts/__init__.py +3 -4
- educommon/utils/licence/__init__.py +5 -16
- educommon/utils/misc.py +9 -18
- educommon/utils/object_grid.py +55 -62
- educommon/utils/phone_number/modelfields.py +1 -3
- educommon/utils/phone_number/phone_number.py +5 -8
- educommon/utils/phone_number/validators.py +8 -23
- educommon/utils/plugins.py +15 -28
- educommon/utils/registry.py +2 -1
- educommon/utils/seqtools.py +1 -3
- educommon/utils/serializer.py +9 -16
- educommon/utils/storage.py +3 -2
- educommon/utils/system.py +1 -3
- educommon/utils/system_app/management/commands/delete_objects.py +17 -34
- educommon/utils/ui.py +87 -84
- educommon/utils/xml/__init__.py +2 -7
- educommon/utils/xml/resolver.py +1 -0
- educommon/ws_log/actions.py +31 -76
- educommon/ws_log/base.py +6 -20
- educommon/ws_log/migrations/0001_initial.py +25 -8
- educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
- educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
- educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
- educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
- educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
- educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
- educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
- educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
- educommon/ws_log/models.py +21 -35
- educommon/ws_log/provider.py +2 -1
- educommon/ws_log/report.py +8 -13
- educommon/ws_log/smev/applications.py +12 -27
- educommon/ws_log/smev/exceptions.py +2 -3
- educommon/ws_log/ui.py +32 -32
- educommon/ws_log/utils.py +1 -3
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/METADATA +26 -14
- educommon-3.13.2.dist-info/RECORD +354 -0
- educommon/utils/patches.py +0 -27
- educommon/version.conf +0 -11
- educommon-3.13.0.dist-info/RECORD +0 -357
- educommon-3.13.0.dist-info/dependency_links.txt +0 -1
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +0 -0
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
@@ -29,8 +29,8 @@ from educommon.django.storages.atcfs.api import (
|
|
29
29
|
|
30
30
|
|
31
31
|
def dictfetchall(cursor):
|
32
|
-
"""
|
33
|
-
|
32
|
+
"""Вспомогательная функция.
|
33
|
+
|
34
34
|
cursor.fetchall возвращает данные в виде списка списков:
|
35
35
|
(('43', 'text 1'), ('44', 'text 2'), ('45', 'text 3'))
|
36
36
|
Эта функция преобразует в вид:
|
@@ -40,13 +40,13 @@ def dictfetchall(cursor):
|
|
40
40
|
"""
|
41
41
|
desc = cursor.description
|
42
42
|
columns = [col[0] for col in desc]
|
43
|
+
|
43
44
|
return [dict(list(zip(columns, row))) for row in cursor.fetchall()]
|
44
45
|
|
45
46
|
|
46
47
|
class Command(BaseCommand):
|
47
|
-
"""
|
48
|
-
|
49
|
-
в которых есть поля FileField.
|
48
|
+
"""Команда обходит все зарегистрированные модели, в которых есть поля FileField.
|
49
|
+
|
50
50
|
Если для поля установлен AtcfsStorage, или он установлен глобально,
|
51
51
|
то файл переносится на сервер ATCFS.
|
52
52
|
"""
|
@@ -61,12 +61,13 @@ class Command(BaseCommand):
|
|
61
61
|
)
|
62
62
|
|
63
63
|
def __init__(self):
|
64
|
-
super(
|
64
|
+
super().__init__()
|
65
|
+
|
65
66
|
self.api = AtcfsApi()
|
66
67
|
|
67
68
|
def _get_fields(self, model):
|
68
|
-
"""
|
69
|
-
|
69
|
+
"""Выбираем в модели все переменные, являющиеся FileField-полями.
|
70
|
+
|
70
71
|
:param model: класс модели
|
71
72
|
:return: список названий полей FileField
|
72
73
|
"""
|
@@ -78,20 +79,18 @@ class Command(BaseCommand):
|
|
78
79
|
continue
|
79
80
|
if isinstance(mem, FileDescriptor):
|
80
81
|
fields.append(nam)
|
82
|
+
|
81
83
|
return fields
|
82
84
|
|
83
85
|
def _get_models(self):
|
84
|
-
"""
|
85
|
-
|
86
|
+
"""Берем все модели, в которых есть FileField.
|
87
|
+
|
86
88
|
:return: список классов моделей
|
87
89
|
"""
|
88
90
|
models = {}
|
89
91
|
|
90
|
-
is_model
|
91
|
-
inspect.isclass(x) and
|
92
|
-
isinstance(x, ModelBase) and
|
93
|
-
not x._meta.abstract
|
94
|
-
)
|
92
|
+
def is_model(x):
|
93
|
+
return inspect.isclass(x) and isinstance(x, ModelBase) and not x._meta.abstract
|
95
94
|
|
96
95
|
apps = settings.INSTALLED_APPS
|
97
96
|
for app in apps:
|
@@ -108,18 +107,18 @@ class Command(BaseCommand):
|
|
108
107
|
return models
|
109
108
|
|
110
109
|
def _delete_all_files(self, models):
|
111
|
-
"""
|
112
|
-
|
113
|
-
В работе команды не учавствует.
|
110
|
+
"""Сервисный метод.
|
111
|
+
|
112
|
+
Используется для технических нужд. В работе команды не учавствует.
|
114
113
|
"""
|
115
114
|
for model, fields in models.items():
|
116
|
-
kwargs = dict(list(zip(fields, ['']*len(fields))))
|
115
|
+
kwargs = dict(list(zip(fields, [''] * len(fields))))
|
117
116
|
cnt = model.objects.all().update(**kwargs)
|
118
117
|
print('{0}: {1}'.format(model, cnt))
|
119
118
|
|
120
119
|
def _send_file(self, file_name):
|
121
|
-
"""
|
122
|
-
|
120
|
+
"""Непосредственная отправка файла на ATCFS.
|
121
|
+
|
123
122
|
:param file_name: название файла
|
124
123
|
:return: идентификатор файла в ATCFS
|
125
124
|
"""
|
@@ -127,37 +126,31 @@ class Command(BaseCommand):
|
|
127
126
|
file_path = os.path.join(settings.MEDIA_ROOT, file_name)
|
128
127
|
try:
|
129
128
|
with open(file_path, 'r') as fd:
|
130
|
-
ident = self.api.upload_file(
|
131
|
-
os.path.basename(file_name), fd.read()
|
132
|
-
)
|
129
|
+
ident = self.api.upload_file(os.path.basename(file_name), fd.read())
|
133
130
|
except IOError:
|
134
131
|
pass
|
132
|
+
|
135
133
|
return ident
|
136
134
|
|
137
135
|
def _get_objs(self, model, fields):
|
138
|
-
"""
|
139
|
-
|
136
|
+
"""Запрашиваем из базы напрямую объекты по модели.
|
137
|
+
|
140
138
|
:param model: класс модели
|
141
139
|
:param fields: список полей
|
142
140
|
:return: список словарей в которых id и значения полей
|
143
141
|
"""
|
144
142
|
cursor = connection.cursor()
|
145
143
|
select_fields = ', '.join(fields)
|
146
|
-
where_fields = ' OR '.join(
|
147
|
-
|
148
|
-
)
|
149
|
-
sql = 'SELECT id, {0} from {1} WHERE {2};'.format(
|
150
|
-
select_fields,
|
151
|
-
model._meta.db_table,
|
152
|
-
where_fields
|
153
|
-
)
|
144
|
+
where_fields = ' OR '.join(["COALESCE({0}, '') <> ''".format(field) for field in fields])
|
145
|
+
sql = 'SELECT id, {0} from {1} WHERE {2};'.format(select_fields, model._meta.db_table, where_fields)
|
154
146
|
cursor.execute(sql)
|
155
147
|
objs = dictfetchall(cursor)
|
148
|
+
|
156
149
|
return objs
|
157
150
|
|
158
151
|
def _update_objs(self, model, objs):
|
159
|
-
"""
|
160
|
-
|
152
|
+
"""Изменяем значения полей в базе.
|
153
|
+
|
161
154
|
:param model: класс модели
|
162
155
|
:param objs: словарь списков, где ключ - id объекта,
|
163
156
|
а значение - список тюплов (название, значение)
|
@@ -165,28 +158,20 @@ class Command(BaseCommand):
|
|
165
158
|
cursor = connection.cursor()
|
166
159
|
sql = ''
|
167
160
|
for obj_id, obj_fields in objs.items():
|
168
|
-
set_fields = ', '.join(
|
169
|
-
|
170
|
-
)
|
171
|
-
sql += 'UPDATE {0} SET {1} WHERE id = {2};'.format(
|
172
|
-
model._meta.db_table,
|
173
|
-
set_fields,
|
174
|
-
obj_id
|
175
|
-
)
|
161
|
+
set_fields = ', '.join(["{0[0]} = '{0[1]}'".format(field) for field in obj_fields])
|
162
|
+
sql += 'UPDATE {0} SET {1} WHERE id = {2};'.format(model._meta.db_table, set_fields, obj_id)
|
176
163
|
if sql:
|
177
164
|
cursor.execute(sql)
|
178
165
|
commit_unless_managed()
|
179
166
|
|
180
167
|
def _migrate_all_files(self, models):
|
181
|
-
"""
|
182
|
-
|
168
|
+
"""Проходимся по всем моделям, всем объектам, отсылаем файлы на ATCFS.
|
169
|
+
|
183
170
|
:param models: модели, в которых есть FileField
|
184
171
|
"""
|
185
172
|
total = len(models)
|
186
173
|
for i, (model, fields) in enumerate(models.items(), start=1):
|
187
|
-
print(self.style.SQL_KEYWORD(
|
188
|
-
'{0} ({1}/{2})'.format(model, i, total)
|
189
|
-
))
|
174
|
+
print(self.style.SQL_KEYWORD('{0} ({1}/{2})'.format(model, i, total)))
|
190
175
|
objs = self._get_objs(model, fields)
|
191
176
|
updated_objs = {}
|
192
177
|
for obj in objs:
|
@@ -196,12 +181,14 @@ class Command(BaseCommand):
|
|
196
181
|
if field_value:
|
197
182
|
ident = self._send_file(field_value)
|
198
183
|
updated_fields.append((field_name, ident))
|
199
|
-
print(
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
184
|
+
print(
|
185
|
+
'{0},{1},{2},{3}'.format(
|
186
|
+
obj['id'],
|
187
|
+
field_name.decode('UTF-8'),
|
188
|
+
field_value.decode('UTF-8'),
|
189
|
+
ident.decode('UTF-8'),
|
190
|
+
)
|
191
|
+
)
|
205
192
|
updated_objs[obj['id']] = updated_fields
|
206
193
|
self._update_objs(model, updated_objs)
|
207
194
|
|
@@ -1,7 +1,5 @@
|
|
1
|
-
"""
|
2
|
-
|
3
|
-
для работы с AtcfsStorage.
|
4
|
-
"""
|
1
|
+
"""Внедряем в джанговский дефолтный FieldFile необходимый функционал для работы с AtcfsStorage."""
|
2
|
+
|
5
3
|
import re
|
6
4
|
|
7
5
|
from django.core.files.storage import (
|
@@ -21,8 +19,8 @@ DEFAULT_FILE_STORAGE = get_storage_class()
|
|
21
19
|
|
22
20
|
|
23
21
|
def is_atcfs_storage(storage):
|
24
|
-
"""
|
25
|
-
|
22
|
+
"""Функция определяет является ли переданный storage AtcfsStorage.
|
23
|
+
|
26
24
|
:param storage: объект Storage
|
27
25
|
:return: True/False
|
28
26
|
"""
|
@@ -30,11 +28,12 @@ def is_atcfs_storage(storage):
|
|
30
28
|
# Второй случай когда в сетингсах установлен DEFAULT_FILE_STORAGE,
|
31
29
|
# и он не переопределен через параметр storage в филде.
|
32
30
|
if (
|
33
|
-
isinstance(storage, AtcfsStorage)
|
34
|
-
isinstance(storage, DefaultStorage)
|
35
|
-
|
31
|
+
isinstance(storage, AtcfsStorage)
|
32
|
+
or isinstance(storage, DefaultStorage)
|
33
|
+
and DEFAULT_FILE_STORAGE == AtcfsStorage
|
36
34
|
):
|
37
35
|
return True
|
36
|
+
|
38
37
|
return False
|
39
38
|
|
40
39
|
|
@@ -42,13 +41,13 @@ def is_atcfs_storage(storage):
|
|
42
41
|
# Необходимо установить field_name,
|
43
42
|
# в котором будет храниться реальное название файла.
|
44
43
|
|
45
|
-
uuid_re = re.compile(
|
46
|
-
r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'
|
47
|
-
)
|
44
|
+
uuid_re = re.compile(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}')
|
48
45
|
|
49
46
|
old_field_file__init__ = files.FieldFile.__init__
|
50
47
|
|
48
|
+
|
51
49
|
def new_field_file__init__(self, instance, field, name):
|
50
|
+
"""Инициализирует FieldFile с дополнительной логикой для AtcfsStorage."""
|
52
51
|
old_field_file__init__(self, instance, field, name)
|
53
52
|
if is_atcfs_storage(self.storage):
|
54
53
|
if self.name and uuid_re.match(self.name):
|
@@ -56,6 +55,7 @@ def new_field_file__init__(self, instance, field, name):
|
|
56
55
|
else:
|
57
56
|
self.file_name = ''
|
58
57
|
|
58
|
+
|
59
59
|
files.FieldFile.__init__ = new_field_file__init__
|
60
60
|
|
61
61
|
|
@@ -63,12 +63,15 @@ files.FieldFile.__init__ = new_field_file__init__
|
|
63
63
|
|
64
64
|
old_field_file__str__ = files.FieldFile.__str__
|
65
65
|
|
66
|
+
|
66
67
|
def new_field_file__str__(self):
|
68
|
+
"""Возвращает строковое представление файла."""
|
67
69
|
if is_atcfs_storage(self.storage):
|
68
70
|
return self.file_name or ''
|
69
71
|
else:
|
70
72
|
return old_field_file__str__(self)
|
71
73
|
|
74
|
+
|
72
75
|
files.FieldFile.__str__ = new_field_file__str__
|
73
76
|
|
74
77
|
|
@@ -76,7 +79,9 @@ files.FieldFile.__str__ = new_field_file__str__
|
|
76
79
|
|
77
80
|
old_file_field_get_prep_value = files.FileField.get_prep_value
|
78
81
|
|
82
|
+
|
79
83
|
def new_file_field_get_prep_value(self, value):
|
84
|
+
"""Подготавливает значение FileField для сохранения в БД."""
|
80
85
|
if is_atcfs_storage(self.storage):
|
81
86
|
if value is None:
|
82
87
|
return None
|
@@ -84,4 +89,5 @@ def new_file_field_get_prep_value(self, value):
|
|
84
89
|
else:
|
85
90
|
return old_file_field_get_prep_value(self, value)
|
86
91
|
|
92
|
+
|
87
93
|
files.FileField.get_prep_value = new_file_field_get_prep_value
|
@@ -24,20 +24,18 @@ from educommon.django.storages.atcfs.exceptions import (
|
|
24
24
|
|
25
25
|
|
26
26
|
# Сообщение, выдаваемое в интерфейс при сохранении если сервер недоступен.
|
27
|
-
ATCFS_UNAVAILABLE_MSG =
|
27
|
+
ATCFS_UNAVAILABLE_MSG = """
|
28
28
|
Извините, в настоящий момент внешнее файловое хранилище недоступно,
|
29
29
|
сохранение приложенного файла невозможно. Пожалуйста, повторите действие позже
|
30
30
|
или удалите приложенный файл перед сохранением.
|
31
|
-
|
31
|
+
"""
|
32
32
|
|
33
33
|
# Ссылка на файл и имя, когда недоступен сервер.
|
34
34
|
UNAVAILABLE_FILE_NAME = 'Файл недоступен (сбой в работе файлового хранилища)'
|
35
35
|
|
36
36
|
|
37
37
|
class AtcfsStorage(Storage):
|
38
|
-
"""
|
39
|
-
ATCFS Storage
|
40
|
-
"""
|
38
|
+
"""ATCFS Storage."""
|
41
39
|
|
42
40
|
def __init__(self):
|
43
41
|
self.api = AtcfsApi()
|
@@ -55,6 +53,7 @@ class AtcfsStorage(Storage):
|
|
55
53
|
except AtcfsUnavailable:
|
56
54
|
# Выдаем сообщение непосредственно в интерфейс.
|
57
55
|
raise ApplicationLogicException(ATCFS_UNAVAILABLE_MSG)
|
56
|
+
|
58
57
|
return ident
|
59
58
|
|
60
59
|
def delete(self, ident):
|
@@ -72,6 +71,7 @@ class AtcfsStorage(Storage):
|
|
72
71
|
file_url = self.api.get_file_url(ident)
|
73
72
|
except AtcfsUnavailable:
|
74
73
|
file_url = reverse('atcfs_unavailable')
|
74
|
+
|
75
75
|
return file_url
|
76
76
|
|
77
77
|
def size(self, ident):
|
@@ -80,6 +80,7 @@ class AtcfsStorage(Storage):
|
|
80
80
|
file_size = file_info['size']
|
81
81
|
except AtcfsUnavailable:
|
82
82
|
file_size = 0
|
83
|
+
|
83
84
|
return file_size
|
84
85
|
|
85
86
|
def name(self, ident):
|
@@ -88,12 +89,11 @@ class AtcfsStorage(Storage):
|
|
88
89
|
file_name = file_info['name']
|
89
90
|
except AtcfsUnavailable:
|
90
91
|
file_name = UNAVAILABLE_FILE_NAME
|
92
|
+
|
91
93
|
return file_name
|
92
94
|
|
93
95
|
def path(self, ident):
|
94
|
-
"""
|
95
|
-
Загружаем файл, сохраняем его во временной папке, отдаем путь.
|
96
|
-
"""
|
96
|
+
"""Загружаем файл, сохраняем его во временной папке, отдаем путь."""
|
97
97
|
try:
|
98
98
|
file_name, file_content = self.api.download_file(ident)
|
99
99
|
except AtcfsUnavailable:
|
@@ -103,34 +103,25 @@ class AtcfsStorage(Storage):
|
|
103
103
|
file_path = os.path.join(dir_path, file_name)
|
104
104
|
with open(file_path, 'w') as fd:
|
105
105
|
fd.write(file_content)
|
106
|
+
|
106
107
|
return file_path
|
107
108
|
|
108
109
|
def exists(self, name):
|
109
|
-
"""
|
110
|
-
Заглушка
|
111
|
-
"""
|
110
|
+
"""Заглушка."""
|
112
111
|
return False
|
113
112
|
|
114
113
|
def listdir(self, path):
|
115
|
-
"""
|
116
|
-
Заглушка
|
117
|
-
"""
|
114
|
+
"""Заглушка."""
|
118
115
|
return [], []
|
119
116
|
|
120
117
|
def accessed_time(self, name):
|
121
|
-
"""
|
122
|
-
Заглушка
|
123
|
-
"""
|
118
|
+
"""Заглушка."""
|
124
119
|
return datetime.datetime(1, 1, 1)
|
125
120
|
|
126
121
|
def created_time(self, name):
|
127
|
-
"""
|
128
|
-
Заглушка
|
129
|
-
"""
|
122
|
+
"""Заглушка."""
|
130
123
|
return datetime.datetime(1, 1, 1)
|
131
124
|
|
132
125
|
def modified_time(self, name):
|
133
|
-
"""
|
134
|
-
Заглушка
|
135
|
-
"""
|
126
|
+
"""Заглушка."""
|
136
127
|
return datetime.datetime(1, 1, 1)
|
@@ -1,5 +1,4 @@
|
|
1
1
|
"""Параметры фильтрации ввода для различного типа полей (ИНН, СНИЛС и тд.).
|
2
|
-
from __future__ import absolute_import
|
3
2
|
|
4
3
|
Примеры использования:
|
5
4
|
|
@@ -11,68 +10,43 @@ from __future__ import absolute_import
|
|
11
10
|
"""
|
12
11
|
|
13
12
|
# параметры для поля ввода СНИЛС
|
14
|
-
snils_field_params = dict(
|
15
|
-
input_mask='###-###-### ##',
|
16
|
-
regex=r'^\d{3}-\d{3}-\d{3} \d{2}$'
|
17
|
-
)
|
13
|
+
snils_field_params = dict(input_mask='###-###-### ##', regex=r'^\d{3}-\d{3}-\d{3} \d{2}$')
|
18
14
|
|
19
15
|
# параметры для поля ввода ИНН юр.лица или физ.лица
|
20
|
-
inn_field_params = dict(
|
21
|
-
input_mask='############',
|
22
|
-
regex=r'^\d{10}(\d{2})?$'
|
23
|
-
)
|
16
|
+
inn_field_params = dict(input_mask='############', regex=r'^\d{10}(\d{2})?$')
|
24
17
|
|
25
18
|
# параметры для поля ввода ИНН юр. лица
|
26
|
-
inn10_field_params = dict(
|
27
|
-
input_mask='##########',
|
28
|
-
regex=r'^\d{10}$'
|
29
|
-
)
|
19
|
+
inn10_field_params = dict(input_mask='##########', regex=r'^\d{10}$')
|
30
20
|
|
31
21
|
# параметры для поля ввода ИНН физ.лица или ИП
|
32
|
-
inn12_field_params = dict(
|
33
|
-
input_mask='############',
|
34
|
-
regex=r'^\d{12}$'
|
35
|
-
)
|
22
|
+
inn12_field_params = dict(input_mask='############', regex=r'^\d{12}$')
|
36
23
|
|
37
|
-
children_document_series_field_params = dict(
|
38
|
-
input_mask='****-ZZ',
|
39
|
-
regex='^[A-Za-z0-9]{1,4}-[А-ЯA-Z]{2}$'
|
40
|
-
)
|
24
|
+
children_document_series_field_params = dict(input_mask='****-ZZ', regex='^[A-Za-z0-9]{1,4}-[А-ЯA-Z]{2}$')
|
41
25
|
|
42
|
-
children_document_number_field_params = dict(
|
43
|
-
input_mask='#' * 6,
|
44
|
-
regex='^\d{6}$'
|
45
|
-
)
|
26
|
+
children_document_number_field_params = dict(input_mask='#' * 6, regex='^\d{6}$')
|
46
27
|
|
47
|
-
delegate_document_series_field_params = dict(
|
48
|
-
input_mask='#' * 4,
|
49
|
-
regex='^\d{4}$'
|
50
|
-
)
|
28
|
+
delegate_document_series_field_params = dict(input_mask='#' * 4, regex='^\d{4}$')
|
51
29
|
|
52
|
-
delegate_document_number_field_params = dict(
|
53
|
-
input_mask='#' * 6,
|
54
|
-
regex='^\d{6}$'
|
55
|
-
)
|
30
|
+
delegate_document_number_field_params = dict(input_mask='#' * 6, regex='^\d{6}$')
|
56
31
|
|
57
32
|
url_field_params = dict(
|
58
|
-
regex=
|
59
|
-
invalid_text='Адрес сайта должен начинаться с http:// '
|
60
|
-
'или https:// и не должен содержать пробелов',
|
33
|
+
regex='^((http|https)\:\/\/)([^\s]*)$',
|
34
|
+
invalid_text='Адрес сайта должен начинаться с http:// или https:// и не должен содержать пробелов',
|
61
35
|
)
|
62
36
|
|
63
37
|
# Параметры поля для ввода имён.
|
64
38
|
name_field_params = dict(
|
65
|
-
mask_re=
|
39
|
+
mask_re="[- \\'а-яёА-ЯЁ]",
|
66
40
|
)
|
67
41
|
|
68
42
|
# Параметры поля для ввода имён,допускает наличи латиницы.
|
69
43
|
eng_name_field_params = dict(
|
70
|
-
mask_re=
|
44
|
+
mask_re="[- \\'а-яёА-ЯЁa-zA-Z]",
|
71
45
|
)
|
72
46
|
|
73
47
|
# Параметры поля для ввода имён, допускает наличие цифр.
|
74
48
|
name_digits_field_params = dict(
|
75
|
-
mask_re=
|
49
|
+
mask_re="[- \\'а-яёА-ЯЁ0-9]",
|
76
50
|
)
|
77
51
|
|
78
52
|
# Параметры поля для ввода КПП.
|
@@ -126,14 +100,10 @@ okfs_field_params = dict(
|
|
126
100
|
)
|
127
101
|
|
128
102
|
# Параметры поля ввода Телефон.
|
129
|
-
phone_field_params = dict(
|
130
|
-
mask_re=r'^[0-9,()-]+$'
|
131
|
-
)
|
103
|
+
phone_field_params = dict(mask_re=r'^[0-9,()-]+$')
|
132
104
|
|
133
105
|
# Параметры поля ввода эл. почты.
|
134
|
-
email_field_params = dict(
|
135
|
-
regex=r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
|
136
|
-
)
|
106
|
+
email_field_params = dict(regex=r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
|
137
107
|
|
138
108
|
# Параметры поля ввода БИК.
|
139
109
|
bik_field_params = dict(
|