add saving translations of maintainer names and package descriptions

parent 56ef68f1
import json
from .models import User
from .models import Maintainer, User, Package
class MaintainerMethod:
@classmethod
def add(cls, nickname: str, name: str, name_ru: str | None = None):
"""создание записи сопровождающего"""
if cls.get(nickname=nickname) is None:
maintainer = Maintainer(
name=name, name_ru=name_ru, nickname=nickname)
maintainer.save()
return True
return False
@classmethod
def get(cls, nickname: str) -> Maintainer | None:
"""получение записи сопровождающего"""
maintainer: Maintainer | None = Maintainer.get_or_none(
Maintainer.nickname == nickname)
return maintainer
@classmethod
def get_all(cls):
"""Получение записей всех сопровождающих"""
return [maintainer for maintainer in Maintainer.select()]
@classmethod
def delete(cls, nickname: str):
"""удаление записи сопровождающего"""
maintainer = cls.get(nickname)
if maintainer is None:
return False
maintainer.delete_instance()
return True
@classmethod
def change_name_ru(cls, nickname: str, name_ru: str):
maintainer = cls.get(nickname)
if maintainer is None:
return False
maintainer.name_ru = name_ru
maintainer.save()
return True
class UserMethod:
......@@ -8,7 +50,7 @@ class UserMethod:
def add(
cls,
user_id: int,
maintainer: str,
maintainer: Maintainer,
default_branch: str = "sisyphus",
):
"""создание записи пользователя"""
......@@ -76,7 +118,7 @@ class UserMethod:
return False
@classmethod
def change_maintainer(cls, user_id: int, maintainer: str):
def change_maintainer(cls, user_id: int, maintainer: Maintainer):
user = cls.get(user_id)
if user is None:
return False
......@@ -94,5 +136,25 @@ class UserMethod:
return True
class PackageMethod:
@classmethod
def add(cls, name: str, summary: str, summary_ru: str | None = None):
"""создание записи пакета"""
if cls.get(name=name) is None:
package = Package(
name=name, summary=summary, summary_ru=summary_ru)
package.save()
return True
return False
@classmethod
def get(cls, name: str) -> Package | None:
"""получение записи пакета"""
package: Package | None = Package.get_or_none(Package.name == name)
return package
class DB:
maintainer = MaintainerMethod
user = UserMethod
package = PackageMethod
......@@ -3,7 +3,8 @@ from peewee import (
Model,
AutoField,
IntegerField,
TextField
TextField,
ForeignKeyField
)
db = SqliteDatabase("alt-packages-bot.db")
......@@ -18,11 +19,26 @@ class BaseModel(Model):
database = db
class Maintainer(BaseModel):
"""модель сопровождающего"""
name = TextField()
name_ru = TextField(null=True)
nickname = TextField()
class Meta:
table_name = "maintainers"
class User(BaseModel):
"""модель пользователя"""
user_id = IntegerField() # id пользователя
maintainer = TextField() # никнейм сопровождающего
maintainer: Maintainer = ForeignKeyField( # сопровождающий
Maintainer,
to_field="nickname"
)
default_branch = TextField( # Репозитоий по умолчанию
default="sisyphus"
)
......@@ -30,3 +46,14 @@ class User(BaseModel):
class Meta:
table_name = "users"
class Package(BaseModel):
"""модель пакета"""
name = TextField()
summary = TextField()
summary_ru = TextField(null=True)
class Meta:
table_name = "packages"
......@@ -16,7 +16,7 @@ async def alrtrepo_users(m: Message):
users_data = DB.user.get_all()
user_message = ""
for user in users_data:
user_message += f"{user.user_id} | {user.maintainer} | {user.default_branch}\n"
user_message += f"{user.user_id} | {user.maintainer.nickname} | {user.default_branch}\n"
await m.answer(user_message)
......@@ -35,7 +35,7 @@ async def alrtrepo_users(m: Message, user_id: int):
await m.answer(
f"{user.first_name.unwrap_or("")} {user.last_name.unwrap_or("")} {username}"
f" Сопровождающий: {db_user.maintainer}\n"
f" Сопровождающий: {db_user.maintainer.nickname}\n"
f" Репозиторий: {db_user.default_branch}\n"
f" Роли: {", ".join(user_roles) or "пользователь"}\n"
)
......@@ -63,6 +63,16 @@ async def alrtrepo_users(
await m.answer("Пользователь добавлен")
@dp.message(Command("altrepo_remove_user", Argument("user_id")))
async def alrtrepo_users(m: Message, user_id: int):
if not user_id:
return
if DB.user.delete(user_id):
await m.answer("Пользователь удалён")
@dp.message(Command("altrepo_add_role", Argument("user_id"), Argument("role")))
async def alrtrepo_users(m: Message, user_id: int, role: str):
......
......@@ -5,6 +5,7 @@ from telegrinder.tools.formatting import HTMLFormatter
from altrepo import altrepo
from database.models import User
from database.func import DB
from data.keyboards import bugs_keyboards
from config import BUGS_URL
......@@ -17,21 +18,21 @@ dp = Dispatch()
async def bugs_handler(m: Message, user: User | None, maintainer: str | None = None) -> None:
if maintainer:
maintainer = maintainer.lower()
maintainer_data = await altrepo.api.site.all_maintainers("sisyphus")
if not any(
_m.packager_nickname == maintainer for _m in maintainer_data.maintainers
):
await m.answer(f"Сопровождающий {maintainer} не найден.")
_maintainer = maintainer.lower()
maintainer = DB.maintainer.get(_maintainer)
if not maintainer:
await m.answer(f"Сопровождающий {_maintainer} не найден.")
return
else:
if user:
maintainer = user.maintainer
else:
return
bugs_data = await altrepo.api.bug.bugzilla_by_maintainer(maintainer)
bugs_data = await altrepo.api.bug.bugzilla_by_maintainer(maintainer.nickname)
if bugs_data:
unresolved_bugs = [bug for bug in bugs_data.bugs if bug.status not in ["RESOLVED", "CLOSED"]]
unresolved_bugs = [
bug for bug in bugs_data.bugs if bug.status not in ["RESOLVED", "CLOSED"]]
else:
unresolved_bugs = []
......@@ -40,19 +41,18 @@ async def bugs_handler(m: Message, user: User | None, maintainer: str | None = N
"Нет открытых багов"
)
return
bugs_message = "Ошибки:\n\n"
for i, bug in enumerate(unresolved_bugs):
if i == 20:
break
bugs_message += HTMLFormatter(f"<a href='{BUGS_URL}{bug.id}'>#{bug.id}</a>") + \
f" | {bug.product} - {bug.component} | {bug.severity}\n"
markup = None
if len(unresolved_bugs) > 20:
bugs_message += "\n..."
markup = bugs_keyboards.bugs_more_kb(maintainer)
markup = bugs_keyboards.bugs_more_kb(maintainer.nickname)
await m.answer(bugs_message, reply_markup=markup)
......@@ -4,28 +4,27 @@ from telegrinder.rules import Command, Argument
from altrepo import altrepo
from database.models import User
from database.func import DB
dp = Dispatch()
@dp.message(Command("ftbfs", Argument("maintainer", optional=True)))
async def ftbfs_handler(m: Message, user: User | None, maintainer: str | None = None) -> None:
@dp.message(Command("ftbfs", Argument("_maintainer", optional=True)))
async def ftbfs_handler(m: Message, user: User | None, _maintainer: str | None = None) -> None:
if maintainer:
maintainer = maintainer.lower()
if _maintainer:
maintainer = _maintainer.lower()
group_data = await altrepo.api.acl.groups("sisyphus")
maintainer_data = await altrepo.api.site.all_maintainers("sisyphus")
if not any(
_m.packager_nickname == maintainer for _m in maintainer_data.maintainers
) and not any(
_g.group == maintainer for _g in group_data.groups
) and not maintainer in ["@nobody"]:
_maintainer = DB.maintainer.get(_maintainer)
if not _maintainer and not any(
_g.group == _maintainer for _g in group_data.groups
) and not _maintainer in ["@nobody"]:
await m.answer(f"Сопровождающий или группа {maintainer} не найдены.")
return
else:
if user:
maintainer = user.maintainer
maintainer = user.maintainer.nickname
else:
return
......
......@@ -4,6 +4,7 @@ from telegrinder.tools.formatting import HTMLFormatter, code_inline
dp = Dispatch()
@dp.message(Command("hedgehog"))
async def info_handler(m: Message) -> None:
await m.answer(HTMLFormatter(code_inline("""
......
......@@ -5,12 +5,13 @@ from altrepo import altrepo
dp = Dispatch()
@dp.message(Command("altrepo_info"))
async def info_handler(m: Message) -> None:
api_data = await altrepo.api.version()
warn = (
f"Бот разработан под версию API {altrepo.api.BASE_API_VERSION} и может работать нестабильно.\n"
"Разработчик уже уведомлён."
"Разработчик уже уведомлён."
)
await m.answer(
"Telegram бот для портала packages.altlinux.org\n"
......
......@@ -33,7 +33,7 @@ async def news_handler(
await m.ctx_api.send_message(
chat_id=m.from_user.id, text=text, reply_markup=news_keyboards.news_type_kb
)
if isinstance(m, CallbackQuery):
await m.answer()
......
......@@ -22,26 +22,27 @@ async def profile_handler(m: Message, user: User | None) -> None:
if user is None:
return
maintainer_data = await altrepo.api.site.maintainer_info(user.default_branch, user.maintainer)
maintainer = maintainer_data.information
maintainer_data = await altrepo.api.site.maintainer_info(user.default_branch, user.maintainer.nickname)
count_source_pkg = maintainer_data.information.count_source_pkg
roles = DB.user.get_roles(m.from_user.id)
watch = await altrepo.parser.packages.watch_by_maintainer(
maintainer.packager_nickname, "by-acl"
user.maintainer.nickname, "by-acl"
)
bugs_data = await altrepo.api.bug.bugzilla_by_maintainer(user.maintainer)
bugs_data = await altrepo.api.bug.bugzilla_by_maintainer(user.maintainer.nickname)
if bugs_data:
all_bugs = bugs_data.bugs
unresolved_bugs = [bug for bug in bugs_data.bugs if bug.status not in ["RESOLVED", "CLOSED"]]
unresolved_bugs = [
bug for bug in bugs_data.bugs if bug.status not in ["RESOLVED", "CLOSED"]]
else:
all_bugs = []
unresolved_bugs = []
await m.answer(
"Профиль:\n\n"
f"Сопровождающий: {maintainer.packager_name} ({maintainer.packager_nickname})\n"
f"Исходные пакеты: {maintainer.count_source_pkg}\n"
f"Сопровождающий: {user.maintainer.name_ru or user.maintainer.name} ({user.maintainer.nickname})\n"
f"Исходные пакеты: {count_source_pkg}\n"
f"Устаревшие пакеты: {len(watch)}\n"
"\n"
f"Всего багов: {len(all_bugs)}\n"
......@@ -50,6 +51,7 @@ async def profile_handler(m: Message, user: User | None) -> None:
reply_markup=profile_keyboards.profile_kb
)
@dp.callback_query(PayloadEqRule("profile/settings"))
async def callback_confirm_handler(cb: CallbackQuery) -> None:
await cb.ctx_api.send_message(
......@@ -59,10 +61,11 @@ async def callback_confirm_handler(cb: CallbackQuery) -> None:
)
await cb.answer()
@dp.callback_query(PayloadEqRule("profile/settings/maintainer"))
async def callback_confirm_handler(cb: CallbackQuery) -> None:
await cb.edit_text("Введите никнейм сопровождающего:")
api_data = await altrepo.api.site.all_maintainers("sisyphus")
while True:
msg, _ = await wm.wait(MESSAGE_FROM_USER, cb.from_user.id, release=HasText())
......@@ -84,18 +87,20 @@ async def callback_confirm_handler(cb: CallbackQuery) -> None:
"Введите никнейм сопровождающего:"
)
@dp.callback_query(PayloadEqRule("profile/settings/branch"))
async def callback_confirm_handler(cb: CallbackQuery) -> None:
await cb.edit_text(
"Выберите репозиторий",
reply_markup=profile_keyboards.profile_settings_branch_kb()
)
@dp.callback_query(PayloadMarkupRule("profile/settings/branch/<branch>"))
async def callback_confirm_handler(cb: CallbackQuery, branch: str) -> None:
await cb.edit_text(f"Вы выбрали {branch}")
DB.user.change_default_branch(
cb.from_user.id,
branch
......@@ -103,10 +108,12 @@ async def callback_confirm_handler(cb: CallbackQuery, branch: str) -> None:
await sleep(3.0)
await cb.delete()
@dp.callback_query(PayloadEqRule("command/menu"))
async def menu_handler(cb: CallbackQuery):
await send_menu(cb=cb)
@dp.message(Command(["menu", "меню"]) | Text(["меню", "menu"]), IsPrivate())
async def menu_handler(m: Message):
await send_menu(m=m)
......@@ -5,8 +5,6 @@ from database.func import DB
from database.models import User
from data.keyboards import start_keyboards
from altrepo import altrepo
from services.menu import send_menu
from config import config, DEFAUIL_BRANCHES
......@@ -16,6 +14,7 @@ wm = WaiterMachine(dp)
dp.message.auto_rules = IsPrivate()
@dp.message(StartCommand())
async def start_handler(m: Message, user: User | None) -> None:
......@@ -23,23 +22,18 @@ async def start_handler(m: Message, user: User | None) -> None:
await m.answer(
"Введите никнейм сопровождающего:"
)
api_data = await altrepo.api.site.all_maintainers("sisyphus")
while True:
msg, _ = await wm.wait(MESSAGE_FROM_USER, m.from_user.id, release=HasText())
maintainer = msg.text.unwrap().lower()
if any(_m.packager_nickname == maintainer for _m in api_data.maintainers):
_maintainer = msg.text.unwrap().lower()
maintainer = DB.maintainer.get(_maintainer)
if maintainer:
await m.answer(
f"Вы выбрали {maintainer}"
)
DB.user.add(
m.from_user.id,
maintainer
f"Вы выбрали {maintainer.nickname}"
)
break
else:
await m.answer(
f"Сопровождающий {maintainer} не найден.\n"
f"Сопровождающий {_maintainer} не найден.\n"
"Введите никнейм сопровождающего:"
)
await m.answer(
......@@ -60,7 +54,6 @@ async def start_handler(m: Message, user: User | None) -> None:
"Выберите репозиторий по умолчанию.",
reply_markup=start_keyboards.default_branch_kb()
)
DB.user.add(
m.from_user.id,
maintainer,
......
......@@ -11,10 +11,11 @@ from database.models import User
dp = Dispatch()
wm = WaiterMachine(dp)
@dp.message(Command("statistics", Argument("branch", optional=True)))
@dp.message(Text(["statistics", "статистика"], ignore_case=True), IsPrivate())
async def statistics_handler(m: Message, user: User | None, branch: str | None = None) -> None:
active_branches = (await altrepo.api.packageset.active_packagesets()).packagesets
if branch:
branch = branch.strip().lower()
......@@ -26,12 +27,12 @@ async def statistics_handler(m: Message, user: User | None, branch: str | None =
branch = user.default_branch
else:
branch = active_branches[0]
statistics_data = (await altrepo.api.packageset.repository_statistics(branch)).branches[0]
statistics_date = (datetime.fromisoformat(
statistics_data.date_update)).strftime("%F")
if "_" in statistics_data.branch:
branch, arch = statistics_data.branch.split("_")
branch = f"{branch} ({arch})"
......
......@@ -5,6 +5,7 @@ from telegrinder.tools.formatting import HTMLFormatter
from altrepo import altrepo
from database.models import User
from database.func import DB
from data.keyboards import watch_keyboards
dp = Dispatch()
......@@ -12,8 +13,8 @@ dp = Dispatch()
@dp.message(
Command("watch",
Argument("maintainer", optional=True),
Argument("acl", optional=True))
Argument("maintainer", optional=True),
Argument("acl", optional=True))
)
@dp.message(Text(["watch", "отслеживание"], ignore_case=True), IsUser())
async def watch_test_handler(
......@@ -22,14 +23,13 @@ async def watch_test_handler(
if maintainer:
maintainer = maintainer.lower()
maintainer_data = await altrepo.api.site.all_maintainers("sisyphus")
if not any(
_m.packager_nickname == maintainer for _m in maintainer_data.maintainers
):
_maintainer = DB.maintainer.get(maintainer)
if not _maintainer:
await m.answer(f"Сопровождающий {maintainer} не найден.")
return
else:
if user:
maintainer = user.maintainer
maintainer = user.maintainer.nickname
else:
return
......
......@@ -6,10 +6,11 @@ from telegrinder.node import Error
from config import tg_api
from altrepo import altrepo
from altrepo.api.errors import TooManyRequests
from database.models import db, User
from database.models import db, Maintainer, User, Package
from middlewares import UserMiddleware
from services.test_api_version import test_api_version
from services.update_maintainers import update_maintainers
bot = Telegrinder(tg_api)
bot.dispatch.load_from_dir("src/handlers")
......@@ -18,10 +19,11 @@ bot.on.message.register_middleware(UserMiddleware)
@bot.loop_wrapper.lifespan.on_startup
async def startup():
db.create_tables([User])
db.create_tables([Maintainer, User, Package])
logger.info("initializing ALTRepo")
await altrepo.init()
await test_api_version()
await update_maintainers()
await bot.api.set_my_commands(commands=[
BotCommand("watch", "Отслеживание по пакетам"),
BotCommand("bugs", "Отслеживание по ошибкам")
......@@ -35,6 +37,11 @@ async def shutdown():
@bot.loop_wrapper.interval(days=1)
async def api_test():
await test_api_version()
@bot.loop_wrapper.interval(days=1)
async def update_maintainers_db():
await update_maintainers()
@bot.on.error()
async def error_handler(err: Error[TooManyRequests], m: Message):
......
......@@ -6,7 +6,7 @@ from collections import defaultdict
from altrepo.parser.models import PackagesModel, PackageElementModel, RemovedPackageElementModel
from config import PACKAGES_URL
from services.utils import translate_async, chunk_list
from services.utils import translate_package, translate_maintainer, chunk_list
repo = PACKAGES_URL.format(repo="sisyphus")
......@@ -47,8 +47,8 @@ async def format_packages(packages: PackagesModel, translate: bool | None = None
async def _format_package(package: PackageElementModel, translate: bool):
message = HTMLFormatter(
bold(link(f"{repo}srpms/{package.name}", text=package.name))
) + f" - {(await translate_async(package.description)) if translate else package.description}\n"
message += f"{(await translate_async(package.maintainer_name)) if translate else package.maintainer_name} ({package.maintainer_nick})\n\n"
) + f" - {(await translate_package(package.name, package.description)) if translate else package.description}\n"
message += f"{(await translate_maintainer(package.maintainer_nick)) if translate else package.maintainer_name} ({package.maintainer_nick})\n\n"
return message
......@@ -77,12 +77,12 @@ async def _format_updated_packages(packages_model: PackagesModel, translate: boo
selected_pkgs = random.sample(pkgs, min(8, len(pkgs)))
maintainer_display = (
await translate_async(name) if translate else name
await translate_maintainer(nick) if translate else name
) + f" ({nick})"
for pkg in selected_pkgs:
description = (
await translate_async(pkg.description)
await translate_package(pkg.name, pkg.description)
if translate else pkg.description
)
pkg_link = link(f"{repo}srpms/{pkg.name}", text=pkg.name)
......
from telegrinder.modules import logger
from altrepo import altrepo
from database.func import DB
async def update_maintainers():
maintainers = await altrepo.api.site.all_maintainers("sisyphus")
for maintainer in maintainers.maintainers:
DB.maintainer.add(
maintainer.packager_nickname,
maintainer.packager_name
)
logger.info("the database of maintainers has been updated")
import asyncio
async def translate_async(text):
from database.func import DB
async def _translate(text):
process = await asyncio.create_subprocess_exec(
"trans", "-b", "-e", "bing", text,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE
)
stdout, stderr = await process.communicate()
if process.returncode != 0:
raise RuntimeError(f"Translate error: {stderr.decode().strip()}")
return stdout.decode().strip()
async def translate_package(name, summary):
package = DB.package.get(name)
if not package:
summary_ru = await _translate(summary)
DB.package.add(
name,
summary,
summary_ru
)
else:
summary_ru = package.summary_ru
return summary_ru
async def translate_maintainer(nick):
maintainer = DB.maintainer.get(nick)
if not maintainer:
return "..."
if maintainer.name_ru:
return maintainer.name_ru
else:
name_ru = await _translate(maintainer.name)
maintainer.name_ru = name_ru
maintainer.save()
return (name_ru)
def chunk_list(lst, size):
return [lst[i:i + size] for i in range(0, len(lst), size)]
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