users: allow profile without maintainer

parent 950d64a6
...@@ -4,10 +4,12 @@ from database.func import DB ...@@ -4,10 +4,12 @@ from database.func import DB
def menu_kb(user_id: int): def menu_kb(user_id: int):
user = DB.user.get(user_id)
user_rules = DB.user.get_roles(user_id) user_rules = DB.user.get_roles(user_id)
kb = Keyboard() kb = Keyboard()
kb.add(Button("Профиль")) kb.add(Button("Профиль"))
if user and user.maintainer:
kb.row() kb.row()
kb.add(Button("Отслеживание")) kb.add(Button("Отслеживание"))
kb.add(Button("Ошибки")) kb.add(Button("Ошибки"))
......
...@@ -9,18 +9,22 @@ profile_kb = ( ...@@ -9,18 +9,22 @@ profile_kb = (
.add(InlineButton("Настройки", callback_data="profile/settings")) .add(InlineButton("Настройки", callback_data="profile/settings"))
).get_markup() ).get_markup()
profile_settings_kb = ( def profile_settings_kb(has_maintainer: bool = True):
InlineKeyboard() maintainer_label = "Сменить сопровождающего" if has_maintainer else "Выбрать сопровождающего"
.add(InlineButton("Рассылки и уведомления", callback_data="profile/mailing")) kb = InlineKeyboard()
.row() kb.add(InlineButton("Рассылки и уведомления", callback_data="profile/mailing"))
.add(InlineButton("Отслеживаемые пакеты", callback_data="profile/settings/packages")) kb.row()
.row() kb.add(InlineButton("Отслеживаемые пакеты", callback_data="profile/settings/packages"))
.add(InlineButton("Сменить сопровождающего", callback_data="profile/settings/maintainer")) kb.row()
.row() kb.add(InlineButton(maintainer_label, callback_data="profile/settings/maintainer"))
.add(InlineButton("Сменить репозиторий", callback_data="profile/settings/branch")) kb.row()
.row() if has_maintainer:
.add(InlineButton("Закрыть", callback_data="profile/close")) kb.add(InlineButton("Выйти", callback_data="profile/settings/logout"))
).get_markup() kb.row()
kb.add(InlineButton("Сменить репозиторий", callback_data="profile/settings/branch"))
kb.row()
kb.add(InlineButton("Закрыть", callback_data="profile/close"))
return kb.get_markup()
def profile_settings_branch_kb(): def profile_settings_branch_kb():
...@@ -44,14 +48,19 @@ INSTANT_TYPES = [ ...@@ -44,14 +48,19 @@ INSTANT_TYPES = [
] ]
def mailing_settings_kb(schedule, enabled: list[str]): def mailing_settings_kb(schedule, enabled: list[str], has_maintainer: bool = True):
kb = InlineKeyboard() kb = InlineKeyboard()
kb.add(InlineButton("Дни недели", callback_data="profile/mailing/days")) kb.add(InlineButton("Дни недели", callback_data="profile/mailing/days"))
kb.add(InlineButton("Время", callback_data="profile/mailing/set-time")) kb.add(InlineButton("Время", callback_data="profile/mailing/set-time"))
kb.row() kb.row()
for type_id, label in SCHEDULED_TYPES: scheduled_types = SCHEDULED_TYPES if has_maintainer else [
item for item in SCHEDULED_TYPES if item[0] == "pkg_watch"
]
instant_types = INSTANT_TYPES if has_maintainer else []
for type_id, label in scheduled_types:
status = "вкл" if type_id in enabled else "выкл" status = "вкл" if type_id in enabled else "выкл"
kb.add(InlineButton( kb.add(InlineButton(
f"{label}: {status}", f"{label}: {status}",
...@@ -59,7 +68,7 @@ def mailing_settings_kb(schedule, enabled: list[str]): ...@@ -59,7 +68,7 @@ def mailing_settings_kb(schedule, enabled: list[str]):
)) ))
kb.row() kb.row()
for type_id, label in INSTANT_TYPES: for type_id, label in instant_types:
status = "вкл" if type_id in enabled else "выкл" status = "вкл" if type_id in enabled else "выкл"
kb.add(InlineButton( kb.add(InlineButton(
f"{label}: {status}", f"{label}: {status}",
......
...@@ -3,6 +3,12 @@ from telegrinder import Button, Keyboard ...@@ -3,6 +3,12 @@ from telegrinder import Button, Keyboard
from config import DEFAUIL_BRANCHES from config import DEFAUIL_BRANCHES
def maintainer_kb():
kb = Keyboard(one_time_keyboard=True)
kb.add(Button("Пропустить"))
return kb.get_markup()
def default_branch_kb(): def default_branch_kb():
kb = Keyboard(one_time_keyboard=True) kb = Keyboard(one_time_keyboard=True)
for branch in DEFAUIL_BRANCHES: for branch in DEFAUIL_BRANCHES:
......
...@@ -60,7 +60,7 @@ class UserMethod: ...@@ -60,7 +60,7 @@ class UserMethod:
def add( def add(
cls, cls,
user_id: int, user_id: int,
maintainer: Maintainer, maintainer: Maintainer | None,
default_branch: str = "sisyphus", default_branch: str = "sisyphus",
): ):
"""создание записи пользователя""" """создание записи пользователя"""
...@@ -132,7 +132,7 @@ class UserMethod: ...@@ -132,7 +132,7 @@ class UserMethod:
return False return False
@classmethod @classmethod
def change_maintainer(cls, user_id: int, maintainer: Maintainer): def change_maintainer(cls, user_id: int, maintainer: Maintainer | None):
user = cls.get(user_id) user = cls.get(user_id)
if user is None: if user is None:
return False return False
......
...@@ -36,9 +36,10 @@ class User(BaseModel): ...@@ -36,9 +36,10 @@ class User(BaseModel):
"""модель пользователя""" """модель пользователя"""
user_id = IntegerField() # id пользователя user_id = IntegerField() # id пользователя
maintainer: Maintainer = ForeignKeyField( # сопровождающий maintainer: Maintainer | None = ForeignKeyField( # сопровождающий
Maintainer, Maintainer,
to_field="nickname" to_field="nickname",
null=True,
) )
default_branch = TextField( # Репозитоий по умолчанию default_branch = TextField( # Репозитоий по умолчанию
default="sisyphus" default="sisyphus"
......
...@@ -27,7 +27,8 @@ async def alrtrepo_users(m: Message): ...@@ -27,7 +27,8 @@ async def alrtrepo_users(m: Message):
users_data = DB.user.get_all() users_data = DB.user.get_all()
user_message = "" user_message = ""
for user in users_data: for user in users_data:
user_message += f"{user.user_id} | {user.maintainer.nickname} | {user.default_branch}\n" maintainer = user.maintainer.nickname if user.maintainer else "-"
user_message += f"{user.user_id} | {maintainer} | {user.default_branch}\n"
await m.answer(user_message) await m.answer(user_message)
...@@ -43,10 +44,11 @@ async def alrtrepo_users(m: Message, user_id: int): ...@@ -43,10 +44,11 @@ async def alrtrepo_users(m: Message, user_id: int):
user = (await tg_api.get_chat(chat_id=user_id)).unwrap() user = (await tg_api.get_chat(chat_id=user_id)).unwrap()
username = user.username.unwrap_or_none() username = user.username.unwrap_or_none()
username = f"(@{username})\n" if username else "\n" username = f"(@{username})\n" if username else "\n"
maintainer = db_user.maintainer.nickname if db_user.maintainer else "-"
await m.answer( await m.answer(
f"{user.first_name.unwrap_or("")} {user.last_name.unwrap_or("")} {username}" f"{user.first_name.unwrap_or("")} {user.last_name.unwrap_or("")} {username}"
f" Сопровождающий: {db_user.maintainer.nickname}\n" f" Сопровождающий: {maintainer}\n"
f" Репозиторий: {db_user.default_branch}\n" f" Репозиторий: {db_user.default_branch}\n"
f" Роли: {", ".join(user_roles) or "пользователь"}\n" f" Роли: {", ".join(user_roles) or "пользователь"}\n"
) )
...@@ -70,7 +72,12 @@ async def alrtrepo_users( ...@@ -70,7 +72,12 @@ async def alrtrepo_users(
if not branch: if not branch:
branch = "sisyphus" branch = "sisyphus"
if DB.user.add(user_id, maintainer, branch): maintainer_obj = DB.maintainer.get(maintainer)
if not maintainer_obj:
await m.answer("Сопровождающий не найден")
return
if DB.user.add(user_id, maintainer_obj, branch):
await m.answer("Пользователь добавлен") await m.answer("Пользователь добавлен")
......
...@@ -24,9 +24,12 @@ async def ftbfs_handler(m: Message, user: User | None, _maintainer: str | None = ...@@ -24,9 +24,12 @@ async def ftbfs_handler(m: Message, user: User | None, _maintainer: str | None =
return return
else: else:
if user: if user and user.maintainer:
maintainer = user.maintainer.nickname maintainer = user.maintainer.nickname
else: else:
await m.answer(
"Команда требует сопровождающего. Укажите ник в команде или выберите сопровождающего в профиле."
)
return return
ftbfs_data = await altrepo.parser.packages.ftbfs() ftbfs_data = await altrepo.parser.packages.ftbfs()
......
...@@ -78,7 +78,9 @@ async def help_handler(m: Message) -> None: ...@@ -78,7 +78,9 @@ async def help_handler(m: Message) -> None:
await m.answer( await m.answer(
f"{_bold("Основные:")}\n" f"{_bold("Основные:")}\n"
" /profile — профиль сопровождающего\n" " /profile — профиль\n"
" /login — выбрать сопровождающего\n"
" /logout — удалить сопровождающего\n"
" /help — помощь\n" " /help — помощь\n"
" /altrepo_info — информация о боте\n\n" " /altrepo_info — информация о боте\n\n"
...@@ -103,4 +105,3 @@ async def help_handler(m: Message) -> None: ...@@ -103,4 +105,3 @@ async def help_handler(m: Message) -> None:
" /news_range дата_от дата_до — новости за период\n" " /news_range дата_от дата_до — новости за период\n"
" /pulse [дней] — пульс Сизифа (по умолчанию 7)\n" " /pulse [дней] — пульс Сизифа (по умолчанию 7)\n"
) )
...@@ -25,10 +25,20 @@ DESCRIPTIONS = { ...@@ -25,10 +25,20 @@ DESCRIPTIONS = {
"task_events": "Изменения статуса тасков текущего сопровождающего.", "task_events": "Изменения статуса тасков текущего сопровождающего.",
} }
MAINTAINER_MAILINGS = {"watch", "bugs", "task_events"}
async def _drop_pending_input(user_id: int) -> None:
try:
await wm.drop(MESSAGE_FROM_USER, user_id)
except LookupError:
pass
def _mailing_text_and_markup(user): def _mailing_text_and_markup(user):
schedule = DB.schedule.get(user) schedule = DB.schedule.get(user)
enabled = DB.mailing.get_enabled(user) enabled = DB.mailing.get_enabled(user)
has_maintainer = user.maintainer is not None
text = _bold("Рассылки:\n\n") text = _bold("Рассылки:\n\n")
...@@ -39,19 +49,28 @@ def _mailing_text_and_markup(user): ...@@ -39,19 +49,28 @@ def _mailing_text_and_markup(user):
else: else:
text += "Расписание: не настроено\n\n" text += "Расписание: не настроено\n\n"
for type_id, label in profile_keyboards.SCHEDULED_TYPES: scheduled_types = profile_keyboards.SCHEDULED_TYPES if has_maintainer else [
item for item in profile_keyboards.SCHEDULED_TYPES if item[0] not in MAINTAINER_MAILINGS
]
instant_types = profile_keyboards.INSTANT_TYPES if has_maintainer else []
for type_id, label in scheduled_types:
status = "вкл" if type_id in enabled else "выкл" status = "вкл" if type_id in enabled else "выкл"
text += _bold(f"{label}: {status}\n") text += _bold(f"{label}: {status}\n")
text += f"{DESCRIPTIONS[type_id]}\n\n" text += f"{DESCRIPTIONS[type_id]}\n\n"
if instant_types:
text += _bold("Уведомления:\n\n") text += _bold("Уведомления:\n\n")
for type_id, label in profile_keyboards.INSTANT_TYPES: for type_id, label in instant_types:
status = "вкл" if type_id in enabled else "выкл" status = "вкл" if type_id in enabled else "выкл"
text += _bold(f"{label}: {status}\n") text += _bold(f"{label}: {status}\n")
text += f"{DESCRIPTIONS[type_id]}\n\n" text += f"{DESCRIPTIONS[type_id]}\n\n"
markup = profile_keyboards.mailing_settings_kb(schedule, enabled) if not has_maintainer:
text += "Рассылки по сопровождающему появятся после выбора сопровождающего в профиле.\n"
markup = profile_keyboards.mailing_settings_kb(schedule, enabled, has_maintainer)
return text, markup return text, markup
...@@ -61,6 +80,17 @@ async def profile_handler(m: Message, user: User | None) -> None: ...@@ -61,6 +80,17 @@ async def profile_handler(m: Message, user: User | None) -> None:
if user is None: if user is None:
return return
if not user.maintainer:
roles = DB.user.get_roles(m.from_user.id)
await m.answer(
f"{_bold("Профиль:\n\n")}"
"Сопровождающий: не выбран\n"
f"Репозиторий: {user.default_branch}\n\n"
f"Роли в боте: {", ".join(roles) or "пользователь"}",
reply_markup=profile_keyboards.profile_kb
)
return
nickname = user.maintainer.nickname nickname = user.maintainer.nickname
maintainer_data, watch, bugs_data, branches_data, ftbfs_data = await asyncio.gather( maintainer_data, watch, bugs_data, branches_data, ftbfs_data = await asyncio.gather(
...@@ -104,9 +134,13 @@ async def profile_handler(m: Message, user: User | None) -> None: ...@@ -104,9 +134,13 @@ async def profile_handler(m: Message, user: User | None) -> None:
@dp.callback_query(PayloadEqRule("profile/settings")) @dp.callback_query(PayloadEqRule("profile/settings"))
async def settings_handler(cb: CallbackQuery) -> None: async def settings_handler(cb: CallbackQuery) -> None:
await _drop_pending_input(cb.from_user.id)
user = DB.user.get(cb.from_user.id)
await cb.edit_text( await cb.edit_text(
"Настройки", "Настройки",
reply_markup=profile_keyboards.profile_settings_kb reply_markup=profile_keyboards.profile_settings_kb(
user is not None and user.maintainer is not None
)
) )
await cb.answer() await cb.answer()
...@@ -117,37 +151,93 @@ async def close_handler(cb: CallbackQuery) -> None: ...@@ -117,37 +151,93 @@ async def close_handler(cb: CallbackQuery) -> None:
await cb.answer() await cb.answer()
@dp.callback_query(PayloadEqRule("profile/settings/maintainer")) async def _login(chat_id: int, user_id: int, ctx_api, edit_cb: CallbackQuery | None = None) -> None:
async def maintainer_handler(cb: CallbackQuery) -> None:
cancel = cancel_kb("profile/settings") cancel = cancel_kb("profile/settings")
await cb.edit_text("Введите никнейм сопровождающего:", reply_markup=cancel) if edit_cb:
await edit_cb.edit_text("Введите никнейм сопровождающего:", reply_markup=cancel)
else:
await ctx_api.send_message(
chat_id=chat_id,
text="Введите никнейм сопровождающего:",
reply_markup=cancel,
)
try: try:
while True: while True:
msg, _ = await wm.wait(MESSAGE_FROM_USER, cb.from_user.id, release=HasText()) msg, _ = await wm.wait(MESSAGE_FROM_USER, user_id, release=HasText())
maintainer = msg.text.unwrap().lower() maintainer = msg.text.unwrap().lower()
await msg.delete() await msg.delete()
maintainer_obj = DB.maintainer.get(maintainer) maintainer_obj = DB.maintainer.get(maintainer)
if maintainer_obj: if maintainer_obj:
DB.user.change_maintainer(cb.from_user.id, maintainer_obj) DB.user.change_maintainer(user_id, maintainer_obj)
await cb.edit_text( text = f"Сопровождающий: {maintainer}"
f"Сопровождающий: {maintainer}", markup = profile_keyboards.profile_settings_kb(True)
reply_markup=profile_keyboards.profile_settings_kb if edit_cb:
) await edit_cb.edit_text(text, reply_markup=markup)
else:
await ctx_api.send_message(chat_id=chat_id, text=text, reply_markup=markup)
break break
else: else:
await cb.edit_text( text = (
f"Сопровождающий {maintainer} не найден.\n" f"Сопровождающий {maintainer} не найден.\n"
"Введите никнейм сопровождающего:", "Введите никнейм сопровождающего:"
reply_markup=cancel,
) )
if edit_cb:
await edit_cb.edit_text(text, reply_markup=cancel)
else:
await ctx_api.send_message(chat_id=chat_id, text=text, reply_markup=cancel)
except (asyncio.CancelledError, LookupError): except (asyncio.CancelledError, LookupError):
return return
@dp.callback_query(PayloadEqRule("profile/settings/maintainer"))
async def maintainer_handler(cb: CallbackQuery) -> None:
await _login(cb.chat_id.unwrap(), cb.from_user.id, cb.ctx_api, cb)
await cb.answer()
@dp.callback_query(PayloadEqRule("profile/settings/logout"))
async def logout_callback_handler(cb: CallbackQuery) -> None:
user = DB.user.get(cb.from_user.id)
if not user:
return
DB.user.change_maintainer(cb.from_user.id, None)
for mailing_type in MAINTAINER_MAILINGS:
await scheduler.disable_mailing(user, mailing_type)
await cb.edit_text(
"Сопровождающий удалён.",
reply_markup=profile_keyboards.profile_settings_kb(False),
)
await cb.answer() await cb.answer()
@dp.message(Command("login"), IsPrivate())
async def login_handler(m: Message, user: User | None) -> None:
if user is None:
await m.answer("Сначала запустите /start.")
return
await _login(m.chat_id, m.from_user.id, m.ctx_api)
@dp.message(Command("logout"), IsPrivate())
async def logout_handler(m: Message, user: User | None) -> None:
if user is None:
await m.answer("Сначала запустите /start.")
return
if not user.maintainer:
await m.answer("Сопровождающий не выбран.")
return
DB.user.change_maintainer(m.from_user.id, None)
for mailing_type in MAINTAINER_MAILINGS:
await scheduler.disable_mailing(user, mailing_type)
await m.answer("Сопровождающий удалён.")
@dp.callback_query(PayloadEqRule("profile/settings/branch")) @dp.callback_query(PayloadEqRule("profile/settings/branch"))
async def branch_handler(cb: CallbackQuery) -> None: async def branch_handler(cb: CallbackQuery) -> None:
await cb.edit_text( await cb.edit_text(
...@@ -159,9 +249,12 @@ async def branch_handler(cb: CallbackQuery) -> None: ...@@ -159,9 +249,12 @@ async def branch_handler(cb: CallbackQuery) -> None:
@dp.callback_query(PayloadMarkupRule("profile/settings/branch/<branch>")) @dp.callback_query(PayloadMarkupRule("profile/settings/branch/<branch>"))
async def branch_select_handler(cb: CallbackQuery, branch: str) -> None: async def branch_select_handler(cb: CallbackQuery, branch: str) -> None:
DB.user.change_default_branch(cb.from_user.id, branch) DB.user.change_default_branch(cb.from_user.id, branch)
user = DB.user.get(cb.from_user.id)
await cb.edit_text( await cb.edit_text(
f"Репозиторий: {branch}", f"Репозиторий: {branch}",
reply_markup=profile_keyboards.profile_settings_kb reply_markup=profile_keyboards.profile_settings_kb(
user is not None and user.maintainer is not None
)
) )
await cb.answer() await cb.answer()
...@@ -170,6 +263,7 @@ async def branch_select_handler(cb: CallbackQuery, branch: str) -> None: ...@@ -170,6 +263,7 @@ async def branch_select_handler(cb: CallbackQuery, branch: str) -> None:
@dp.callback_query(PayloadEqRule("profile/mailing")) @dp.callback_query(PayloadEqRule("profile/mailing"))
async def mailing_handler(cb: CallbackQuery) -> None: async def mailing_handler(cb: CallbackQuery) -> None:
await _drop_pending_input(cb.from_user.id)
user = DB.user.get(cb.from_user.id) user = DB.user.get(cb.from_user.id)
if not user: if not user:
return return
...@@ -249,6 +343,10 @@ async def mailing_toggle_handler(cb: CallbackQuery, mailing_type: str) -> None: ...@@ -249,6 +343,10 @@ async def mailing_toggle_handler(cb: CallbackQuery, mailing_type: str) -> None:
if not user: if not user:
return return
if mailing_type in MAINTAINER_MAILINGS and not user.maintainer:
await cb.answer("Сначала выберите сопровождающего.", show_alert=True)
return
if DB.mailing.is_enabled(user, mailing_type): if DB.mailing.is_enabled(user, mailing_type):
await scheduler.disable_mailing(user, mailing_type) await scheduler.disable_mailing(user, mailing_type)
else: else:
...@@ -263,6 +361,7 @@ async def mailing_toggle_handler(cb: CallbackQuery, mailing_type: str) -> None: ...@@ -263,6 +361,7 @@ async def mailing_toggle_handler(cb: CallbackQuery, mailing_type: str) -> None:
@dp.callback_query(PayloadEqRule("profile/settings/packages")) @dp.callback_query(PayloadEqRule("profile/settings/packages"))
async def user_packages_handler(cb: CallbackQuery) -> None: async def user_packages_handler(cb: CallbackQuery) -> None:
await _drop_pending_input(cb.from_user.id)
uid = cb.from_user.id uid = cb.from_user.id
packages = DB.watch_list.get_list(uid) packages = DB.watch_list.get_list(uid)
......
...@@ -20,11 +20,16 @@ async def start_handler(m: Message, user: User | None) -> None: ...@@ -20,11 +20,16 @@ async def start_handler(m: Message, user: User | None) -> None:
if user is None: if user is None:
await m.answer( await m.answer(
"Введите никнейм сопровождающего:" "Введите никнейм сопровождающего или пропустите этот шаг:",
reply_markup=start_keyboards.maintainer_kb(),
) )
maintainer = None
while True: while True:
msg, _ = await wm.wait(MESSAGE_FROM_USER, m.from_user.id, release=HasText()) msg, _ = await wm.wait(MESSAGE_FROM_USER, m.from_user.id, release=HasText())
_maintainer = msg.text.unwrap().lower() _maintainer = msg.text.unwrap().lower()
if _maintainer in ["пропустить", "skip", "/skip"]:
await m.answer("Сопровождающий не выбран.")
break
maintainer = DB.maintainer.get(_maintainer) maintainer = DB.maintainer.get(_maintainer)
if maintainer: if maintainer:
await m.answer( await m.answer(
...@@ -34,7 +39,8 @@ async def start_handler(m: Message, user: User | None) -> None: ...@@ -34,7 +39,8 @@ async def start_handler(m: Message, user: User | None) -> None:
else: else:
await m.answer( await m.answer(
f"Сопровождающий {_maintainer} не найден.\n" f"Сопровождающий {_maintainer} не найден.\n"
"Введите никнейм сопровождающего:" "Введите никнейм сопровождающего или пропустите этот шаг:",
reply_markup=start_keyboards.maintainer_kb(),
) )
await m.answer( await m.answer(
"Выберите репозиторий по умолчанию.", "Выберите репозиторий по умолчанию.",
......
...@@ -45,10 +45,12 @@ async def tasks_handler(m: Message, user: User | None, maintainer: str | None = ...@@ -45,10 +45,12 @@ async def tasks_handler(m: Message, user: User | None, maintainer: str | None =
maintainer_obj = DB.maintainer.get(maintainer.lower()) maintainer_obj = DB.maintainer.get(maintainer.lower())
if not maintainer_obj: if not maintainer_obj:
return await m.answer("Сопровождающий не найден.") return await m.answer("Сопровождающий не найден.")
elif user: elif user and user.maintainer:
maintainer_obj = user.maintainer maintainer_obj = user.maintainer
else: else:
return return await m.answer(
"Команда требует сопровождающего. Укажите ник в команде или выберите сопровождающего в профиле."
)
try: try:
tasks_data = await altrepo.api.task.progress.find_tasks( tasks_data = await altrepo.api.task.progress.find_tasks(
......
...@@ -55,6 +55,44 @@ def _migrate_scheduled_tasks(): ...@@ -55,6 +55,44 @@ def _migrate_scheduled_tasks():
logger.info("Migration complete, old table dropped") logger.info("Migration complete, old table dropped")
def _migrate_nullable_user_maintainer():
if not db.table_exists("users"):
return
columns = db.execute_sql("PRAGMA table_info(users)").fetchall()
maintainer_column = next((col for col in columns if col[1] == "maintainer_id"), None)
if maintainer_column is None or not maintainer_column[3]:
return
logger.info("Migrating users.maintainer_id to nullable")
db.execute_sql("PRAGMA foreign_keys=off")
try:
db.execute_sql(
"""
CREATE TABLE users_new (
id INTEGER NOT NULL PRIMARY KEY,
user_id INTEGER NOT NULL,
maintainer_id TEXT,
default_branch TEXT NOT NULL,
roles TEXT NOT NULL,
FOREIGN KEY (maintainer_id) REFERENCES maintainers (nickname)
)
"""
)
db.execute_sql(
"""
INSERT INTO users_new (id, user_id, maintainer_id, default_branch, roles)
SELECT id, user_id, maintainer_id, default_branch, roles FROM users
"""
)
db.execute_sql("DROP TABLE users")
db.execute_sql("ALTER TABLE users_new RENAME TO users")
db.execute_sql("CREATE INDEX user_maintainer_id ON users (maintainer_id)")
finally:
db.execute_sql("PRAGMA foreign_keys=on")
logger.info("Migration complete, users.maintainer_id is nullable")
@bot.loop_wrapper.lifespan.on_startup @bot.loop_wrapper.lifespan.on_startup
async def startup(): async def startup():
db.create_tables( db.create_tables(
...@@ -69,6 +107,7 @@ async def startup(): ...@@ -69,6 +107,7 @@ async def startup():
] ]
) )
_migrate_nullable_user_maintainer()
_migrate_scheduled_tasks() _migrate_scheduled_tasks()
logger.info("initializing ALTRepo") logger.info("initializing ALTRepo")
...@@ -89,6 +128,8 @@ async def startup(): ...@@ -89,6 +128,8 @@ async def startup():
BotCommand("pkg_watch", "Обновления отслеживаемых пакетов"), BotCommand("pkg_watch", "Обновления отслеживаемых пакетов"),
BotCommand("ftbfs", "Ошибки пересборки"), BotCommand("ftbfs", "Ошибки пересборки"),
BotCommand("statistics", "Статистика репозитория"), BotCommand("statistics", "Статистика репозитория"),
BotCommand("login", "Выбрать сопровождающего"),
BotCommand("logout", "Удалить сопровождающего"),
BotCommand("altrepo_info", "Информация о боте"), BotCommand("altrepo_info", "Информация о боте"),
BotCommand("help", "Справка"), BotCommand("help", "Справка"),
] ]
......
...@@ -17,6 +17,8 @@ MAILING_HANDLERS = { ...@@ -17,6 +17,8 @@ MAILING_HANDLERS = {
), ),
} }
MAINTAINER_MAILINGS = {"watch", "bugs"}
class CustomScheduler: class CustomScheduler:
def __init__(self): def __init__(self):
...@@ -116,6 +118,8 @@ class CustomScheduler: ...@@ -116,6 +118,8 @@ class CustomScheduler:
if not user: if not user:
return return
for mailing_type in DB.mailing.get_enabled(user): for mailing_type in DB.mailing.get_enabled(user):
if mailing_type in MAINTAINER_MAILINGS and not user.maintainer:
continue
handler = MAILING_HANDLERS.get(mailing_type) handler = MAILING_HANDLERS.get(mailing_type)
if handler: if handler:
await handler(user) await handler(user)
......
...@@ -15,7 +15,10 @@ async def bugs( ...@@ -15,7 +15,10 @@ async def bugs(
maintainer: str | None = None maintainer: str | None = None
) -> None: ) -> None:
chat_id = chat_id or user.user_id if chat_id is None:
if user is None:
return
chat_id = user.user_id
resolved = await resolve_maintainer(maintainer, user, chat_id) resolved = await resolve_maintainer(maintainer, user, chat_id)
if not resolved: if not resolved:
......
...@@ -18,11 +18,15 @@ async def resolve_maintainer( ...@@ -18,11 +18,15 @@ async def resolve_maintainer(
if maintainer_arg: if maintainer_arg:
maintainer = DB.maintainer.get(maintainer_arg.lower()) maintainer = DB.maintainer.get(maintainer_arg.lower())
if not maintainer: if not maintainer:
await tg_api.send_message(chat_id, "Сопровождающий не найден.") await tg_api.send_message(chat_id=chat_id, text="Сопровождающий не найден.")
return None return None
return maintainer return maintainer
elif user: elif user and user.maintainer:
return user.maintainer return user.maintainer
await tg_api.send_message(
chat_id=chat_id,
text="Команда требует сопровождающего. Укажите ник в команде или выберите сопровождающего в профиле.",
)
return None return None
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment