-
Notifications
You must be signed in to change notification settings - Fork 13
/
fill_db.py
354 lines (329 loc) · 15.2 KB
/
fill_db.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
import asyncio
import string
import sys
from contextlib import asynccontextmanager
from datetime import datetime, timedelta
from random import choice, choices, randint, sample
from faker import Faker
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
from src.bot.constants import enum
from src.core.db import get_session
from src.core.db.models import AdminUser, Category, ExternalSiteUser, Task, UnsubscribeReason, User
from src.core.enums import UserRoles, UserStatus
CHARACTERS = string.ascii_uppercase + string.digits
CATEGORIES_FILL_DATA = []
CATEGORIES_TEST_DATA = [
{"id": "1", "name": "Дизайн и верстка"},
{"id": "2", "name": "Маркетинг и коммуникации"},
{"id": "3", "name": "Переводы"},
{"id": "4", "name": "IT"},
{"id": "5", "name": "Юридические услуги"},
{"id": "6", "name": "Стратегический консалтинг"},
{"id": "7", "name": "Фото и видео"},
{"id": "8", "name": "Обучение и тренинги"},
{"id": "9", "name": "Финансы и фандрайзинг"},
{"id": "10", "name": "Менеджмент"},
]
SUBCATEGORIES_TEST_DATA = [
{"id": "1", "name": "Новичок"},
{"id": "2", "name": "Архивный новичок"},
{"id": "3", "name": "Опытный"},
{"id": "4", "name": "Архивный опытный"},
{"id": "5", "name": "Профессионал"},
{"id": "6", "name": "Архивный профессионал"},
]
TEST_LOCATION = [
"Москва",
"Санкт-Петербург",
"Новосибирск",
"Екатеринбург",
"Казань",
"Нижний Новгород",
"Челябинск",
"Самара",
"Омск",
"Ростов-на-Дону",
]
TEST_ORGANIZATION = [
"Нефть без границ",
"Транспортный гигант-2",
"Российские роботы",
"Строй Инновация",
"Медицинский Колос",
]
TEST_TASKS = [
{
"id": "1",
"tasks": [
"Создание макета сайта в графическом редакторе",
"Изучение основных принципов дизайна: цвет, типографика, композиция",
"Создание векторной графики для использования на сайте",
"Создание нескольких вариантов дизайна для выбора наилучшего решения",
"Разработка дизайна логотипа и фирменного стиля",
],
},
{
"id": "2",
"tasks": [
"Разработка и продвижение программы лояльности для доноров.",
"Организация и проведение благотворительного аукциона или лотереи.",
"Проведение промо-акций в социальных сетях для привлечения доноров.",
"Организация и проведение благотворительного мероприятия.",
"Создание PR-кампаний и пресс-релизов.",
],
},
{
"id": "3",
"tasks": [
"Перевод средств на поддержку нуждающихся",
"Организация благотворительных мероприятий через переводы",
"Регулярные переводы на улучшение условий жизни нуждающихся",
"Перевод на медицинскую помощь нуждающимся",
"Помощь с переводом для мигрантов и беженцев",
],
},
{
"id": "4",
"tasks": [
"Разработка и поддержка сайта организации",
"Создание базы данных для учета доноров и получателей помощи",
"Разработка мобильного приложения для сбора пожертвований",
"Автоматизация процесса учета и отчетности в организации",
"Разработка системы онлайн-консультаций для получателей помощи",
],
},
{
"id": "5",
"tasks": [
"Регистрация благотворительной организации",
"Разработка устава и другой внутренней документации",
"Получение статуса НКО",
"Консультации по налогообложению и отчетности",
"Правовая поддержка при взаимодействии с государственными органами",
],
},
{
"id": "6",
"tasks": [
"Определение и разработка концепции долгосрочного развития организации.",
"Поиск и обеспечение новых источников финансирования.",
"Разработка стратегии маркетинга и продвижения организации.",
"Оптимизация деятельности и уменьшение издержек организации.",
"Оценка эффективности программ благотворительной помощи.",
],
},
{
"id": "7",
"tasks": [
"Создание промо-видео",
"Фотоотчет",
"Создание видеоинструкций",
"Фотографирование пациентов",
"Создание коротких видеороликов",
],
},
{
"id": "8",
"tasks": [
"Развитие навыков лидерства и командной работы",
"Навыки эффективной коммуникации и делового переговоров",
"Финансовое планирование и управление бюджетом",
"Управление проектами и достижение целей организации",
"Развитие личной эффективности и эмоционального интеллекта",
],
},
{
"id": "9",
"tasks": [
"Разработка стратегии привлечения доноров на следующий квартал.",
"Проведение анализа эффективности рекламных кампаний.",
"Организация благотворительного концерта с участием артистов.",
"Проведение финансовой аудитории для улучшения финансовой дисциплины.",
"Разработка системы мотивации для волонтеров.",
],
},
{
"id": "10",
"tasks": [
"Разработать стратегию привлечения новых доноров",
"Организация гала-вечеринки в поддержку благотворительной программы",
"Подготовка презентации о деятельности организации.",
"Провести опрос среди населения для выявления актуальных проблем.",
"Разработать план волонтерской деятельности для привлечения помощи.",
],
},
]
USERS_TABLE_ROWS = 30
FAKE_ADMINS_COUNT = 30
async def get_task_name_by_id(category_id):
"""Function for selecting tasks from the TEST_TASKS list."""
for task in TEST_TASKS:
if int(task["id"]) == category_id:
for i in task["tasks"]:
yield i
async def filling_category_in_db(
session: async_sessionmaker[AsyncSession],
) -> None:
"""Filling the database with test data Categories.
The fields id, name, is_archived are filled in.
"""
for category in CATEGORIES_TEST_DATA:
category_obj = Category(
name=category["name"],
is_archived=choice([True, False]),
id=int(category["id"]),
)
session.add(category_obj)
await session.commit()
async def filling_subcategory_in_db(
session: async_sessionmaker[AsyncSession],
) -> None:
"""Filling the database with test data subcategories.
The fields id, name, is_archived, parent_id are filled in.
"""
for category in CATEGORIES_TEST_DATA:
parent_id = int(category["id"])
category_name = str(category["name"])
for subcategory in SUBCATEGORIES_TEST_DATA:
subcategory_obj = Category(
name=f"{subcategory['name']} для {category_name}",
is_archived=True if "Архивный" in subcategory["name"] else False,
parent_id=parent_id,
id=int(str(subcategory["id"]) + str(parent_id)),
)
if not subcategory_obj.is_archived:
CATEGORIES_FILL_DATA.append(subcategory_obj.id)
session.add(subcategory_obj)
await session.commit()
async def filling_task_in_db(
session: async_sessionmaker[AsyncSession],
) -> None:
"""Filling the database with test data: Tasks.
The fields title, name_organization, deadline, category,
location, description, is_archived.
"""
for category_id in range(0, len(CATEGORIES_TEST_DATA) + 1):
for subcategory in SUBCATEGORIES_TEST_DATA:
async for title in get_task_name_by_id(category_id):
task = Task(
name_organization=f"{choice(TEST_ORGANIZATION)}",
deadline=datetime.now() + timedelta(days=10),
category_id=int(str(subcategory["id"]) + str(category_id)),
title=title,
bonus=randint(1, 4) + randint(1, 4),
location=f"{choice(TEST_LOCATION)}",
link=f"https://example.com/task/" f"{''.join(choices(CHARACTERS, k=6))}",
description=f"Описание {title}",
is_archived=choice([True, False]),
)
session.add(task)
await session.commit()
async def filling_user_and_external_site_user_in_db(
session: async_sessionmaker[AsyncSession],
) -> None:
"""Filling the database with test data: Users, ExternalSiteUser."""
moderation_statuses = [*UserStatus, None]
roles = [*UserRoles, None]
user_fake = Faker(locale="ru_RU")
external_id_fake = Faker()
days_period = 90
for id in range(1, USERS_TABLE_ROWS + 1):
role = choice(roles)
moderation_status = choice(moderation_statuses)
email = choice([None, user_fake.unique.email()])
external_id = external_id_fake.unique.random_int(min=1, max=USERS_TABLE_ROWS)
if role is None:
external_id = choice([None, external_id])
created_at = user_fake.date_between(datetime.now() - timedelta(days=days_period), datetime.now())
specializations = sample(CATEGORIES_FILL_DATA, k=randint(1, 3)) if role == UserRoles.VOLUNTEER else None
user = User(
telegram_id=100_000_000_000 + user_fake.unique.random_int(min=1, max=USERS_TABLE_ROWS),
role=role,
username=user_fake.unique.user_name(),
email=email,
external_id=external_id,
first_name=user_fake.first_name(),
last_name=user_fake.last_name(),
has_mailing=False if email is None else True,
external_signup_date=None if external_id is None else created_at,
banned=user_fake.boolean(),
created_at=created_at,
)
if user.external_id is not None:
external_user = ExternalSiteUser(
external_id=external_id,
role=role,
moderation_status=moderation_status,
first_name=user.first_name,
last_name=user.last_name,
email=email,
specializations=specializations,
user=user,
)
session.add(external_user)
session.add(user)
await session.commit()
async def filling_unsubscribe_reason_in_db(
session: async_sessionmaker[AsyncSession],
) -> None:
"""Filling the database with test data: UnsubscribeReason.
The fields telegram_id, username, email, external_id, first_name,
last_name, has_mailing, external_signup_date, banned.
"""
user_fake = Faker()
days_period = 60
for _ in range(1, int(USERS_TABLE_ROWS / 3) + 1):
unsubscribe_reason = UnsubscribeReason(
user_id=user_fake.unique.random_int(min=1, max=USERS_TABLE_ROWS),
unsubscribe_reason=choice([reason.name for reason in enum.REASONS]),
created_at=user_fake.date_between(datetime.now() - timedelta(days=days_period), datetime.now()),
)
session.add(unsubscribe_reason)
await session.commit()
async def delete_all_data(
session: async_sessionmaker[AsyncSession],
) -> None:
"""The function deletes data."""
await session.execute(
text(
"""TRUNCATE TABLE
tasks, categories, unsubscribe_reason, users, external_site_users
RESTART IDENTITY CASCADE"""
)
)
await session.commit()
async def add_admin_users(start: int, count: int, session: async_sessionmaker[AsyncSession]):
for n in range(start, start + count):
admin_user = AdminUser(
email=f"admin-{n}@example.com",
first_name=f"Эдик-{n}",
last_name="Минов",
hashed_password="1234567890",
is_active=True,
is_superuser=False,
is_verified=False,
)
session.add(admin_user)
await session.commit()
async def run(generate_fake_users: bool, add_fake_admins: bool):
session_manager = asynccontextmanager(get_session)
async with session_manager() as session:
await delete_all_data(session)
await filling_category_in_db(session)
await filling_subcategory_in_db(session)
await filling_task_in_db(session)
if generate_fake_users:
await filling_user_and_external_site_user_in_db(session)
await filling_unsubscribe_reason_in_db(session)
if add_fake_admins:
await add_admin_users(1, FAKE_ADMINS_COUNT, session)
print("Тестовые данные загружены в БД.")
if __name__ == "__main__":
options = sys.argv[1:]
asyncio.run(
run(
"with_fake_users" in options,
"add_fake_admins" in options,
)
)