Skip to content

Commit

Permalink
minor mistakes hotfix; added more information about channel in scroll…
Browse files Browse the repository at this point in the history
…-dialog
  • Loading branch information
bralbral committed Dec 18, 2023
1 parent d4a2c21 commit d1119e2
Show file tree
Hide file tree
Showing 10 changed files with 95 additions and 27 deletions.
3 changes: 3 additions & 0 deletions src/bot/dialogs/channel/getters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from aiogram_dialog import DialogManager

from ...filters import UserRole
from .constants import ID_STUB_SCROLL
from src.db import DataAccessLayer

Expand All @@ -8,13 +9,15 @@ async def scroll_getter(dialog_manager: DialogManager, **_kwargs):
current_page = await dialog_manager.find(ID_STUB_SCROLL).get_page()

dal: DataAccessLayer = dialog_manager.start_data["dal"]
role: UserRole = dialog_manager.start_data["role"]

channels = await dal.get_channels()

dialog_manager.dialog_data["channels"] = channels
dialog_manager.dialog_data["current_page"] = current_page

return {
"role": role,
"is_empty": True if len(channels) == 0 else False,
"pages": len(channels),
"channels": [channel.to_html() for channel in channels],
Expand Down
6 changes: 6 additions & 0 deletions src/bot/dialogs/channel/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from aiogram_dialog.widgets.text import Multi
from sulguk import SULGUK_PARSE_MODE

from ...filters import UserRole
from .constants import ID_STUB_SCROLL
from .getters import scroll_getter
from .on_click import on_delete
Expand Down Expand Up @@ -65,6 +66,11 @@ def scroll_window():
Button(Const("🗑️ Delete"), id="delete", on_click=on_delete),
Button(Const("✏️ Turn on"), id="off", on_click=on_turn_on),
Button(Const("✏️ Turn off"), id="on", on_click=on_turn_off),
when=F["role"] == UserRole.SUPERUSER,
),
Row(
Button(Const("✏️ Turn off"), id="on", on_click=on_turn_off),
when=F["role"] == UserRole.ADMIN,
),
Button(Const("❌ Exit"), id="finish", on_click=on_finish),
when=~F["is_empty"],
Expand Down
6 changes: 3 additions & 3 deletions src/bot/handlers/admin/add_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from ...filters import RoleFilter
from ...filters import UserRole
from ...states import ChannelsSG
from .utils import url_validator
from src.logger import logger
from src.utils import youtube_channel_url_validator


add_channel_router = Router(name="add_channel")
Expand All @@ -40,7 +40,7 @@ async def add_channel(message: Message, state: FSMContext, **kwargs) -> None:
)
async def url_handler(message: Message, state: FSMContext, **kwargs) -> None:
url = message.text.lower().strip()
if url_validator(url):
if youtube_channel_url_validator(url):
await state.update_data(url=url)
await message.answer(
f"URL set to <b>{url}</b>, enter display name or <b>/cancel</b> for reject",
Expand Down Expand Up @@ -76,7 +76,7 @@ async def label_handler(
url=url,
label=label,
enabled=True,
user_id=user_schema.user_id,
user_id=user_schema.id,
)

result = await dal.create_channel(channel_schema=channel_schema)
Expand Down
10 changes: 8 additions & 2 deletions src/bot/handlers/admin/scroll_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,16 @@
State(state="*"),
)
async def start_channels_dialog(
message: Message, dialog_manager: DialogManager, dal: DataAccessLayer, **kwargs
message: Message,
dialog_manager: DialogManager,
dal: DataAccessLayer,
role: UserRole,
**kwargs,
):
await dialog_manager.start(
ChannelsSG.scrolling, mode=StartMode.RESET_STACK, data={"dal": dal}
ChannelsSG.scrolling,
mode=StartMode.RESET_STACK,
data={"dal": dal, "role": role},
)


Expand Down
28 changes: 20 additions & 8 deletions src/bot/handlers/superuser/add_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from ...filters import RoleFilter
from ...filters import UserRole
from ...states import ChannelsSG

from src.utils import youtube_channel_url_validator

add_channels_router = Router(name="add_channels")

Expand All @@ -34,7 +34,9 @@ async def add_channels(message: Message, state: FSMContext, **kwargs) -> None:
await message.answer(
text="Upload a file with format: <br/>"
"<code>url[TAB]label[END_ROW]</code><br/>"
"every single line == channel to insert.",
"every single line == channel to insert.<br/>"
"Set channel url in format: <b>https://www.youtube.com/@username</b>"
"Enter /cancel for exit <br/>",
parse_mode=SULGUK_PARSE_MODE,
)
await state.set_state(ChannelsSG.bulk_channels)
Expand All @@ -61,7 +63,7 @@ async def channel_file_handler(
user_schema = await dal.get_user_by_attr(**{"user_id": message.from_user.id})
if user_schema:
_: BinaryIO = await bot.download_file(file.file_path)

channels: list[ChannelCreateDTO] = []
with TextIOWrapper(_, encoding="utf-8") as text_io:
for line in text_io:
line = line.strip()
Expand All @@ -73,17 +75,27 @@ async def channel_file_handler(
)
return

if not youtube_channel_url_validator(splitted_line[0]):
await message.answer(
text=f"Error url validation: {splitted_line[0]} <br/>"
"Set channel url in format: <b>https://www.youtube.com/@username</b>",
parse_mode=SULGUK_PARSE_MODE,
)
return

channel = ChannelCreateDTO(
url=splitted_line[0],
label=splitted_line[1],
enabled=True,
user_id=user_schema.user_id,
user_id=user_schema.id,
)
channels.append(channel)

result: Optional[ChannelRetrieveDTO] = await dal.create_channel(
channel_schema=channel
)
await message.answer(f"{line} {str(result)}")
for channel in channels:
result: Optional[ChannelRetrieveDTO] = await dal.create_channel(
channel_schema=channel
)
await message.answer(f"{str(result)}")

await state.clear()

Expand Down
34 changes: 29 additions & 5 deletions src/db/dao/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

from pydantic import TypeAdapter
from sqlalchemy import Delete
from sqlalchemy import inspect
from sqlalchemy import ScalarResult
from sqlalchemy import Select
from sqlalchemy import Update
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from src.db.exceptions import ColumnDoesNotExist
from src.db.models import ModelOrm
Expand All @@ -23,6 +25,27 @@ def __init__(
self.model_orm = model_orm
self.schema = schema

@property
def relations(self):
"""
Get all relations
:return:
"""
return {
tuple_name_column[0]: tuple_name_column[1]
for tuple_name_column in inspect(self.model_orm).relationships.items()
}

async def scalars(self, statement):
"""
:param statement: sqlalchemy statement, например sqlalchemy.select
:return:
"""
for relation in self.relations.values():
statement = statement.options(selectinload(relation))

return await self.session.scalars(statement)

async def create(self, *args, **kwargs) -> Any:
raise NotImplementedError()

Expand All @@ -45,7 +68,7 @@ async def __get_by_attrs(self, **kwargs) -> ScalarResult:
.where(*where_clause)
.order_by(self.model_orm.id.desc())
)
result: ScalarResult = await self.session.scalars(stm)
result: ScalarResult = await self.scalars(statement=stm)
return result

async def list_by_attrs(self, **kwargs) -> list[DTO]:
Expand All @@ -54,8 +77,9 @@ async def list_by_attrs(self, **kwargs) -> list[DTO]:
:return:
"""
result: ScalarResult = await self.__get_by_attrs(**kwargs)
all_results = result.all()
ta = TypeAdapter(list[self.schema]) # type: ignore
dto_objects = ta.validate_python(result.all())
dto_objects = ta.validate_python(all_results)

return dto_objects

Expand All @@ -66,7 +90,7 @@ async def get_by_pk(self, pk: int) -> Optional[DTO]:
"""
stm = Select(self.model_orm).where(self.model_orm.id == pk)

result: ScalarResult = await self.session.scalars(stm)
result: ScalarResult = await self.scalars(statement=stm)
model: Optional[ModelOrm] = result.first()

if model:
Expand Down Expand Up @@ -95,7 +119,7 @@ async def delete_by_pk(self, pk: int) -> Optional[int]:
.where(self.model_orm.id == pk)
.returning(self.model_orm.id)
)
result: ScalarResult = await self.session.scalars(stm)
result: ScalarResult = await self.scalars(statement=stm)
deleted_id = result.first()

await self.session.commit()
Expand All @@ -108,7 +132,7 @@ async def update_by_pk(self, pk: int, data: dict) -> Optional[int]:
.values(**data)
.returning(self.model_orm.id)
)
result: ScalarResult = await self.session.scalars(stm)
result: ScalarResult = await self.scalars(statement=stm)
updated_id = result.first()

await self.session.commit()
Expand Down
21 changes: 17 additions & 4 deletions src/dto/channel.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from datetime import datetime

from pydantic import ConfigDict
from pydantic import Field
from pydantic import field_validator

from .base import DTO
from .user import UserRetrieveDTO


class ChannelBaseDTO(DTO):
Expand All @@ -29,13 +32,23 @@ class ChannelCreateDTO(ChannelBaseDTO):

class ChannelRetrieveDTO(ChannelCreateDTO):
id: int
user: UserRetrieveDTO
created_at: datetime
updated_at: datetime

def to_html(self) -> str:
user_attribute_list = [self.user.username, self.user.user_id]
attribute = next(item for item in user_attribute_list if item is not None)
user_link = f'<a href="{self.user.get_url_generated_by_id}">{attribute}</a>'

return (
f"<b>id</b>:{self.id}<br/>"
f"<b>label</b>:{self.label}<br/>"
f"<b>url</b>:{self.url}<br/>"
f"<b>enabled</b>:{self.enabled}<br/>"
f"<b>enabled</b>: <b>{self.enabled}</b><br/>"
f"<b>id</b>: {self.id}<br/>"
f"<b>label</b>: {self.label}<br/>"
f"<b>url</b>: {self.url}<br/>"
f"<b>added by</b>: {user_link}<br/>"
f"<b>added at</b>: {self.created_at}<br/>"
f"<b>last modified at</b>: {self.updated_at}<br/>"
)


Expand Down
4 changes: 4 additions & 0 deletions src/dto/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ class UserBaseDTO(DTO):
is_admin: bool
is_superuser: bool

@property
def get_url_generated_by_id(self) -> str:
return f"tg://openmessage?user_id={self.user_id}"

model_config = ConfigDict(from_attributes=True)


Expand Down
4 changes: 2 additions & 2 deletions src/bot/handlers/admin/utils.py → src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
)


def url_validator(link: str):
def youtube_channel_url_validator(link: str):
match = re.match(YOUTUBE_USERNAME_CHANNEL_LINK_PATTERN, link)
return bool(match)


__all__ = ["url_validator"]
__all__ = ["youtube_channel_url_validator"]
6 changes: 3 additions & 3 deletions tests/test_url_validation.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from src.bot.handlers.admin.utils import url_validator
from src.utils import youtube_channel_url_validator

GOOD_URL = "https://www.youtube.com/@gtrfmusic"
MALFORMED_URL = "https://www.youtube.com/@gtrfmusic?si=23213173713"


def test_url_validation():
assert url_validator(GOOD_URL) is True
assert url_validator(MALFORMED_URL) is False
assert youtube_channel_url_validator(GOOD_URL) is True
assert youtube_channel_url_validator(MALFORMED_URL) is False

0 comments on commit d1119e2

Please sign in to comment.