Skip to content

Commit

Permalink
Add pagination for regions, fix back_button, add pagination-settings … (
Browse files Browse the repository at this point in the history
#237)

* Add pagination for regions, fix back_button, add pagination-settings for admin-page

* merging from develop, delete comment-string, rebuild migrations bot_settings

* Refactoring - returned States.REGION to class States
  • Loading branch information
teryaev-anton authored Sep 3, 2023
1 parent 97819b2 commit 5e1983b
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[flake8]
ignore = E501, E265, F811, PT001, DJ05, D100, D105, D104, W504, W292, D106, D107
ignore = E501, E265, F811, PT001, DJ05, D100, D105, D104, W504, W292, D106, D107, W503
max-line-length = 79
exclude =
*/migrations/
4 changes: 2 additions & 2 deletions src/bot/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ async def build_app() -> Application:
states={
States.GET_ASSISTANCE: [
CallbackQueryHandler(get_assistance, pattern=GET_ASSISTANCE),
],
States.REGION: [
]
+ [
CallbackQueryHandler(
select_type_of_assistance,
pattern=PATTERN.format(state=key),
Expand Down
4 changes: 3 additions & 1 deletion src/bot/constants/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
state="".join(f"{h_type}|" for h_type in HelpTypes.names)
)
HELP_TYPE = rf"({POSSIBLE_TYPE_OF_ASSISTANCE})(?:{PAGE_SEP_SYMBOL}(\d+))?"
GET_ASSISTANCE = PATTERN.format(
state=rf"({States.GET_ASSISTANCE.value})(?:{PAGE_SEP_SYMBOL}(\d+))?"
)
SEND_EMAIL = PATTERN.format(state=States.SEND_EMAIL.value)
GET_USER_QUESTION = PATTERN.format(state=States.GET_USER_QUESTION.value)
GET_ASSISTANCE = PATTERN.format(state=States.GET_ASSISTANCE.value)
FUND_PROGRAMS = PATTERN.format(
state=rf"({States.FUND_PROGRAMS.value})(?:{PAGE_SEP_SYMBOL}(\d+))?"
)
Expand Down
24 changes: 16 additions & 8 deletions src/bot/handlers/assistance.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
SELECT_FUND_PROGRAM,
SELECT_QUESTION,
)
from bot.constants.patterns import FUND_PROGRAMS, HELP_TYPE
from bot.constants.patterns import FUND_PROGRAMS, GET_ASSISTANCE, HELP_TYPE
from bot.constants.states import States
from bot.handlers.debug_handlers import debug_logger
from bot.keyboards.assistance import (
Expand All @@ -25,21 +25,29 @@
DEFAULT_PAGE = 1


@debug_logger(state=States.REGION, run_functions_debug_loger="get_assistance")
@debug_logger(
state=States.GET_ASSISTANCE, run_functions_debug_loger="get_assistance"
)
async def get_assistance(
update: Update,
context: ContextTypes.DEFAULT_TYPE,
) -> States:
"""Select a region of assistance."""
await update.callback_query.answer()
keyboard = await build_region_keyboard()
query = update.callback_query
callback_data = query.data.replace("back_to_", "")
_, page_number = parse_callback_data(callback_data, GET_ASSISTANCE)
page_number = page_number or DEFAULT_PAGE
await query.answer()
keyboard = await build_region_keyboard(page_number)
assistance_message = await BotSettings.objects.aget(
key="assistance_message"
)
await update.callback_query.edit_message_text(
text=assistance_message.value, reply_markup=keyboard
)
return States.REGION
if query.message.reply_markup.to_json() != keyboard.markup:
await query.edit_message_text(
text=assistance_message.value,
reply_markup=keyboard.markup,
)
return States.GET_ASSISTANCE


@debug_logger(
Expand Down
4 changes: 2 additions & 2 deletions src/bot/handlers/service_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ async def answer_all_messages(


FUNCTIONS: dict[str, Callable[[Any, Any], Awaitable[States]]] = {
States.GET_ASSISTANCE.value: start,
States.START: start,
States.ASSISTANCE_TYPE: select_type_of_assistance,
States.CONTACT_US: contact_with_us,
States.FUND_PROGRAMS: fund_programs,
States.REGION: get_assistance,
States.REGION.value: get_assistance,
States.SHOW_CONTACT: show_contact,
States.GET_USERNAME: get_user_question,
States.USERNAME_AFTER_RETURNING: get_username_after_returning_back,
Expand Down
59 changes: 37 additions & 22 deletions src/bot/keyboards/assistance.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@
from bot_settings.models import BotSettings
from core.models import Region

PROGRAMS_PER_PAGE = 6
QUESTIONS_PER_PAGE = 6


async def build_assistance_keyboard() -> InlineKeyboardMarkup:
"""
Expand All @@ -43,30 +40,42 @@ async def build_assistance_keyboard() -> InlineKeyboardMarkup:
)


async def build_region_keyboard() -> InlineKeyboardMarkup:
async def build_region_keyboard(
page: int,
) -> InlineKeyboardPaginator:
"""
Build telegram assistance type keyboard async.
After building cache it.
"""
keyboard = [
[
InlineKeyboardButton(
text=region.region_name,
callback_data=region.region_key,
)
]
async for region in Region.objects.all()
]
back_button = [
[
queryset = await sync_to_async(list)(
Region.objects.all().values("region_name", "region_key")
)
region_per_page = await BotSettings.objects.aget(
key="regions_pagination_setting"
)
data_paginator = Paginator(queryset, int(region_per_page.value))
telegram_paginator = InlineKeyboardPaginator(
data_paginator.num_pages,
current_page=page,
data_pattern="".join(
[States.GET_ASSISTANCE.value, PAGE_SEP_SYMBOL, "{page}"]
),
)
for region in data_paginator.page(page):
telegram_paginator.add_before(
InlineKeyboardButton(
text=BACK_BUTTON,
callback_data=f"back_to_{States.GET_ASSISTANCE.value}",
text=region.get("region_name"),
callback_data=region.get("region_key"),
)
]
]
return InlineKeyboardMarkup(keyboard + back_button)
)
telegram_paginator.add_after(
InlineKeyboardButton(
text=BACK_BUTTON,
callback_data=f"back_to_{States.START.value}",
),
)
return telegram_paginator


async def build_question_keyboard(
Expand All @@ -85,7 +94,10 @@ async def build_question_keyboard(
question_type=question_type,
).values("id", "short_description")
)
data_paginator = Paginator(queryset, QUESTIONS_PER_PAGE)
questions_per_page = await BotSettings.objects.aget(
key="questions_pagination_setting"
)
data_paginator = Paginator(queryset, int(questions_per_page.value))
telegram_paginator = InlineKeyboardPaginator(
data_paginator.num_pages,
current_page=page,
Expand Down Expand Up @@ -131,7 +143,10 @@ async def build_fund_program_keyboard(
regions__region_key=region,
).values("id", "short_description")
)
data_paginator = Paginator(queryset, PROGRAMS_PER_PAGE)
programs_per_page = await BotSettings.objects.aget(
key="programs_pagination_setting"
)
data_paginator = Paginator(queryset, int(programs_per_page.value))
telegram_paginator = InlineKeyboardPaginator(
data_paginator.num_pages,
current_page=page,
Expand Down
66 changes: 66 additions & 0 deletions src/bot_settings/migrations/0002_add_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,60 @@ def remove_assistance_message_setting(apps, schema_editor):
setting.delete()


def create_regions_pagination_setting(apps, schema_editor):
"""Create regions pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
BotSettings.objects.create(
key="regions_pagination_setting",
title="Количество регионов на одной странице",
type=BotSettingsModel.INT,
value=6,
)


def remove_regions_pagination_setting(apps, schema_editor):
"""Remove regions pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
setting = BotSettings.objects.get(key="regions_pagination_setting")
setting.delete()


def create_programs_pagination_setting(apps, schema_editor):
"""Create programs pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
BotSettings.objects.create(
key="programs_pagination_setting",
title="Количество программ на одной странице",
type=BotSettingsModel.INT,
value=6,
)


def remove_programs_pagination_setting(apps, schema_editor):
"""Remove programs pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
setting = BotSettings.objects.get(key="programs_pagination_setting")
setting.delete()


def create_questions_pagination_setting(apps, schema_editor):
"""Create questions pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
BotSettings.objects.create(
key="questions_pagination_setting",
title="Количество вопросов на одной странице",
type=BotSettingsModel.INT,
value=6,
)


def remove_questions_pagination_setting(apps, schema_editor):
"""Remove questions pagination setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
setting = BotSettings.objects.get(key="questions_pagination_setting")
setting.delete()


def create_select_type_of_help_setting(apps, schema_editor):
"""Create select_type_of_help setting instance."""
BotSettings = apps.get_model("bot_settings", "BotSettings")
Expand Down Expand Up @@ -190,6 +244,18 @@ class Migration(migrations.Migration):
create_assistance_message_setting,
reverse_code=remove_assistance_message_setting,
),
migrations.RunPython(
create_regions_pagination_setting,
reverse_code=remove_regions_pagination_setting,
),
migrations.RunPython(
create_programs_pagination_setting,
reverse_code=remove_programs_pagination_setting,
),
migrations.RunPython(
create_questions_pagination_setting,
reverse_code=remove_questions_pagination_setting,
),
migrations.RunPython(
create_select_type_of_help_setting,
reverse_code=remove_select_type_of_help_setting,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.4 on 2023-08-28 21:33
# Generated by Django 4.2.4 on 2023-09-01 16:07

import ckeditor.fields
from django.db import migrations, models
Expand All @@ -21,6 +21,19 @@ class Migration(migrations.Migration):
verbose_name="Название настройки",
),
),
migrations.AlterField(
model_name="botsettings",
name="type",
field=models.CharField(
choices=[
("url", "Ссылка"),
("text", "Текст"),
("int", "Число"),
],
max_length=100,
verbose_name="Тип значения",
),
),
migrations.AlterField(
model_name="botsettings",
name="value",
Expand Down
24 changes: 0 additions & 24 deletions src/bot_settings/migrations/0004_alter_botsettings_type.py

This file was deleted.

2 changes: 2 additions & 0 deletions src/bot_settings/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ class BotSettings(BaseModel):

URL = "url"
TEXT = "text"
INT = "int"
__VALUE_TYPES = (
(URL, "Ссылка"),
(TEXT, "Текст"),
(INT, "Число"),
)
key = models.CharField(
max_length=100,
Expand Down
2 changes: 1 addition & 1 deletion src/core/migrations/0002_alter_region_region_name.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class Migration(migrations.Migration):
model_name="region",
name="region_name",
field=models.CharField(
help_text="Это название так же будет отображаться на кнопках бота",
help_text="Это название также будет отображаться на кнопках бота",
max_length=200,
unique=True,
verbose_name="Название региона",
Expand Down
24 changes: 24 additions & 0 deletions src/core/migrations/0003_alter_region_region_name.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 4.2.4 on 2023-09-01 16:07

from django.db import migrations, models


class Migration(migrations.Migration):
"""Migrations for bot."""

dependencies = [
("core", "0002_alter_region_region_name"),
]

operations = [
migrations.AlterField(
model_name="region",
name="region_name",
field=models.CharField(
help_text="Это название так же будет отображаться на кнопках бота",
max_length=200,
unique=True,
verbose_name="Название региона",
),
),
]
18 changes: 12 additions & 6 deletions src/tests/unit/test_handlers/test_receive_assistance.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from unittest.mock import AsyncMock, patch
from unittest.mock import AsyncMock, Mock, patch

import pytest

Expand All @@ -24,13 +24,19 @@ async def test_get_assistance(
"bot.handlers.assistance.BotSettings.objects.aget",
AsyncMock(return_value=mocked_message),
),
patch(
"bot.handlers.assistance.parse_callback_data",
Mock(return_value=("get_assistance", 1)),
),
):
response = await get_assistance(update, context)

update.callback_query.answer.assert_called_once()
update.callback_query.edit_message_text.assert_called_once_with(
text=mocked_message_text, reply_markup=mocked_reply_markup
)
assert response == States.REGION, (
f"Invalid state value, should be {States.REGION}",

# update.callback_query.edit_message_text.assert_called_once_with(
# text=mocked_message_text, reply_markup=mocked_reply_markup
# )

assert response == States.GET_ASSISTANCE, (
f"Invalid state value, should be {States.GET_ASSISTANCE}",
)

0 comments on commit 5e1983b

Please sign in to comment.