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
educommon/auth/rbac/utils.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Вспомогательные средства для работы с подсистемой RBAC."""
|
2
|
+
|
2
3
|
import operator
|
3
4
|
from inspect import (
|
4
5
|
getfullargspec,
|
@@ -16,6 +17,7 @@ from educommon.m3 import (
|
|
16
17
|
|
17
18
|
def _resolve_packs_or_actions(packs_or_actions):
|
18
19
|
"""Возвращает список из паков и экшенов, заданных классами и строками."""
|
20
|
+
|
19
21
|
def resolve(pack_or_action):
|
20
22
|
if isinstance(pack_or_action, tuple):
|
21
23
|
pack, action = pack_or_action
|
@@ -25,24 +27,18 @@ def _resolve_packs_or_actions(packs_or_actions):
|
|
25
27
|
result = get_pack(pack_or_action)
|
26
28
|
return result
|
27
29
|
|
28
|
-
result = [
|
29
|
-
resolve(pack_or_action)
|
30
|
-
for pack_or_action in packs_or_actions
|
31
|
-
]
|
30
|
+
result = [resolve(pack_or_action) for pack_or_action in packs_or_actions]
|
32
31
|
|
33
32
|
return result
|
34
33
|
|
35
34
|
|
36
35
|
def _rule_filter(rule_handler, packs_or_actions, operator_):
|
37
36
|
"""Возвращает обработчик правила, "обернутый" в фильтрующую функцию."""
|
37
|
+
|
38
38
|
def action_in_list(action):
|
39
39
|
for pack_or_action in _resolve_packs_or_actions(packs_or_actions):
|
40
|
-
if (
|
41
|
-
isinstance(pack_or_action,
|
42
|
-
action.__class__ is pack_or_action.__class__
|
43
|
-
) or (
|
44
|
-
isinstance(pack_or_action, ActionPack) and
|
45
|
-
action.parent is pack_or_action
|
40
|
+
if (isinstance(pack_or_action, Action) and action.__class__ is pack_or_action.__class__) or (
|
41
|
+
isinstance(pack_or_action, ActionPack) and action.parent is pack_or_action
|
46
42
|
):
|
47
43
|
return True
|
48
44
|
|
@@ -97,6 +93,7 @@ def invert_rule(rule_handler):
|
|
97
93
|
|
98
94
|
:rtype: callable
|
99
95
|
"""
|
96
|
+
|
100
97
|
def wrapper(action, request, user, *args, **kwargs):
|
101
98
|
return not rule_handler(action, request, user, *args, **kwargs)
|
102
99
|
|
@@ -118,6 +115,7 @@ def any_rules(*rule_handlers):
|
|
118
115
|
|
119
116
|
:rtype: callable
|
120
117
|
"""
|
118
|
+
|
121
119
|
def wrapper(action, request, user, *args, **kwargs):
|
122
120
|
for rule_handler in rule_handlers:
|
123
121
|
if rule_handler(action, request, user, *args, **kwargs):
|
@@ -145,6 +143,7 @@ def all_rules(*rule_handlers):
|
|
145
143
|
|
146
144
|
:rtype: callable
|
147
145
|
"""
|
146
|
+
|
148
147
|
def wrapper(action, request, user, *args, **kwargs):
|
149
148
|
for rule_handler in rule_handlers:
|
150
149
|
if not rule_handler(action, request, user, *args, **kwargs):
|
@@ -176,7 +175,7 @@ def get_rbac_rule_data(request, action):
|
|
176
175
|
:type action: m3.actions.Action
|
177
176
|
"""
|
178
177
|
if not hasattr(request, '_rbac_rule_data'):
|
179
|
-
if
|
178
|
+
if hasattr(action, 'get_rbac_rule_data'):
|
180
179
|
method = action.get_rbac_rule_data
|
181
180
|
else:
|
182
181
|
method = action.parent.get_rbac_rule_data
|
@@ -12,10 +12,9 @@ from educommon.django.db.validators.simple import (
|
|
12
12
|
)
|
13
13
|
|
14
14
|
|
15
|
-
package_name_validator = RegexValidator(
|
16
|
-
r'(^[_a-z][_a-z0-9]*$)|(^[_a-z][._a-z0-9]*[_a-z0-9]{1}$)', re.IGNORECASE
|
17
|
-
)
|
15
|
+
package_name_validator = RegexValidator(
|
16
|
+
re.compile(r'(^[_a-z][_a-z0-9]*$)|(^[_a-z][._a-z0-9]*[_a-z0-9]{1}$)', re.IGNORECASE)
|
17
|
+
)
|
18
18
|
"""Валидатор имени пакета."""
|
19
19
|
|
20
|
-
is_package_name_valid = partial(validate_value,
|
21
|
-
validator=package_name_validator)
|
20
|
+
is_package_name_valid = partial(validate_value, validator=package_name_validator)
|
@@ -5,8 +5,4 @@ from educommon.auth.simple_auth import (
|
|
5
5
|
|
6
6
|
# Например, settings.LOGIN_URL = simple_auth.get_login_url()
|
7
7
|
def get_login_url():
|
8
|
-
return ''.join((
|
9
|
-
const.AUTH_CONTROLLER_URL,
|
10
|
-
const.AUTH_PACK_URL,
|
11
|
-
const.LOGIN_PAGE_URL
|
12
|
-
))
|
8
|
+
return ''.join((const.AUTH_CONTROLLER_URL, const.AUTH_PACK_URL, const.LOGIN_PAGE_URL))
|
@@ -73,7 +73,8 @@ class AuthPack(BasePack):
|
|
73
73
|
login_checker = checkers.DefaultLoginChecker()
|
74
74
|
|
75
75
|
def __init__(self):
|
76
|
-
super(
|
76
|
+
super().__init__()
|
77
|
+
|
77
78
|
self.login_page_action = LoginPageAction()
|
78
79
|
self.login_action = LoginAction()
|
79
80
|
|
@@ -86,43 +87,55 @@ class AuthPack(BasePack):
|
|
86
87
|
self.change_password_page_action = ChangeResetPasswordPageAction()
|
87
88
|
self.change_password_action = ChangeResetPasswordAction()
|
88
89
|
|
89
|
-
self.actions.extend(
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
90
|
+
self.actions.extend(
|
91
|
+
(
|
92
|
+
self.login_page_action,
|
93
|
+
self.logout_confirm_action,
|
94
|
+
self.login_action,
|
95
|
+
self.logout_action,
|
96
|
+
self.reset_password_page_action,
|
97
|
+
self.reset_password_action,
|
98
|
+
self.change_password_page_action,
|
99
|
+
self.change_password_action,
|
100
|
+
)
|
101
|
+
)
|
99
102
|
|
100
103
|
def declare_context(self, action):
|
101
|
-
|
104
|
+
"""Определяет контекст для экшена входа."""
|
105
|
+
ctx = super().declare_context(action)
|
106
|
+
|
102
107
|
if action is self.login_action:
|
103
108
|
ctx['login'] = dict(type='str', default='')
|
104
109
|
ctx['password'] = dict(type='str', default='')
|
110
|
+
|
105
111
|
return ctx
|
106
112
|
|
107
113
|
def get_login_url(self):
|
114
|
+
"""Возвращает URL экшена входа."""
|
108
115
|
return self.login_action.get_absolute_url()
|
109
116
|
|
110
117
|
def get_logout_url(self):
|
118
|
+
"""Возвращает URL экшена выхода."""
|
111
119
|
return self.logout_action.get_absolute_url()
|
112
120
|
|
113
121
|
def get_login_page_url(self):
|
122
|
+
"""Возвращает URL страницы входа."""
|
114
123
|
return self.login_page_action.get_absolute_url()
|
115
124
|
|
116
125
|
def get_reset_password_page_url(self):
|
126
|
+
"""Возвращает URL страницы восстановления пароля."""
|
117
127
|
return self.reset_password_page_action.get_absolute_url()
|
118
128
|
|
119
129
|
def get_reset_password_url(self):
|
130
|
+
"""Возвращает URL экшена восстановления пароля."""
|
120
131
|
return self.reset_password_action.get_absolute_url()
|
121
132
|
|
122
133
|
def get_change_password_page_url(self):
|
134
|
+
"""Возвращает URL страницы изменения пароля."""
|
123
135
|
return self.change_password_page_action.get_absolute_url()
|
124
136
|
|
125
137
|
def get_change_password_url(self):
|
138
|
+
"""Возвращает URL экшена изменения пароля."""
|
126
139
|
return self.change_password_action.get_absolute_url()
|
127
140
|
|
128
141
|
|
@@ -133,26 +146,21 @@ class LoginPageAction(BaseAction):
|
|
133
146
|
template_file_name = 'simple_auth/login_page.html'
|
134
147
|
|
135
148
|
def _get_login_panel(self, request, context):
|
149
|
+
"""Возвращает компонент панели логина."""
|
136
150
|
get_login_panel = ioc.get('simple_auth__get_login_panel')
|
137
151
|
|
138
|
-
return self.handle(
|
139
|
-
'get_login_panel',
|
140
|
-
get_login_panel(request, context)
|
141
|
-
)
|
152
|
+
return self.handle('get_login_panel', get_login_panel(request, context))
|
142
153
|
|
143
154
|
def get_template_context(self, request, context):
|
155
|
+
"""Формирует контекст шаблона страницы входа."""
|
144
156
|
return dict(
|
145
157
|
login_url=self.parent.get_login_url(),
|
146
158
|
login_panel=self._get_login_panel(request, context),
|
147
|
-
reset_password_page_url=self.parent.get_reset_password_page_url()
|
159
|
+
reset_password_page_url=self.parent.get_reset_password_page_url(),
|
148
160
|
)
|
149
161
|
|
150
162
|
def run(self, request, context):
|
151
|
-
return render(
|
152
|
-
request,
|
153
|
-
self.template_file_name,
|
154
|
-
self.get_template_context(request, context)
|
155
|
-
)
|
163
|
+
return render(request, self.template_file_name, self.get_template_context(request, context))
|
156
164
|
|
157
165
|
|
158
166
|
class LoginAction(BaseAction):
|
@@ -169,19 +177,23 @@ class LoginAction(BaseAction):
|
|
169
177
|
if not request.is_ajax():
|
170
178
|
result = HttpResponseRedirect('/')
|
171
179
|
elif err_msg:
|
172
|
-
result = PreJsonResult(
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
180
|
+
result = PreJsonResult(
|
181
|
+
dict(
|
182
|
+
success=False,
|
183
|
+
redirect='',
|
184
|
+
message=err_msg or '',
|
185
|
+
)
|
186
|
+
)
|
177
187
|
else:
|
178
188
|
user = auth.authenticate(username=username, password=password)
|
179
189
|
auth.login(request, user)
|
180
190
|
|
181
|
-
result = PreJsonResult(
|
182
|
-
|
183
|
-
|
184
|
-
|
191
|
+
result = PreJsonResult(
|
192
|
+
dict(
|
193
|
+
success=True,
|
194
|
+
redirect='/',
|
195
|
+
)
|
196
|
+
)
|
185
197
|
|
186
198
|
return result
|
187
199
|
|
@@ -193,16 +205,13 @@ class ResetPasswordPageAction(BaseAction):
|
|
193
205
|
template_file_name = 'simple_auth/reset_password_page.html'
|
194
206
|
|
195
207
|
def get_template_context(self, request, context):
|
208
|
+
"""Формирует контекст для шаблона восстановления пароля."""
|
196
209
|
return dict(
|
197
|
-
login_page_url=self.parent.get_login_page_url(),
|
198
|
-
reset_password_url=self.parent.get_reset_password_url()
|
210
|
+
login_page_url=self.parent.get_login_page_url(), reset_password_url=self.parent.get_reset_password_url()
|
199
211
|
)
|
200
212
|
|
201
213
|
def run(self, request, context):
|
202
|
-
return render(
|
203
|
-
request, self.template_file_name,
|
204
|
-
self.get_template_context(request, context)
|
205
|
-
)
|
214
|
+
return render(request, self.template_file_name, self.get_template_context(request, context))
|
206
215
|
|
207
216
|
|
208
217
|
class ResetPasswordAction(BaseAction):
|
@@ -212,22 +221,22 @@ class ResetPasswordAction(BaseAction):
|
|
212
221
|
email_template_file_name = 'simple_auth/email/reset_password.html'
|
213
222
|
|
214
223
|
def context_declaration(self):
|
224
|
+
"""Определяет входной контекст с email для восстановления."""
|
215
225
|
return {'email': {'type': 'str'}}
|
216
226
|
|
217
227
|
def get_email_template_context(self, request, context):
|
228
|
+
"""Формирует контекст для email шаблона восстановления пароля."""
|
218
229
|
site_url = settings.SITE_URL.rstrip('/')
|
219
|
-
|
220
|
-
|
221
|
-
recover_url=urljoin(
|
222
|
-
site_url, self.parent.get_change_password_page_url()
|
223
|
-
)
|
224
|
-
)
|
230
|
+
|
231
|
+
return dict(site_url=site_url, recover_url=urljoin(site_url, self.parent.get_change_password_page_url()))
|
225
232
|
|
226
233
|
@staticmethod
|
227
234
|
def _get_user_by_email(email):
|
235
|
+
"""Ищет пользователя по email."""
|
228
236
|
if ioc.has_value('get_user_by_email'):
|
229
237
|
get_user_by_email = ioc.get('get_user_by_email')
|
230
238
|
else:
|
239
|
+
|
231
240
|
def get_user_by_email(email):
|
232
241
|
query = get_user_model().objects.filter(email=email)
|
233
242
|
if query.count() == 1:
|
@@ -238,10 +247,13 @@ class ResetPasswordAction(BaseAction):
|
|
238
247
|
def run(self, request, context):
|
239
248
|
user = ResetPasswordAction._get_user_by_email(context.email)
|
240
249
|
if user is None:
|
241
|
-
return OperationResult(
|
242
|
-
|
243
|
-
|
244
|
-
|
250
|
+
return OperationResult(
|
251
|
+
False,
|
252
|
+
message=(
|
253
|
+
'Этот адрес электронной почты не связан ни с одной учетной '
|
254
|
+
'записью. Вы уверены, что зарегистрированы?'
|
255
|
+
),
|
256
|
+
)
|
245
257
|
|
246
258
|
now = datetime.datetime.now()
|
247
259
|
life = getattr(settings, 'RESET_CODES_LIFE', None)
|
@@ -253,29 +265,17 @@ class ResetPasswordAction(BaseAction):
|
|
253
265
|
code = uuid4().hex
|
254
266
|
ResetPasswords.objects.create(user=user, code=code)
|
255
267
|
template_context = self.get_email_template_context(request, context)
|
256
|
-
template_context.update({
|
257
|
-
'username': user.username,
|
258
|
-
'code': code
|
259
|
-
})
|
268
|
+
template_context.update({'username': user.username, 'code': code})
|
260
269
|
|
261
270
|
# Шаблон отправки email
|
262
|
-
template = render_to_string(
|
263
|
-
self.email_template_file_name,
|
264
|
-
template_context
|
265
|
-
)
|
271
|
+
template = render_to_string(self.email_template_file_name, template_context)
|
266
272
|
|
267
273
|
# Отправка письма
|
268
|
-
msg = EmailMessage(
|
269
|
-
'Восстановление пароля', template,
|
270
|
-
settings.DEFAULT_FROM_EMAIL, [context.email]
|
271
|
-
)
|
274
|
+
msg = EmailMessage('Восстановление пароля', template, settings.DEFAULT_FROM_EMAIL, [context.email])
|
272
275
|
msg.content_subtype = 'html'
|
273
276
|
msg.send()
|
274
277
|
|
275
|
-
return OperationResult(
|
276
|
-
message='На указанный адрес отправлено письмо с дальнейшими'
|
277
|
-
' инструкциями.'
|
278
|
-
)
|
278
|
+
return OperationResult(message='На указанный адрес отправлено письмо с дальнейшими инструкциями.')
|
279
279
|
|
280
280
|
|
281
281
|
class ChangeResetPasswordPageAction(BaseAction):
|
@@ -285,13 +285,15 @@ class ChangeResetPasswordPageAction(BaseAction):
|
|
285
285
|
template_file_name = 'simple_auth/change_reset_password_page.html'
|
286
286
|
|
287
287
|
def context_declaration(self):
|
288
|
+
"""Определяет контекст с кодом восстановления пароля."""
|
288
289
|
return {'code': {'type': 'str'}}
|
289
290
|
|
290
291
|
def get_template_context(self, request, context):
|
292
|
+
"""Формирует контекст для шаблона смены пароля."""
|
291
293
|
return dict(
|
292
294
|
code=context.code,
|
293
295
|
login_page_url=self.parent.get_login_page_url(),
|
294
|
-
change_password_url=self.parent.get_change_password_url()
|
296
|
+
change_password_url=self.parent.get_change_password_url(),
|
295
297
|
)
|
296
298
|
|
297
299
|
def run(self, request, context):
|
@@ -299,17 +301,10 @@ class ChangeResetPasswordPageAction(BaseAction):
|
|
299
301
|
life = getattr(settings, 'RESET_CODES_LIFE', None)
|
300
302
|
life = datetime.timedelta(minutes=life or const.RESET_CODES_LIFE)
|
301
303
|
# Если не найден пользователь
|
302
|
-
if not ResetPasswords.objects.filter(
|
303
|
-
|
304
|
-
).exists():
|
305
|
-
return HttpResponseRedirect(
|
306
|
-
self.parent.get_reset_password_page_url()
|
307
|
-
)
|
304
|
+
if not ResetPasswords.objects.filter(date__gte=now - life, code=context.code).exists():
|
305
|
+
return HttpResponseRedirect(self.parent.get_reset_password_page_url())
|
308
306
|
|
309
|
-
return render(
|
310
|
-
request, self.template_file_name,
|
311
|
-
self.get_template_context(request, context)
|
312
|
-
)
|
307
|
+
return render(request, self.template_file_name, self.get_template_context(request, context))
|
313
308
|
|
314
309
|
|
315
310
|
class ChangeResetPasswordAction(BaseAction):
|
@@ -319,15 +314,10 @@ class ChangeResetPasswordAction(BaseAction):
|
|
319
314
|
validator = validators.DefaultPasswordValidator()
|
320
315
|
|
321
316
|
def context_declaration(self):
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
}
|
327
|
-
|
328
|
-
@convert_validation_error_to(
|
329
|
-
ApplicationLogicException, model=ResetPasswords
|
330
|
-
)
|
317
|
+
"""Определяет контекст с кодом и паролями."""
|
318
|
+
return {'code': {'type': 'str'}, 'password': {'type': 'str'}, 'password_confirm': {'type': 'str'}}
|
319
|
+
|
320
|
+
@convert_validation_error_to(ApplicationLogicException, model=ResetPasswords)
|
331
321
|
def run(self, request, context):
|
332
322
|
password = context.password
|
333
323
|
confirm = context.password_confirm
|
@@ -337,13 +327,9 @@ class ChangeResetPasswordAction(BaseAction):
|
|
337
327
|
life = datetime.timedelta(minutes=life or const.RESET_CODES_LIFE)
|
338
328
|
|
339
329
|
try:
|
340
|
-
user = ResetPasswords.objects.filter(
|
341
|
-
date__gte=now - life
|
342
|
-
).get(code=context.code).user
|
330
|
+
user = ResetPasswords.objects.filter(date__gte=now - life).get(code=context.code).user
|
343
331
|
except ResetPasswords.DoesNotExist:
|
344
|
-
return HttpResponseRedirect(
|
345
|
-
self.parent.get_reset_password_page_url()
|
346
|
-
)
|
332
|
+
return HttpResponseRedirect(self.parent.get_reset_password_page_url())
|
347
333
|
|
348
334
|
if password != confirm:
|
349
335
|
raise ValidationError('Пароль и подтверждение не совпадают!')
|
@@ -356,6 +342,7 @@ class ChangeResetPasswordAction(BaseAction):
|
|
356
342
|
user.save()
|
357
343
|
|
358
344
|
ResetPasswords.objects.filter(user=user).delete()
|
345
|
+
|
359
346
|
return OperationResult(message='Новый пароль установлен!')
|
360
347
|
|
361
348
|
|
@@ -366,8 +353,8 @@ class LogoutConfirmAction(BaseAction):
|
|
366
353
|
|
367
354
|
def run(self, request, context):
|
368
355
|
msg_box = MessageBox(
|
369
|
-
'', 'Вы действительно хотите выйти из системы?',
|
370
|
-
|
356
|
+
'', 'Вы действительно хотите выйти из системы?', MessageBox.ICON_QUESTION, MessageBox.BTN_YESNO
|
357
|
+
)
|
371
358
|
|
372
359
|
msg_box.handler_yes = """
|
373
360
|
Ext.Ajax.request({
|
@@ -379,6 +366,7 @@ class LogoutConfirmAction(BaseAction):
|
|
379
366
|
}
|
380
367
|
});
|
381
368
|
""" % {'url': self.parent.logout_action.get_absolute_url()}
|
369
|
+
|
382
370
|
return http.HttpResponse(msg_box.get_script())
|
383
371
|
|
384
372
|
|
@@ -388,7 +376,6 @@ class LogoutAction(BaseAction):
|
|
388
376
|
url = '/logout'
|
389
377
|
|
390
378
|
def run(self, request, context):
|
391
|
-
|
392
379
|
auth.logout(request)
|
393
380
|
|
394
381
|
if request.is_ajax():
|
@@ -26,9 +26,7 @@ auth_controller = ioc.get('auth_controller')
|
|
26
26
|
|
27
27
|
|
28
28
|
def register_actions():
|
29
|
-
auth_controller.extend_packs((
|
30
|
-
AuthPack(),
|
31
|
-
))
|
29
|
+
auth_controller.extend_packs((AuthPack(),))
|
32
30
|
|
33
31
|
|
34
32
|
def register_desktop_menu():
|
@@ -37,12 +35,7 @@ def register_desktop_menu():
|
|
37
35
|
DesktopLoader.add(
|
38
36
|
GENERIC_USER,
|
39
37
|
DesktopLoader.TOOLBOX,
|
40
|
-
DesktopShortcut(
|
41
|
-
pack=auth_pack.logout_confirm_action,
|
42
|
-
name='Выход',
|
43
|
-
index=256,
|
44
|
-
icon='logout'
|
45
|
-
)
|
38
|
+
DesktopShortcut(pack=auth_pack.logout_confirm_action, name='Выход', index=256, icon='logout'),
|
46
39
|
)
|
47
40
|
|
48
41
|
uificate_the_controller(auth_controller)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Классы, осуществляющие проверку пользовательских данных."""
|
2
|
+
|
2
3
|
from m3_django_compat import (
|
3
4
|
get_user_model,
|
4
5
|
)
|
@@ -17,7 +18,7 @@ class DefaultLoginChecker:
|
|
17
18
|
|
18
19
|
def _check_lic(self, *args, **kwargs):
|
19
20
|
# TODO: проверка лицензии
|
20
|
-
|
21
|
+
kwargs['request']
|
21
22
|
return None
|
22
23
|
|
23
24
|
def _check_user_exists(self, *args, **kwargs):
|
@@ -63,8 +64,7 @@ class DefaultLoginChecker:
|
|
63
64
|
средствами django.
|
64
65
|
"""
|
65
66
|
for checker in self._checkers:
|
66
|
-
error = checker(
|
67
|
-
self, request=request, username=username, password=password)
|
67
|
+
error = checker(self, request=request, username=username, password=password)
|
68
68
|
|
69
69
|
if error:
|
70
70
|
return error
|
@@ -8,7 +8,6 @@ from django.db import (
|
|
8
8
|
|
9
9
|
|
10
10
|
class Migration(migrations.Migration):
|
11
|
-
|
12
11
|
dependencies = [
|
13
12
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
14
13
|
]
|
@@ -18,9 +17,29 @@ class Migration(migrations.Migration):
|
|
18
17
|
name='ResetPasswords',
|
19
18
|
fields=[
|
20
19
|
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
|
21
|
-
(
|
22
|
-
|
23
|
-
|
20
|
+
(
|
21
|
+
'code',
|
22
|
+
models.CharField(
|
23
|
+
unique=True,
|
24
|
+
max_length=32,
|
25
|
+
verbose_name='\u041a\u043e\u0434 \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f',
|
26
|
+
),
|
27
|
+
),
|
28
|
+
(
|
29
|
+
'date',
|
30
|
+
models.DateTimeField(
|
31
|
+
auto_now_add=True,
|
32
|
+
verbose_name='\u0414\u0430\u0442\u0430 \u0441\u0431\u0440\u043e\u0441\u0430 \u043f\u0430\u0440\u043e\u043b\u044f',
|
33
|
+
),
|
34
|
+
),
|
35
|
+
(
|
36
|
+
'user',
|
37
|
+
models.ForeignKey(
|
38
|
+
verbose_name='\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c',
|
39
|
+
to=settings.AUTH_USER_MODEL,
|
40
|
+
on_delete=models.CASCADE,
|
41
|
+
),
|
42
|
+
),
|
24
43
|
],
|
25
44
|
options={
|
26
45
|
'verbose_name': '\u0421\u0431\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c',
|
educommon/contingent/actions.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Паки справочников контингента."""
|
2
|
+
|
2
3
|
from django.db.models import (
|
3
4
|
Q,
|
4
5
|
)
|
@@ -48,7 +49,7 @@ class OkoguPack(ObjectPack):
|
|
48
49
|
|
49
50
|
Добавляется css класс для переноса строк в ячейках грида
|
50
51
|
"""
|
51
|
-
super(
|
52
|
+
super().configure_grid(grid)
|
52
53
|
|
53
54
|
grid.cls = 'word-wrap-grid' # перенос строк в ячейках грида
|
54
55
|
|
@@ -90,7 +91,7 @@ class OKSMPack(ObjectPack):
|
|
90
91
|
'sortable': True,
|
91
92
|
'searchable': True,
|
92
93
|
'width': 3,
|
93
|
-
}
|
94
|
+
},
|
94
95
|
]
|
95
96
|
|
96
97
|
def get_rows_query(self, request, context):
|
@@ -99,16 +100,15 @@ class OKSMPack(ObjectPack):
|
|
99
100
|
|
100
101
|
Исключается отображение РФ.
|
101
102
|
"""
|
102
|
-
records = super(
|
103
|
+
records = super().get_rows_query(request, context)
|
103
104
|
|
104
105
|
return records.exclude(code=OksmVirtialModel.rf_code)
|
105
106
|
|
106
107
|
def apply_search(self, query, request, context):
|
107
108
|
"""Поиск по краткому наименованию или коду."""
|
108
|
-
query = super(
|
109
|
-
OKSMPack, self).apply_search(query, request, context)
|
109
|
+
query = super(OKSMPack, self).apply_search(query, request, context)
|
110
110
|
|
111
111
|
if hasattr(context, 'filter'):
|
112
|
-
query = query.filter(Q(shortname__icontains=context.filter) |
|
113
|
-
|
112
|
+
query = query.filter(Q(shortname__icontains=context.filter) | Q(code=context.filter))
|
113
|
+
|
114
114
|
return query
|
educommon/contingent/app_meta.py
CHANGED
educommon/contingent/base.py
CHANGED
@@ -4,6 +4,7 @@ BaseCatalogVirtualModel - виртуальная модель на основе
|
|
4
4
|
BaseEnumerateProductSpecific - перечисление с продуктовыми зависимостями.
|
5
5
|
BaseModelView - перечисление на основе виртуальной модели.
|
6
6
|
"""
|
7
|
+
|
7
8
|
import json
|
8
9
|
import os
|
9
10
|
|
@@ -66,11 +67,8 @@ class BaseCatalogVirtualModel(VirtualModel):
|
|
66
67
|
|
67
68
|
@classmethod
|
68
69
|
def get_serialized_values(cls, ids):
|
69
|
-
"""Список сериализованных объектов
|
70
|
-
|
71
|
-
"""
|
72
|
-
return json.dumps(list(cls.objects.filter(id__in=ids).values(
|
73
|
-
*cls.fields_to_serialize)))
|
70
|
+
"""Список сериализованных объектов для маппинга в ExtMultiSelectField."""
|
71
|
+
return json.dumps(list(cls.objects.filter(id__in=ids).values(*cls.fields_to_serialize)))
|
74
72
|
|
75
73
|
@classmethod
|
76
74
|
def _get_ids(cls):
|
@@ -84,7 +82,8 @@ class BaseCatalogVirtualModel(VirtualModel):
|
|
84
82
|
|
85
83
|
:param dict params: Данные объекта модели.
|
86
84
|
"""
|
87
|
-
super(
|
85
|
+
super().__init__()
|
86
|
+
|
88
87
|
for param in params:
|
89
88
|
setattr(self, param, params[param])
|
90
89
|
|
@@ -130,18 +129,15 @@ class BaseEnumerateProductSpecific(BaseEnumerate, ProductSpecific):
|
|
130
129
|
assert all(code in cls.values for code in list_codes), (
|
131
130
|
'Все значения list_codes должны содержаться в values класса'
|
132
131
|
)
|
133
|
-
|
132
|
+
|
133
|
+
super().set_category(list_codes)
|
134
134
|
|
135
135
|
@classmethod
|
136
136
|
def get_choices(cls):
|
137
137
|
"""Возвращает заданные для конкретных продуктов значения."""
|
138
138
|
codes = cls.current_kind or cls.values
|
139
139
|
|
140
|
-
return [
|
141
|
-
(k, v)
|
142
|
-
for k, v in cls.values.items()
|
143
|
-
if k in codes
|
144
|
-
]
|
140
|
+
return [(k, v) for k, v in cls.values.items() if k in codes]
|
145
141
|
|
146
142
|
|
147
143
|
class BaseModelView(ProductSpecific):
|
@@ -170,9 +166,7 @@ class BaseModelView(ProductSpecific):
|
|
170
166
|
|
171
167
|
:return: [(value_field, display_field), ...]
|
172
168
|
"""
|
173
|
-
codes = cls.current_kind or [
|
174
|
-
rec[cls.value_field]
|
175
|
-
for rec in cls.model.data]
|
169
|
+
codes = cls.current_kind or [rec[cls.value_field] for rec in cls.model.data]
|
176
170
|
|
177
171
|
result = (
|
178
172
|
(record[cls.value_field], record[cls.display_field])
|
@@ -181,4 +175,5 @@ class BaseModelView(ProductSpecific):
|
|
181
175
|
)
|
182
176
|
|
183
177
|
result = tuple(sorted(result, key=lambda code_name: code_name[1]))
|
178
|
+
|
184
179
|
return result
|