edu-rdm-integration 3.5.10__py3-none-any.whl → 3.6.0__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.
- edu_rdm_integration/app_settings.py +13 -0
- edu_rdm_integration/base.py +106 -0
- edu_rdm_integration/consts.py +2 -0
- edu_rdm_integration/enums.py +31 -0
- edu_rdm_integration/migrations/0016_transferredentity_queue_level.py +22 -0
- edu_rdm_integration/models.py +6 -0
- edu_rdm_integration/registry/actions.py +23 -4
- edu_rdm_integration/registry/ui.py +44 -0
- edu_rdm_integration/tasks.py +105 -113
- {edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/METADATA +88 -3
- {edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/RECORD +14 -13
- {edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/WHEEL +0 -0
- {edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/licenses/LICENSE +0 -0
- {edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,19 @@ RDM_TRANSFER_TASK_HOUR = '*/4'
|
|
41
41
|
RDM_TRANSFER_TASK_DAY_OF_WEEK = '*'
|
42
42
|
RDM_TRANSFER_TASK_LOCK_EXPIRE_SECONDS = 60 * 60 * 6
|
43
43
|
|
44
|
+
# Настройка запуска периодической задачи выгрузки данных - очередь быстрого уровня
|
45
|
+
RDM_FAST_TRANSFER_TASK_MINUTE = '*/5'
|
46
|
+
RDM_FAST_TRANSFER_TASK_HOUR = '*'
|
47
|
+
RDM_FAST_TRANSFER_TASK_DAY_OF_WEEK = '*'
|
48
|
+
RDM_FAST_TRANSFER_TASK_LOCK_EXPIRE_SECONDS = 60 * 30
|
49
|
+
|
50
|
+
# Настройка запуска периодической задачи выгрузки данных - очередь медленного уровня
|
51
|
+
RDM_LONG_TRANSFER_TASK_MINUTE = '0'
|
52
|
+
RDM_LONG_TRANSFER_TASK_HOUR = '*/6'
|
53
|
+
RDM_LONG_TRANSFER_TASK_DAY_OF_WEEK = '*'
|
54
|
+
RDM_LONG_TRANSFER_TASK_LOCK_EXPIRE_SECONDS = 60 * 60 * 6
|
55
|
+
|
56
|
+
|
44
57
|
# Настройка запуска периодической задачи статуса загрузки данных в витрину:
|
45
58
|
RDM_UPLOAD_STATUS_TASK_MINUTE = '*/30'
|
46
59
|
RDM_UPLOAD_STATUS_TASK_HOUR = '*'
|
edu_rdm_integration/base.py
CHANGED
@@ -3,10 +3,40 @@ from abc import (
|
|
3
3
|
ABC,
|
4
4
|
abstractmethod,
|
5
5
|
)
|
6
|
+
from collections import (
|
7
|
+
defaultdict,
|
8
|
+
)
|
6
9
|
from typing import (
|
7
10
|
Optional,
|
8
11
|
)
|
9
12
|
|
13
|
+
from django.db.models import (
|
14
|
+
Q,
|
15
|
+
)
|
16
|
+
|
17
|
+
from m3_db_utils.consts import (
|
18
|
+
DEFAULT_ORDER_NUMBER,
|
19
|
+
)
|
20
|
+
|
21
|
+
from edu_rdm_integration.consts import (
|
22
|
+
REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA,
|
23
|
+
REGIONAL_DATA_MART_INTEGRATION_EXPORTING_DATA,
|
24
|
+
)
|
25
|
+
from edu_rdm_integration.helpers import (
|
26
|
+
UploadStatusHelper,
|
27
|
+
get_collecting_managers_max_period_ended_dates,
|
28
|
+
get_exporting_managers_max_period_ended_dates,
|
29
|
+
save_command_log_link,
|
30
|
+
)
|
31
|
+
from edu_rdm_integration.models import (
|
32
|
+
ExportingDataSubStageUploaderClientLog,
|
33
|
+
RegionalDataMartEntityEnum,
|
34
|
+
TransferredEntity,
|
35
|
+
)
|
36
|
+
from edu_rdm_integration.storages import (
|
37
|
+
RegionalDataMartEntityStorage,
|
38
|
+
)
|
39
|
+
|
10
40
|
|
11
41
|
class BaseOperationData(ABC):
|
12
42
|
"""Базовый класс операций с данными."""
|
@@ -39,3 +69,79 @@ class BaseOperationData(ABC):
|
|
39
69
|
logging.getLogger('exception_logger').removeHandler(self._file_handler)
|
40
70
|
|
41
71
|
self._file_handler.close()
|
72
|
+
|
73
|
+
|
74
|
+
class BaseTransferLatestEntitiesDataMixin:
|
75
|
+
"""Миксин сбора и выгрузки данных."""
|
76
|
+
|
77
|
+
def __init__(self) -> None:
|
78
|
+
super().__init__()
|
79
|
+
|
80
|
+
self._collecting_data_managers: dict[str, type['RunnerManager']] = {}
|
81
|
+
self._collecting_data_manager_to_logs_period_end: dict[str, 'datetime'] = {}
|
82
|
+
|
83
|
+
self._exporting_data_managers: dict[str, type['RunnerManager']] = {}
|
84
|
+
self._exporting_data_manager_to_period_end: dict[str, 'datetime'] = {}
|
85
|
+
|
86
|
+
self._transferred_entities = []
|
87
|
+
self._entites_models_map = defaultdict(list)
|
88
|
+
|
89
|
+
def get_entity_qs(self) -> 'QuerySet[TransferredEntity]':
|
90
|
+
"""Возвращает сущностей сбора и выгрузки."""
|
91
|
+
raise NotImplementedError
|
92
|
+
|
93
|
+
def _collect_transferred_entities(self) -> None:
|
94
|
+
"""Собирает сущности РВД, по которым будет произведен сбор и экспорт данных."""
|
95
|
+
|
96
|
+
self._transferred_entities = [
|
97
|
+
(RegionalDataMartEntityEnum.get_model_enum_value(key=entity), export_enabled)
|
98
|
+
for entity, export_enabled in self.get_entity_qs().values_list('entity', 'export_enabled')
|
99
|
+
]
|
100
|
+
|
101
|
+
# Собираем словарь по сущностям с моделями для сборки
|
102
|
+
for entity, _ in self._transferred_entities:
|
103
|
+
self._entites_models_map[entity.key].extend(
|
104
|
+
(model_enum for model_enum in (*entity.additional_model_enums, entity.main_model_enum)
|
105
|
+
if model_enum.order_number != DEFAULT_ORDER_NUMBER)
|
106
|
+
)
|
107
|
+
|
108
|
+
def _collect_managers(self) -> None:
|
109
|
+
"""Собирает менеджеры Функций для сбора и выгрузки данных."""
|
110
|
+
entity_storage = RegionalDataMartEntityStorage()
|
111
|
+
entity_storage.prepare()
|
112
|
+
|
113
|
+
collecting_models_data_managers_map = entity_storage.prepare_entities_manager_map(
|
114
|
+
tags={REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA},
|
115
|
+
)
|
116
|
+
exporting_entities_data_managers_map = entity_storage.prepare_entities_manager_map(
|
117
|
+
tags={REGIONAL_DATA_MART_INTEGRATION_EXPORTING_DATA},
|
118
|
+
)
|
119
|
+
|
120
|
+
for entity_key, entity_models in self._entites_models_map.items():
|
121
|
+
for entity_model in entity_models:
|
122
|
+
collect_manager_class = collecting_models_data_managers_map.get(entity_model.key)
|
123
|
+
if collect_manager_class:
|
124
|
+
self._collecting_data_managers[entity_model.key] = collect_manager_class
|
125
|
+
|
126
|
+
export_manager_class = exporting_entities_data_managers_map.get(entity_key)
|
127
|
+
if export_manager_class:
|
128
|
+
self._exporting_data_managers[entity_key] = export_manager_class
|
129
|
+
|
130
|
+
def _calculate_collecting_managers_logs_period_ended_at(self) -> None:
|
131
|
+
"""Определяет дату последнего успешного этапа сбора у менеджеров Функций сбора."""
|
132
|
+
self._collecting_data_manager_to_logs_period_end = get_collecting_managers_max_period_ended_dates(
|
133
|
+
self._collecting_data_managers.values()
|
134
|
+
)
|
135
|
+
|
136
|
+
def _calculate_exporting_managers_ended_at(self) -> None:
|
137
|
+
"""Определяет дату последнего успешного подэтапа экспорта у менеджеров Функций экспорта."""
|
138
|
+
self._exporting_data_manager_to_period_end = get_exporting_managers_max_period_ended_dates(
|
139
|
+
self._exporting_data_managers.values()
|
140
|
+
)
|
141
|
+
|
142
|
+
def prepare_collect_export_managers(self) -> None:
|
143
|
+
"""Подготовка менджеров сбора и экспорта."""
|
144
|
+
self._collect_transferred_entities()
|
145
|
+
self._collect_managers()
|
146
|
+
self._calculate_collecting_managers_logs_period_ended_at()
|
147
|
+
self._calculate_exporting_managers_ended_at()
|
edu_rdm_integration/consts.py
CHANGED
edu_rdm_integration/enums.py
CHANGED
@@ -6,6 +6,12 @@ from m3.db import (
|
|
6
6
|
BaseEnumerate,
|
7
7
|
)
|
8
8
|
|
9
|
+
from edu_rdm_integration.consts import (
|
10
|
+
FAST_TRANSFER_TASK_QUEUE_NAME,
|
11
|
+
LONG_TRANSFER_TASK_QUEUE_NAME,
|
12
|
+
TASK_QUEUE_NAME,
|
13
|
+
)
|
14
|
+
|
9
15
|
|
10
16
|
class ValueCodeEnumerate(BaseEnumerate):
|
11
17
|
"""
|
@@ -166,3 +172,28 @@ class CommandType(BaseEnumerate):
|
|
166
172
|
AUTO: 'Автоматический',
|
167
173
|
MANUAL: 'Ручной',
|
168
174
|
}
|
175
|
+
|
176
|
+
|
177
|
+
class EntityLevelQueueTypeEnum(BaseEnumerate):
|
178
|
+
"""Тип уровня очереди сущности."""
|
179
|
+
|
180
|
+
FAST = 1
|
181
|
+
BASE = 2
|
182
|
+
LONG = 3
|
183
|
+
|
184
|
+
values = {
|
185
|
+
FAST: 'Быстрая',
|
186
|
+
BASE: 'Основная',
|
187
|
+
LONG: 'Долгая'
|
188
|
+
}
|
189
|
+
|
190
|
+
celery_queue_maps = {
|
191
|
+
FAST: FAST_TRANSFER_TASK_QUEUE_NAME,
|
192
|
+
BASE: TASK_QUEUE_NAME,
|
193
|
+
LONG: LONG_TRANSFER_TASK_QUEUE_NAME
|
194
|
+
}
|
195
|
+
|
196
|
+
@classmethod
|
197
|
+
def get_queue_name(cls, level: int) -> Optional[str]:
|
198
|
+
"""Возвращает очередь."""
|
199
|
+
return cls.celery_queue_maps.get(level)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Generated by Django 3.2.24 on 2025-04-17 12:43
|
2
|
+
|
3
|
+
from django.db import (
|
4
|
+
migrations,
|
5
|
+
models,
|
6
|
+
)
|
7
|
+
|
8
|
+
|
9
|
+
class Migration(migrations.Migration):
|
10
|
+
|
11
|
+
dependencies = [
|
12
|
+
('edu_rdm_integration', '0015_set_exporting_sub_stage_status'),
|
13
|
+
]
|
14
|
+
|
15
|
+
operations = [
|
16
|
+
migrations.AddField(
|
17
|
+
model_name='transferredentity',
|
18
|
+
name='queue_level',
|
19
|
+
field=models.PositiveIntegerField(
|
20
|
+
choices=[(1, 'Быстрая'), (2, 'Основная'), (3, 'Долгая')], default=2, verbose_name='Уровень очереди'),
|
21
|
+
),
|
22
|
+
]
|
edu_rdm_integration/models.py
CHANGED
@@ -63,6 +63,7 @@ from m3_db_utils.models import (
|
|
63
63
|
|
64
64
|
from edu_rdm_integration.enums import (
|
65
65
|
CommandType,
|
66
|
+
EntityLevelQueueTypeEnum,
|
66
67
|
FileUploadStatusEnum,
|
67
68
|
)
|
68
69
|
from edu_rdm_integration.uploader_log.managers import (
|
@@ -932,6 +933,11 @@ class TransferredEntity(BaseObjectModel):
|
|
932
933
|
verbose_name='Включение экспорта для сущности',
|
933
934
|
default=True,
|
934
935
|
)
|
936
|
+
queue_level = PositiveIntegerField(
|
937
|
+
choices=EntityLevelQueueTypeEnum.get_choices(),
|
938
|
+
default=EntityLevelQueueTypeEnum.BASE,
|
939
|
+
verbose_name='Уровень очереди',
|
940
|
+
)
|
935
941
|
|
936
942
|
class Meta:
|
937
943
|
db_table = 'rdm_transferred_entity'
|
@@ -21,6 +21,7 @@ from edu_rdm_integration.models import (
|
|
21
21
|
TransferredEntity,
|
22
22
|
)
|
23
23
|
from edu_rdm_integration.registry.ui import (
|
24
|
+
TransferredEntityEditWindow,
|
24
25
|
TransferredEntityListWindow,
|
25
26
|
)
|
26
27
|
|
@@ -97,14 +98,27 @@ class TransferredEntitySaveAction(BaseAction):
|
|
97
98
|
"""Объявляет контекст экшна."""
|
98
99
|
return {
|
99
100
|
'id': {'type': 'str_list', 'default': []},
|
101
|
+
self.parent.id_param_name: {'type': 'int'}
|
100
102
|
}
|
101
103
|
|
102
104
|
def run(self, request, context):
|
103
105
|
"""Обеспечивает выполнение запроса."""
|
104
|
-
self.parent.
|
105
|
-
|
106
|
-
|
107
|
-
|
106
|
+
obj_id = getattr(context, self.parent.id_param_name)
|
107
|
+
if obj_id:
|
108
|
+
queue_level = getattr(context, 'queue_level', None)
|
109
|
+
if queue_level:
|
110
|
+
self.parent.model.objects.filter(
|
111
|
+
id=obj_id
|
112
|
+
).exclude(
|
113
|
+
queue_level=queue_level
|
114
|
+
).update(
|
115
|
+
queue_level=queue_level
|
116
|
+
)
|
117
|
+
else:
|
118
|
+
self.parent.model.objects.bulk_create([
|
119
|
+
self.parent.model(entity_id=key)
|
120
|
+
for key in context.id
|
121
|
+
])
|
108
122
|
|
109
123
|
return OperationResult(success=True)
|
110
124
|
|
@@ -121,6 +135,7 @@ class TransferredEntityPack(ObjectPack):
|
|
121
135
|
|
122
136
|
need_check_permission = True
|
123
137
|
list_window = TransferredEntityListWindow
|
138
|
+
edit_window = TransferredEntityEditWindow
|
124
139
|
|
125
140
|
columns = [
|
126
141
|
{
|
@@ -134,6 +149,10 @@ class TransferredEntityPack(ObjectPack):
|
|
134
149
|
{
|
135
150
|
'data_index': 'no_export',
|
136
151
|
'header': 'Отключение экспорта',
|
152
|
+
},
|
153
|
+
{
|
154
|
+
'data_index': 'queue_level',
|
155
|
+
'header': 'Уровень очереди',
|
137
156
|
}
|
138
157
|
]
|
139
158
|
|
@@ -1,14 +1,22 @@
|
|
1
1
|
from m3_ext.ui.all_components import (
|
2
2
|
ExtButton,
|
3
|
+
ExtDisplayField,
|
3
4
|
)
|
4
5
|
from objectpack.ui import (
|
6
|
+
BaseEditWindow,
|
5
7
|
BaseListWindow,
|
8
|
+
anchor100,
|
9
|
+
model_fields_to_controls,
|
6
10
|
)
|
7
11
|
|
8
12
|
from educommon.utils.ui import (
|
9
13
|
append_template_globals,
|
10
14
|
)
|
11
15
|
|
16
|
+
from edu_rdm_integration.models import (
|
17
|
+
TransferredEntity,
|
18
|
+
)
|
19
|
+
|
12
20
|
|
13
21
|
class TransferredEntityListWindow(BaseListWindow):
|
14
22
|
"""Окно реестра сущностей для сбора и экспорта данных."""
|
@@ -39,3 +47,39 @@ class TransferredEntityListWindow(BaseListWindow):
|
|
39
47
|
params['pack'].export_change_action.get_absolute_url()
|
40
48
|
)
|
41
49
|
self.pack = params['pack']
|
50
|
+
|
51
|
+
|
52
|
+
class TransferredEntityEditWindow(BaseEditWindow):
|
53
|
+
"""Окно редактирования сущностей."""
|
54
|
+
|
55
|
+
def _init_components(self):
|
56
|
+
"""Инициализация компонентов."""
|
57
|
+
super()._init_components()
|
58
|
+
|
59
|
+
self._controls = model_fields_to_controls(
|
60
|
+
TransferredEntity,
|
61
|
+
self,
|
62
|
+
field_list=[
|
63
|
+
'queue_level',
|
64
|
+
],
|
65
|
+
)
|
66
|
+
self.entity_name_field = ExtDisplayField(
|
67
|
+
read_only=True,
|
68
|
+
label='Сущность',
|
69
|
+
name='entity_name',
|
70
|
+
)
|
71
|
+
self._controls.insert(0, self.entity_name_field)
|
72
|
+
|
73
|
+
def _do_layout(self):
|
74
|
+
"""Расположение компонентов."""
|
75
|
+
super()._do_layout()
|
76
|
+
|
77
|
+
self.form.items.extend(list(map(anchor100, self._controls)))
|
78
|
+
|
79
|
+
def set_params(self, params, *args, **kwargs):
|
80
|
+
"""Простановка парметров."""
|
81
|
+
super().set_params(params, *args, **kwargs)
|
82
|
+
|
83
|
+
obj = params.get('object')
|
84
|
+
if obj:
|
85
|
+
self.entity_name_field.value = obj.entity_id
|
edu_rdm_integration/tasks.py
CHANGED
@@ -25,16 +25,15 @@ from educommon.async_task.models import (
|
|
25
25
|
RunningTask,
|
26
26
|
)
|
27
27
|
from educommon.async_task.tasks import (
|
28
|
-
PeriodicAsyncTask,
|
29
28
|
UniquePeriodicAsyncTask,
|
30
29
|
)
|
31
30
|
from educommon.utils.date import (
|
32
31
|
get_today_min_datetime,
|
33
32
|
)
|
34
|
-
from m3_db_utils.consts import (
|
35
|
-
DEFAULT_ORDER_NUMBER,
|
36
|
-
)
|
37
33
|
|
34
|
+
from edu_rdm_integration.base import (
|
35
|
+
BaseTransferLatestEntitiesDataMixin,
|
36
|
+
)
|
38
37
|
from edu_rdm_integration.collect_and_export_data.models import (
|
39
38
|
EduRdmCollectDataCommandProgress,
|
40
39
|
EduRdmExportDataCommandProgress,
|
@@ -46,12 +45,13 @@ from edu_rdm_integration.collect_data.helpers import (
|
|
46
45
|
set_failed_status_suspended_collecting_data_stages,
|
47
46
|
)
|
48
47
|
from edu_rdm_integration.consts import (
|
49
|
-
|
50
|
-
|
48
|
+
FAST_TRANSFER_TASK_QUEUE_NAME,
|
49
|
+
LONG_TRANSFER_TASK_QUEUE_NAME,
|
51
50
|
TASK_QUEUE_NAME,
|
52
51
|
)
|
53
52
|
from edu_rdm_integration.enums import (
|
54
53
|
CommandType,
|
54
|
+
EntityLevelQueueTypeEnum,
|
55
55
|
FileUploadStatusEnum,
|
56
56
|
)
|
57
57
|
from edu_rdm_integration.export_data.export import (
|
@@ -66,18 +66,12 @@ from edu_rdm_integration.export_data.queue import (
|
|
66
66
|
)
|
67
67
|
from edu_rdm_integration.helpers import (
|
68
68
|
UploadStatusHelper,
|
69
|
-
get_collecting_managers_max_period_ended_dates,
|
70
|
-
get_exporting_managers_max_period_ended_dates,
|
71
69
|
save_command_log_link,
|
72
70
|
)
|
73
71
|
from edu_rdm_integration.models import (
|
74
72
|
ExportingDataSubStageUploaderClientLog,
|
75
|
-
RegionalDataMartEntityEnum,
|
76
73
|
TransferredEntity,
|
77
74
|
)
|
78
|
-
from edu_rdm_integration.storages import (
|
79
|
-
RegionalDataMartEntityStorage,
|
80
|
-
)
|
81
75
|
|
82
76
|
|
83
77
|
if TYPE_CHECKING:
|
@@ -85,10 +79,6 @@ if TYPE_CHECKING:
|
|
85
79
|
datetime,
|
86
80
|
)
|
87
81
|
|
88
|
-
from function_tools.managers import (
|
89
|
-
RunnerManager,
|
90
|
-
)
|
91
|
-
|
92
82
|
|
93
83
|
class RDMCheckUploadStatus(UniquePeriodicAsyncTask):
|
94
84
|
"""Периодическая задача для сбора статусов по загрузке файла в витрину."""
|
@@ -154,61 +144,24 @@ class CheckSuspendedExportedStagePeriodicTask(UniquePeriodicAsyncTask):
|
|
154
144
|
)
|
155
145
|
|
156
146
|
|
157
|
-
class
|
158
|
-
"""
|
159
|
-
|
160
|
-
queue = TASK_QUEUE_NAME
|
161
|
-
routing_key = TASK_QUEUE_NAME
|
162
|
-
description = 'Периодическая задача сбора и экспорта данных РВД'
|
163
|
-
lock_expire_seconds = settings.RDM_TRANSFER_TASK_LOCK_EXPIRE_SECONDS
|
164
|
-
task_type = AsyncTaskType.UNKNOWN
|
165
|
-
run_every = crontab(
|
166
|
-
minute=settings.RDM_TRANSFER_TASK_MINUTE,
|
167
|
-
hour=settings.RDM_TRANSFER_TASK_HOUR,
|
168
|
-
day_of_week=settings.RDM_TRANSFER_TASK_DAY_OF_WEEK,
|
169
|
-
)
|
147
|
+
class BaseTransferLatestEntitiesDataPeriodicTask(BaseTransferLatestEntitiesDataMixin, UniquePeriodicAsyncTask):
|
148
|
+
"""Базовая периодическая задача сбора и выгрузки данных для переиспользования в разных очередях."""
|
170
149
|
|
171
150
|
def __init__(self) -> None:
|
172
151
|
super().__init__()
|
173
152
|
|
174
|
-
self.
|
175
|
-
self._collecting_data_manager_to_logs_period_end: dict[str, 'datetime'] = {}
|
176
|
-
|
177
|
-
self._exporting_data_managers: dict[str, type['RunnerManager']] = {}
|
178
|
-
self._exporting_data_manager_to_period_end: dict[str, 'datetime'] = {}
|
179
|
-
|
180
|
-
self._transferred_entities = []
|
181
|
-
self._entites_models_map = defaultdict(list)
|
182
|
-
|
183
|
-
def process(self, *args, **kwargs):
|
184
|
-
"""Выполняет задачу."""
|
185
|
-
super().process(*args, **kwargs)
|
186
|
-
|
187
|
-
self._collect_transferred_entities()
|
188
|
-
self._collect_managers()
|
189
|
-
self._calculate_collecting_managers_logs_period_ended_at()
|
190
|
-
self._calculate_exporting_managers_ended_at()
|
191
|
-
|
192
|
-
task_id = RunningTask.objects.filter(
|
193
|
-
pk=self.request.id,
|
194
|
-
).values_list('pk', flat=True).first()
|
153
|
+
self._period_ended_at: Optional[datetime] = None
|
195
154
|
|
196
|
-
|
155
|
+
def _get_period_ended_at(self):
|
156
|
+
"""Определяет единую дату окончания периода сбора.
|
197
157
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
if model_enum_value.key not in collected_entity_models:
|
204
|
-
self._run_collect_model_data(model_enum_value.key, task_id)
|
205
|
-
collected_entity_models.add(model_enum_value.key)
|
158
|
+
Это нужно для исключения разного времени окончания сбора при явном запуске функции - чтобы
|
159
|
+
избежать ошибки экспорта при недосборе данных.
|
160
|
+
"""
|
161
|
+
if not self._period_ended_at:
|
162
|
+
self._period_ended_at = timezone.now()
|
206
163
|
|
207
|
-
|
208
|
-
if export_enabled:
|
209
|
-
self._run_export_entity_data(entity_enum.key, task_id)
|
210
|
-
except Exception:
|
211
|
-
continue
|
164
|
+
return self._period_ended_at
|
212
165
|
|
213
166
|
def _run_collect_model_data(self, model: str, task_id: str) -> None:
|
214
167
|
"""Запускает сбор данных модели РВД."""
|
@@ -229,54 +182,6 @@ class TransferLatestEntitiesDataPeriodicTask(UniquePeriodicAsyncTask):
|
|
229
182
|
command.refresh_from_db(fields=['stage_id'])
|
230
183
|
save_command_log_link(command, settings.RDM_EXPORT_LOG_DIR)
|
231
184
|
|
232
|
-
def _collect_transferred_entities(self) -> None:
|
233
|
-
"""Собирает сущности РВД, по которым будет произведен сбор и экспорт данных."""
|
234
|
-
self._transferred_entities = [
|
235
|
-
(RegionalDataMartEntityEnum.get_model_enum_value(key=entity), export_enabled)
|
236
|
-
for entity, export_enabled in TransferredEntity.objects.values_list('entity', 'export_enabled')
|
237
|
-
]
|
238
|
-
|
239
|
-
# Собираем словарь по сущностям с моделями для сборки
|
240
|
-
for entity, _ in self._transferred_entities:
|
241
|
-
self._entites_models_map[entity.key].extend(
|
242
|
-
(model_enum for model_enum in (*entity.additional_model_enums, entity.main_model_enum)
|
243
|
-
if model_enum.order_number != DEFAULT_ORDER_NUMBER)
|
244
|
-
)
|
245
|
-
|
246
|
-
def _collect_managers(self) -> None:
|
247
|
-
"""Собирает менеджеры Функций для сбора и выгрузки данных."""
|
248
|
-
entity_storage = RegionalDataMartEntityStorage()
|
249
|
-
entity_storage.prepare()
|
250
|
-
|
251
|
-
collecting_models_data_managers_map = entity_storage.prepare_entities_manager_map(
|
252
|
-
tags={REGIONAL_DATA_MART_INTEGRATION_COLLECTING_DATA},
|
253
|
-
)
|
254
|
-
exporting_entities_data_managers_map = entity_storage.prepare_entities_manager_map(
|
255
|
-
tags={REGIONAL_DATA_MART_INTEGRATION_EXPORTING_DATA},
|
256
|
-
)
|
257
|
-
|
258
|
-
for entity_key, entity_models in self._entites_models_map.items():
|
259
|
-
for entity_model in entity_models:
|
260
|
-
collect_manager_class = collecting_models_data_managers_map.get(entity_model.key)
|
261
|
-
if collect_manager_class:
|
262
|
-
self._collecting_data_managers[entity_model.key] = collect_manager_class
|
263
|
-
|
264
|
-
export_manager_class = exporting_entities_data_managers_map.get(entity_key)
|
265
|
-
if export_manager_class:
|
266
|
-
self._exporting_data_managers[entity_key] = export_manager_class
|
267
|
-
|
268
|
-
def _calculate_collecting_managers_logs_period_ended_at(self) -> None:
|
269
|
-
"""Определяет дату последнего успешного этапа сбора у менеджеров Функций сбора."""
|
270
|
-
self._collecting_data_manager_to_logs_period_end = get_collecting_managers_max_period_ended_dates(
|
271
|
-
self._collecting_data_managers.values()
|
272
|
-
)
|
273
|
-
|
274
|
-
def _calculate_exporting_managers_ended_at(self) -> None:
|
275
|
-
"""Определяет дату последнего успешного подэтапа экспорта у менеджеров Функций экспорта."""
|
276
|
-
self._exporting_data_manager_to_period_end = get_exporting_managers_max_period_ended_dates(
|
277
|
-
self._exporting_data_managers.values()
|
278
|
-
)
|
279
|
-
|
280
185
|
def _create_collect_command(self, model: str, task_id: str) -> EduRdmCollectDataCommandProgress:
|
281
186
|
"""Создает команду сбора данных моделей РВД."""
|
282
187
|
manager = self._collecting_data_managers[model]
|
@@ -286,7 +191,7 @@ class TransferLatestEntitiesDataPeriodicTask(UniquePeriodicAsyncTask):
|
|
286
191
|
)
|
287
192
|
|
288
193
|
period_started_at = manager_last_collected
|
289
|
-
period_ended_at =
|
194
|
+
period_ended_at = self._get_period_ended_at()
|
290
195
|
|
291
196
|
return EduRdmCollectDataCommandProgress.objects.create(
|
292
197
|
model_id=model,
|
@@ -340,6 +245,91 @@ class TransferLatestEntitiesDataPeriodicTask(UniquePeriodicAsyncTask):
|
|
340
245
|
task_id=self.request.id,
|
341
246
|
)
|
342
247
|
|
248
|
+
def process(self, *args, **kwargs):
|
249
|
+
"""Выполняет задачу."""
|
250
|
+
super().process(*args, **kwargs)
|
251
|
+
|
252
|
+
self._period_ended_at = None
|
253
|
+
self.prepare_collect_export_managers()
|
254
|
+
|
255
|
+
task_id = RunningTask.objects.filter(
|
256
|
+
pk=self.request.id,
|
257
|
+
).values_list('pk', flat=True).first()
|
258
|
+
|
259
|
+
collected_entity_models = set()
|
260
|
+
|
261
|
+
for entity_enum, export_enabled in sorted(
|
262
|
+
self._transferred_entities, key=lambda entity: entity[0].order_number
|
263
|
+
):
|
264
|
+
entity_models = self._entites_models_map.get(entity_enum.key, ())
|
265
|
+
for model_enum_value in entity_models:
|
266
|
+
if model_enum_value.key not in collected_entity_models:
|
267
|
+
collected_entity_models.add(model_enum_value.key)
|
268
|
+
try:
|
269
|
+
self._run_collect_model_data(model_enum_value.key, task_id)
|
270
|
+
except Exception:
|
271
|
+
continue
|
272
|
+
|
273
|
+
try:
|
274
|
+
if export_enabled:
|
275
|
+
self._run_export_entity_data(entity_enum.key, task_id)
|
276
|
+
except Exception:
|
277
|
+
continue
|
278
|
+
|
279
|
+
|
280
|
+
class TransferLatestEntitiesDataPeriodicTask(BaseTransferLatestEntitiesDataPeriodicTask):
|
281
|
+
"""Периодическая задача сбора и выгрузки данных."""
|
282
|
+
|
283
|
+
queue = TASK_QUEUE_NAME
|
284
|
+
routing_key = TASK_QUEUE_NAME
|
285
|
+
description = 'Периодическая задача сбора и экспорта данных РВД'
|
286
|
+
lock_expire_seconds = settings.RDM_TRANSFER_TASK_LOCK_EXPIRE_SECONDS
|
287
|
+
task_type = AsyncTaskType.UNKNOWN
|
288
|
+
run_every = crontab(
|
289
|
+
minute=settings.RDM_TRANSFER_TASK_MINUTE,
|
290
|
+
hour=settings.RDM_TRANSFER_TASK_HOUR,
|
291
|
+
day_of_week=settings.RDM_TRANSFER_TASK_DAY_OF_WEEK,
|
292
|
+
)
|
293
|
+
|
294
|
+
def get_entity_qs(self) -> 'QuerySet[TransferredEntity]':
|
295
|
+
return TransferredEntity.objects.filter(queue_level=EntityLevelQueueTypeEnum.BASE)
|
296
|
+
|
297
|
+
|
298
|
+
class TransferLatestEntitiesDataFastPeriodicTask(BaseTransferLatestEntitiesDataPeriodicTask):
|
299
|
+
"""Периодическая задача сбора и выгрузки данных для быстрого уровня очереди."""
|
300
|
+
|
301
|
+
queue = FAST_TRANSFER_TASK_QUEUE_NAME
|
302
|
+
routing_key = FAST_TRANSFER_TASK_QUEUE_NAME
|
303
|
+
description = 'Периодическая задача сбора и экспорта данных РВД (быстрый уровень)'
|
304
|
+
lock_expire_seconds = settings.RDM_FAST_TRANSFER_TASK_LOCK_EXPIRE_SECONDS
|
305
|
+
task_type = AsyncTaskType.UNKNOWN
|
306
|
+
run_every = crontab(
|
307
|
+
minute=settings.RDM_FAST_TRANSFER_TASK_MINUTE,
|
308
|
+
hour=settings.RDM_FAST_TRANSFER_TASK_HOUR,
|
309
|
+
day_of_week=settings.RDM_FAST_TRANSFER_TASK_DAY_OF_WEEK,
|
310
|
+
)
|
311
|
+
|
312
|
+
def get_entity_qs(self) -> 'QuerySet[TransferredEntity]':
|
313
|
+
return TransferredEntity.objects.filter(queue_level=EntityLevelQueueTypeEnum.FAST)
|
314
|
+
|
315
|
+
|
316
|
+
class TransferLatestEntitiesDataLongPeriodicTask(BaseTransferLatestEntitiesDataPeriodicTask):
|
317
|
+
"""Периодическая задача сбора и выгрузки данных для долгого уровня очереди."""
|
318
|
+
|
319
|
+
queue = LONG_TRANSFER_TASK_QUEUE_NAME
|
320
|
+
routing_key = LONG_TRANSFER_TASK_QUEUE_NAME
|
321
|
+
description = 'Периодическая задача сбора и экспорта данных РВД (долгий уровень)'
|
322
|
+
lock_expire_seconds = settings.RDM_LONG_TRANSFER_TASK_LOCK_EXPIRE_SECONDS
|
323
|
+
task_type = AsyncTaskType.UNKNOWN
|
324
|
+
run_every = crontab(
|
325
|
+
minute=settings.RDM_LONG_TRANSFER_TASK_MINUTE,
|
326
|
+
hour=settings.RDM_LONG_TRANSFER_TASK_HOUR,
|
327
|
+
day_of_week=settings.RDM_LONG_TRANSFER_TASK_DAY_OF_WEEK,
|
328
|
+
)
|
329
|
+
|
330
|
+
def get_entity_qs(self) -> 'QuerySet[TransferredEntity]':
|
331
|
+
return TransferredEntity.objects.filter(queue_level=EntityLevelQueueTypeEnum.LONG)
|
332
|
+
|
343
333
|
|
344
334
|
class UploadDataAsyncTask(UniquePeriodicAsyncTask):
|
345
335
|
"""Формирование очереди файлов и их отправка."""
|
@@ -383,3 +373,5 @@ celery_app.register_task(RDMCheckUploadStatus)
|
|
383
373
|
celery_app.register_task(CheckSuspendedExportedStagePeriodicTask)
|
384
374
|
celery_app.register_task(TransferLatestEntitiesDataPeriodicTask)
|
385
375
|
celery_app.register_task(UploadDataAsyncTask)
|
376
|
+
celery_app.register_task(TransferLatestEntitiesDataFastPeriodicTask)
|
377
|
+
celery_app.register_task(TransferLatestEntitiesDataLongPeriodicTask)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: edu-rdm-integration
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.6.0
|
4
4
|
Summary: Интеграция с Региональной витриной данных
|
5
5
|
Author-email: BARS Group <education_dev@bars.group>
|
6
6
|
Project-URL: Homepage, https://stash.bars-open.ru/projects/EDUBASE/repos/edu_rdm_integration/browse
|
@@ -78,6 +78,19 @@ Dynamic: license-file
|
|
78
78
|
|
79
79
|
Стоит обратить внимание, что сущности РВД могут содержать в себе данные из нескольких моделей РВД.
|
80
80
|
|
81
|
+
Очереди для периодических задач сборки и выгрузки данных
|
82
|
+
: Важно учитывать, что с версии пакета 3.6 вводится две новые очереди и соответсвущие этим очередям периодические задачи
|
83
|
+
сбора и выгрузки данных. Очередь для сущности указывается в реестре "Сущности для сбора и экспорта данных" - по умолчанию все
|
84
|
+
сущности относятся к основной очереди.
|
85
|
+
Итого - нужно настроить три очереди для работы.
|
86
|
+
|
87
|
+
- "Быстрая" очередь - RDM_FAST - для сущностей, по которым данные должны отдаваться каждые 5/10/15 минут по требованиям
|
88
|
+
витрины. Периодическая задача - TransferLatestEntitiesDataFastPeriodicTask.
|
89
|
+
- Основная очередь (та которая была до версии 3.6) - RDM- ля всех сущностей по умолчанию.
|
90
|
+
Периодическая задача - TransferLatestEntitiesDataFastPeriodicTask.
|
91
|
+
- "Долгая" очередь - RDM_LONG - для сущностей по которым идет долгий сбор, например для расчетных сущностей.
|
92
|
+
Периодическая задача - TransferLatestEntitiesDataLongPeriodicTask.
|
93
|
+
|
81
94
|
## Требования к окружению
|
82
95
|
|
83
96
|
Для работы требуется Python >=3.9. Так же в зависимостях есть внутренние пакеты:
|
@@ -129,6 +142,39 @@ Dynamic: license-file
|
|
129
142
|
('uploader_client', 'ENABLE_REQUEST_EMULATION'): False,
|
130
143
|
})
|
131
144
|
```
|
145
|
+
С версии пакета 3.6 добавляются новые настройки для двух периодических задач разных очередей сбора и выгрузки данных
|
146
|
+
```
|
147
|
+
PROJECT_DEFAULT_CONFIG.update({
|
148
|
+
# Настройки РВД
|
149
|
+
('rdm_general', 'EXPORT_ENTITY_ID_PREFIX'): '', # Дефолтное значение нужно изменить на специфическое системе
|
150
|
+
('rdm_general', 'COLLECT_CHUNK_SIZE'): 500,
|
151
|
+
('rdm_general', 'EXPORT_CHUNK_SIZE'): 500,
|
152
|
+
('rdm_transfer_task', 'MINUTE'): '0',
|
153
|
+
('rdm_transfer_task', 'HOUR'): '*/4',
|
154
|
+
('rdm_transfer_task', 'DAY_OF_WEEK'): '*',
|
155
|
+
('rdm_transfer_task', 'LOCK_EXPIRE_SECONDS'): 21600,
|
156
|
+
('rdm_transfer_task', 'TIMEDELTA'): 3600,
|
157
|
+
('rdm_transfer_task', 'ENTITIES'): '',
|
158
|
+
('rdm_transfer_task_fast', 'MINUTE'): '*/5',
|
159
|
+
('rdm_transfer_task_fast', 'HOUR'): '*',
|
160
|
+
('rdm_transfer_task_fast', 'DAY_OF_WEEK'): '*',
|
161
|
+
('rdm_transfer_task_fast', 'LOCK_EXPIRE_SECONDS'): 1800,
|
162
|
+
('rdm_transfer_task_long', 'MINUTE'): '0',
|
163
|
+
('rdm_transfer_task_long', 'HOUR'): '*/6',
|
164
|
+
('rdm_transfer_task_long', 'DAY_OF_WEEK'): '*',
|
165
|
+
('rdm_transfer_task_long', 'LOCK_EXPIRE_SECONDS'): 28800,
|
166
|
+
('rdm_upload_status_task', 'MINUTE'): '*/30',
|
167
|
+
('rdm_upload_status_task', 'HOUR'): '*',
|
168
|
+
('rdm_upload_status_task', 'DAY_OF_WEEK'): '*',
|
169
|
+
('rdm_upload_status_task', 'LOCK_EXPIRE_SECONDS'): 7200,
|
170
|
+
('uploader_client', 'URL'): 'http://localhost:8090',
|
171
|
+
('uploader_client', 'DATAMART_NAME'): '',
|
172
|
+
('uploader_client', 'REQUEST_RETRIES'): 10,
|
173
|
+
('uploader_client', 'REQUEST_TIMEOUT'): 10,
|
174
|
+
('uploader_client', 'ENABLE_REQUEST_EMULATION'): False,
|
175
|
+
})
|
176
|
+
|
177
|
+
```
|
132
178
|
- Получение значений настроек из конфигурационного файла в settings.py:
|
133
179
|
|
134
180
|
```
|
@@ -187,7 +233,21 @@ Dynamic: license-file
|
|
187
233
|
RDM_UPLOADER_CLIENT_ENABLE_REQUEST_EMULATION = conf.get_bool('uploader_client', 'ENABLE_REQUEST_EMULATION')
|
188
234
|
|
189
235
|
```
|
190
|
-
|
236
|
+
С версии пакета 3.6 добавляются настройки для двух новых периодических задач
|
237
|
+
```
|
238
|
+
# Настройка запуска периодической задачи выгрузки данных - быстрая очередь:
|
239
|
+
RDM_FAST_TRANSFER_TASK_MINUTE = conf.get('rdm_transfer_task_fast', 'MINUTE')
|
240
|
+
RDM_FAST_TRANSFER_TASK_HOUR = conf.get('rdm_transfer_task_fast', 'HOUR')
|
241
|
+
RDM_FAST_TRANSFER_TASK_DAY_OF_WEEK = conf.get('rdm_transfer_task_fast', 'DAY_OF_WEEK')
|
242
|
+
RDM_FAST_TRANSFER_TASK_LOCK_EXPIRE_SECONDS = conf.get_int('rdm_transfer_task_fast', 'LOCK_EXPIRE_SECONDS')
|
243
|
+
|
244
|
+
# Настройка запуска периодической задачи выгрузки данных - долгая очередь расчетных моделей:
|
245
|
+
RDM_LONG_TRANSFER_TASK_MINUTE = conf.get('rdm_transfer_task_long', 'MINUTE')
|
246
|
+
RDM_LONG_TRANSFER_TASK_HOUR = conf.get('rdm_transfer_task_long', 'HOUR')
|
247
|
+
RDM_LONG_TRANSFER_TASK_DAY_OF_WEEK = conf.get('rdm_transfer_task_long', 'DAY_OF_WEEK')
|
248
|
+
RDM_LONG_TRANSFER_TASK_LOCK_EXPIRE_SECONDS = conf.get_int('rdm_transfer_task_long', 'LOCK_EXPIRE_SECONDS')
|
249
|
+
|
250
|
+
```
|
191
251
|
Перечень настроек в settings.py указан в таблице ниже.
|
192
252
|
|
193
253
|
| Название настройки в settings | Описание | Значение по умолчанию |
|
@@ -211,7 +271,18 @@ Dynamic: license-file
|
|
211
271
|
| RDM_UPLOAD_STATUS_TASK_LOCK_EXPIRE_SECONDS | Время по истечении которого, блокировка может быть снята (в секунадх) | 3600 |
|
212
272
|
| RDM_CHECK_SUSPEND_TASK_STAGE_TIMEOUT | Дельта для определения зависшего подэтапа. Минута | 120 |
|
213
273
|
|
214
|
-
|
274
|
+
С версии пакета 3.6 добавляются новые настройки
|
275
|
+
|
276
|
+
| Название настройки в settings | Описание | Значение по умолчанию |
|
277
|
+
|--------------------------------------------|----------------------------------------------------------------------------------------|-----------------------|
|
278
|
+
| RDM_FAST_TRANSFER_TASK_MINUTE | Настройка запуска периодической задачи (быстрая очередь) выгрузки данных. Минута | '*/5' |
|
279
|
+
| RDM_FAST_TRANSFER_TASK_HOUR | Настройка запуска периодической задачи (быстрая очередь) выгрузки данных. Час | '*' |
|
280
|
+
| RDM_FAST_TRANSFER_TASK_DAY_OF_WEEK | Настройка запуска периодической задачи (быстрая очередь) выгрузки данных. День недели | '*' |
|
281
|
+
| RDM_FAST_TRANSFER_TASK_LOCK_EXPIRE_SECONDS | Время по истечении которого, блокировка может быть снята (в секунадх) | 1800 |
|
282
|
+
| RDM_LONG_TRANSFER_TASK_MINUTE | Настройка запуска периодической задачи (долгая очередь) выгрузки данных. Минута | 0 |
|
283
|
+
| RDM_LONG_TRANSFER_TASK_HOUR | Настройка запуска периодической задачи (долгая очередь) выгрузки данных. Час | '*/6' |
|
284
|
+
| RDM_LONG_TRANSFER_TASK_DAY_OF_WEEK | Настройка запуска периодической задачи (долгая очередь) выгрузки данных. День недели | '*' |
|
285
|
+
| RDM_LONG_TRANSFER_TASK_LOCK_EXPIRE_SECONDS | Время по истечении которого, блокировка может быть снята (в секунадх) | 28800 |
|
215
286
|
|
216
287
|
- В дефолтный конфиг проекта необходимо добавить:
|
217
288
|
|
@@ -267,7 +338,21 @@ Dynamic: license-file
|
|
267
338
|
# Включить эмуляцию отправки запросов
|
268
339
|
ENABLE_REQUEST_EMULATION = True
|
269
340
|
```
|
341
|
+
- С версии 3.6 в деволтный конфиг также нужно добавить два дополнительных раздела
|
342
|
+
```
|
343
|
+
|
344
|
+
[rdm_transfer_task_fast]
|
345
|
+
MINUTE=*/2
|
346
|
+
HOUR=*
|
347
|
+
DAY_OF_WEEK=*
|
348
|
+
LOCK_EXPIRE_SECONDS = 1800
|
270
349
|
|
350
|
+
[rdm_transfer_task_long]
|
351
|
+
MINUTE=*/15
|
352
|
+
HOUR=*
|
353
|
+
DAY_OF_WEEK=*
|
354
|
+
LOCK_EXPIRE_SECONDS = 21600
|
355
|
+
```
|
271
356
|
На основе дефолтного конфига произвести конфигурирование приложений.
|
272
357
|
|
273
358
|
## Сборка и распространение
|
@@ -1,18 +1,18 @@
|
|
1
1
|
edu_rdm_integration/__init__.py,sha256=fVCvQ7QGI_iCyAeE8dMapyY8gOM617ye5GQqAVGPlZI,72
|
2
2
|
edu_rdm_integration/app_meta.py,sha256=v5IU69yaeLbyHF0Ln6iPN_IfizbtF3rCWrz2n71m8dU,337
|
3
|
-
edu_rdm_integration/app_settings.py,sha256=
|
3
|
+
edu_rdm_integration/app_settings.py,sha256=9alLUaen3DRCD7wngNyNI2oXf98R-qW1rvKpTvLTMrQ,3684
|
4
4
|
edu_rdm_integration/apps.py,sha256=Dl1og2yZcRyJmqrifUNIjLZ9Us2jw2mgAP1_q2fg29A,3699
|
5
|
-
edu_rdm_integration/base.py,sha256=
|
6
|
-
edu_rdm_integration/consts.py,sha256=
|
5
|
+
edu_rdm_integration/base.py,sha256=1NgLZd0KZRRgUcVfufVIpDJU2coT2zksFGDaX4fWqps,5967
|
6
|
+
edu_rdm_integration/consts.py,sha256=QnL9TqTKuJ0MrysqtqHvtCwOFbS1T7iwcfUZGjVsZTU,1166
|
7
7
|
edu_rdm_integration/entities.py,sha256=mhVeB88A-VD5IAzZCNeI1qnkvNoZ8LPiLBdqk1yA3Jc,14541
|
8
|
-
edu_rdm_integration/enums.py,sha256=
|
8
|
+
edu_rdm_integration/enums.py,sha256=RpQIZM1iSgFbYDHfwrbT-BwgRf-N9ZZnJgx8UyRFQ2o,4978
|
9
9
|
edu_rdm_integration/helpers.py,sha256=wr4ddI9LNsmcwdZMEUYT070YnM49ixbAQ0-tBh4gp08,14808
|
10
10
|
edu_rdm_integration/mapping.py,sha256=1B6TsC4Os9wiM8L8BChnCNv_iWqjeWu3bdDsqKVsId0,616
|
11
|
-
edu_rdm_integration/models.py,sha256=
|
11
|
+
edu_rdm_integration/models.py,sha256=pimS5MIQzRl4b9RIUUCSxsAA54zB_aoiEY0evrywpHM,33325
|
12
12
|
edu_rdm_integration/redis_cache.py,sha256=SP_rcL5t6PTVLOnEYn_NTX0Z666VdZT4By2pyED24Z4,1537
|
13
13
|
edu_rdm_integration/signals.py,sha256=3eRlpkDcFCF6TN80-QM8yBYLcyozzcmoPjz6r4_ApWg,73
|
14
14
|
edu_rdm_integration/storages.py,sha256=G4Q4tIyJdEyb9ka551PADCFIm66bpsJe9VBRcvQhLMI,6745
|
15
|
-
edu_rdm_integration/tasks.py,sha256=
|
15
|
+
edu_rdm_integration/tasks.py,sha256=LyFc91ntwlYZoLN9-gYEzS_vjBnvVpF3D5N7ubtp6FM,15136
|
16
16
|
edu_rdm_integration/typing.py,sha256=2asD8biX0l_DVqJSU4y19-zzEBJMk967PUj3UhzICzs,785
|
17
17
|
edu_rdm_integration/utils.py,sha256=NNRfblJ9QoX07qUa2kfKG0jM3fHJ3oaDvG2zwj0As70,12120
|
18
18
|
edu_rdm_integration/adapters/__init__.py,sha256=cU0swn4Ny5ZQz5buWRcWsT1mpWuUFJaUlHf2l7TtEBo,83
|
@@ -167,10 +167,11 @@ edu_rdm_integration/migrations/0012_exportingdatasubstageattachment_attachment_s
|
|
167
167
|
edu_rdm_integration/migrations/0013_set_attachment_size.py,sha256=Gol8T137gdaCTSkJ2e4as5x4gfqeouZmgWgkOl7zxCQ,2048
|
168
168
|
edu_rdm_integration/migrations/0014_uploaddatacommand.py,sha256=Hh0vKKiGgKOvY1kBAcmway4dSYUXwVArHAc9YrsjCIU,2079
|
169
169
|
edu_rdm_integration/migrations/0015_set_exporting_sub_stage_status.py,sha256=zVe2baNq8JYzMPRmtpAwplmgKHOP3lwMKHLo_yRz0QE,790
|
170
|
+
edu_rdm_integration/migrations/0016_transferredentity_queue_level.py,sha256=xMnDYE5_fK8Sdwq-1GwJlJZlVoz4e4yml0SDueKcbUA,587
|
170
171
|
edu_rdm_integration/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
171
172
|
edu_rdm_integration/registry/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
172
|
-
edu_rdm_integration/registry/actions.py,sha256
|
173
|
-
edu_rdm_integration/registry/ui.py,sha256=
|
173
|
+
edu_rdm_integration/registry/actions.py,sha256=-CHe95jbxO9JAEaOx6nV6Avn75ynppvZRWN8YPc6c6s,6074
|
174
|
+
edu_rdm_integration/registry/ui.py,sha256=v4GqbQUcoeHxfUPUYORuj4DfzIp49diY-F1hyL3TCPo,2592
|
174
175
|
edu_rdm_integration/templates/ui-js/transferred-entity-list.js,sha256=IWEZ9JoTxD5-CLic5v07XHWW0iGRWk-cjeGVSzU4yKg,1117
|
175
176
|
edu_rdm_integration/uploader_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
176
177
|
edu_rdm_integration/uploader_log/actions.py,sha256=2ckgI1PKgVcLYkbhtbK_bfv_6lDxpiIRSk1uPCIL-gg,6755
|
@@ -179,8 +180,8 @@ edu_rdm_integration/uploader_log/enums.py,sha256=rgSO3BL2rh2xpfm0Pt4waQW8fB1VMJL
|
|
179
180
|
edu_rdm_integration/uploader_log/managers.py,sha256=OFdToWV8qhdfeGNpd-UWAmSEISzixmVQ6LF75EW7gzA,3248
|
180
181
|
edu_rdm_integration/uploader_log/ui.py,sha256=YM9Buqp2wxE95Wf5gvAATBzuYzDOossK1sEmvFk07cI,2110
|
181
182
|
edu_rdm_integration/uploader_log/templates/ui-js/object-grid-buttons.js,sha256=2xyGe0wdVokM0RhpzRzcRvJPBkBmPe3SlZry4oP4Nzs,6201
|
182
|
-
edu_rdm_integration-3.
|
183
|
-
edu_rdm_integration-3.
|
184
|
-
edu_rdm_integration-3.
|
185
|
-
edu_rdm_integration-3.
|
186
|
-
edu_rdm_integration-3.
|
183
|
+
edu_rdm_integration-3.6.0.dist-info/licenses/LICENSE,sha256=uw43Gjjj-1vXWCItfSrNDpbejnOwZMrNerUh8oWbq8Q,3458
|
184
|
+
edu_rdm_integration-3.6.0.dist-info/METADATA,sha256=rV5ZHyItlhOmIl5k0jC3nfJTrv6k7Cmr_S-bXUsI480,27415
|
185
|
+
edu_rdm_integration-3.6.0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
186
|
+
edu_rdm_integration-3.6.0.dist-info/top_level.txt,sha256=nRJV0O14UtNE-jGIYG03sohgFnZClvf57H5m6VBXe9Y,20
|
187
|
+
edu_rdm_integration-3.6.0.dist-info/RECORD,,
|
File without changes
|
{edu_rdm_integration-3.5.10.dist-info → edu_rdm_integration-3.6.0.dist-info}/licenses/LICENSE
RENAMED
File without changes
|
File without changes
|