Skip to content

Commit

Permalink
Reworked mechanism of skipping empty days
Browse files Browse the repository at this point in the history
Instead of just skipping days without lessons (which was confusing to users before), now they see a menu that says the number of days without lessons.

Also refactored bot/pages/schedule.py file
  • Loading branch information
cubicbyte committed Feb 18, 2023
1 parent e860edd commit 5df43c0
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 68 deletions.
169 changes: 101 additions & 68 deletions bot/pages/schedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,71 @@

logger = logging.getLogger()

def create_lessons_empty_text(message: types.Message) -> str:
line = '—————————————————————————'
lessons_missing_text = message.lang['text.subjects.missing']
spaces_count = int(len(line) / 2) - int(len(lessons_missing_text) / 2)

# All this code is needed to center the text
if spaces_count < 0:
spaces_count = 0
elif len(line) % 2 == 0 and len(lessons_missing_text) % 2 != 0:
spaces_count -= 1

spaces = ' ' * spaces_count
text = f"`{line}`\n\n`{spaces}``{lessons_missing_text}`\n\n`{line}`"
def count_no_lesson_days(schedule: list[dict[str, any]], date: _date, direction_right = True) -> timedelta | None:
'Counts the number of days without lessons'
if not direction_right:
schedule = reversed(schedule)

res = None
for day in schedule:
day_date = datetime.strptime(day['date'], '%Y-%m-%d').date()
if direction_right:
if day_date > date:
res = day_date - date
break
else:
if day_date < date:
res = date - day_date
break

return res

def get_localized_date(date: _date, message: types.Message) -> str:
date_localized = format_date(date, locale=message.lang_code)
week_day_localized = message.lang['text.time.week_day.' + str(date.weekday())]
full_date_localized = f"*{date_localized}* `[`*{week_day_localized}*`]`"
return full_date_localized

def create_schedule_section(schedule_day: dict[str, any], message: types.Message) -> str:
schedule_section = ''
for lesson in schedule_day['lessons']:
for period in lesson['periods']:
# Escape apostrophes in teacher names because they break Telegram Markdown
period['teachersName'] = period['teachersName'].replace('`', '\\`')
period['teachersNameFull'] = period['teachersNameFull'].replace('`', '\\`')

# If there are multiple teachers, display the first one and add +1 to the end
if ',' in period['teachersName']:
count = str(period['teachersNameFull'].count(','))
period['teachersName'] = period['teachersName'][:period['teachersName'].index(',')] + ' +' + count
period['teachersNameFull'] = period['teachersNameFull'][:period['teachersNameFull'].index(',')] + ' +' + count

schedule_section += message.lang['text.schedule.period'].format(
**period,
lessonNumber=lesson['number']
)

schedule_section += '`—――—―``―——``―—―``――``—``―``—``――――``――``―――`'
return schedule_section


return text

def create_message(message: types.Message, date: _date | str) -> dict:
# Create "date_str" and "date" variables
if isinstance(date, _date):
date_str = date.strftime('%Y-%m-%d')
else:
date_str = date
date = datetime.strptime(date, '%Y-%m-%d').date()

try:
schedule = api.timetable_group(message.config['groupId'], date)

# Get schedule
dateStart = date - timedelta(days=date.weekday() + 7)
dateEnd = dateStart + timedelta(days=20)
try:
schedule = api.timetable_group(message.config['groupId'], dateStart, dateEnd)
except requests.exceptions.HTTPError as err:
if err.response.status_code == 422:
return create_invalid_group_message(message)
Expand All @@ -46,71 +85,65 @@ def create_message(message: types.Message, date: _date | str) -> dict:
):
return create_api_unavaliable_message(message)

page_content = ''
markup = types.InlineKeyboardMarkup(row_width=2)
current_date = _date.today()

day_next = None
# Find schedule of current day
cur_day_schedule = None
for day in schedule:
if day['date'] != date_str:
day_next = day['date']
if day['date'] == date_str:
cur_day_schedule = day
break
if day_next is None:
day_next = (date + timedelta(days=1)).strftime('%Y-%m-%d')


# Create the schedule page content
if cur_day_schedule is not None:
msg_text = message.lang['page.schedule'].format(
date=get_localized_date(date, message),
schedule=create_schedule_section(cur_day_schedule, message)
)
# If there is no lesson for the current day
else:
# Variables with the number of days you need to skip to reach a day with lessons
skip_left = count_no_lesson_days(schedule, date, direction_right=False)
skip_right = count_no_lesson_days(schedule, date, direction_right=True)
if skip_right is None:
skip_right = dateEnd - date + timedelta(days=1)
if skip_left is None:
skip_left = date - dateStart + timedelta(days=1)
# If there are no lessons for multiple days
# Then combine all the days without lessons into one page
if skip_left.days > 1 or skip_right.days > 1:
dateStart_localized = get_localized_date(date - skip_left + timedelta(days=1), message)
dateEnd_localized = get_localized_date(date + skip_right - timedelta(days=1), message)
msg_text = message.lang['page.schedule.empty.multiple_days'].format(
dateStart=dateStart_localized,
dateEnd=dateEnd_localized
)
# If no lessons for only one day
else:
msg_text = message.lang['page.schedule.empty'].format(date=get_localized_date(date, message))



# Create buttons
if cur_day_schedule is not None:
day_next = date + timedelta(days=1)
day_prev = date - timedelta(days=1)
else:
day_next = date + skip_right
day_prev = date - skip_left
markup = types.InlineKeyboardMarkup(row_width=2)
buttons = [
types.InlineKeyboardButton(text=message.lang['button.navigation.day_previous'], callback_data='open.schedule.day#date=' + (date - timedelta(days=1)).strftime('%Y-%m-%d')),
types.InlineKeyboardButton(text=message.lang['button.navigation.day_next'], callback_data='open.schedule.day#date=' + day_next),
types.InlineKeyboardButton(text=message.lang['button.navigation.day_previous'], callback_data='open.schedule.day#date=' + day_prev.strftime('%Y-%m-%d')),
types.InlineKeyboardButton(text=message.lang['button.navigation.day_next'], callback_data='open.schedule.day#date=' + day_next.strftime('%Y-%m-%d')),
types.InlineKeyboardButton(text=message.lang['button.navigation.week_previous'], callback_data='open.schedule.day#date=' + (date - timedelta(days=7)).strftime('%Y-%m-%d')),
types.InlineKeyboardButton(text=message.lang['button.navigation.week_next'], callback_data='open.schedule.day#date=' + (date + timedelta(days=7)).strftime('%Y-%m-%d')),
types.InlineKeyboardButton(text=message.lang['button.menu'], callback_data='open.menu')
]

if date != current_date:
# If the selected day is not today, then add "today" button
buttons.insert(
-1, types.InlineKeyboardButton(text=message.lang['button.navigation.today'], callback_data='open.schedule.today')
)

# If the selected day is not today, then add "today" button
if date != _date.today():
buttons.append(types.InlineKeyboardButton(text=message.lang['button.navigation.today'], callback_data='open.schedule.today'))
markup.add(*buttons)

# Find day in schedule
day_i = None
for i in range(len(schedule)):
if schedule[i]['date'] == date_str:
day_i = i
break
if day_i is None:
page_content = create_lessons_empty_text(message)

else:
# Create page content
for lesson in schedule[i]['lessons']:
for period in lesson['periods']:
period['teachersName'] = period['teachersName'].replace('`', '\'')
period['teachersNameFull'] = period['teachersNameFull'].replace('`', '\'')

# If there are multiple teachers, display the first one and add +1 to the end
if ',' in period['teachersName']:
count = str(period['teachersNameFull'].count(','))
period['teachersName'] = period['teachersName'][:period['teachersName'].index(',')] + ' +' + count
period['teachersNameFull'] = period['teachersNameFull'][:period['teachersNameFull'].index(',')] + ' +' + count

page_content += f"`———— ``{period['timeStart']}`` ——— ``{period['timeEnd']}`` ————`\n"
page_content += f"` `*{period['disciplineShortName']}*`[{period['typeStr']}]`\n"
page_content += f"`{lesson['number']} `{period['classroom']}\n` `{period['teachersNameFull']}\n"

page_content += '`—――—―``―——``―—―``――``—``―``—``――――``――``―――`'


date_locale = format_date(date, locale=message.lang_code)
week_day_locale = message.lang['text.time.week_day.' + str(date.weekday())]
date_locale_text = f"*{date_locale}* `[`*{week_day_locale}*`]`"

msg_text = message.lang['page.schedule'].format(
date=date_locale_text,
schedule=page_content
)

msg = {
'chat_id': message.chat.id,
Expand Down
3 changes: 3 additions & 0 deletions langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"text.not_selected": "\u274c Not selected",
"text.group_incorrect": "\u274c Failed to get schedule for your group\n\nPlease try to select another one.",
"text.from_cache": "Received from cache",
"text.schedule.period": "`———— ``{timeStart}`` ——— ``{timeEnd}`` ————`\n` `*{disciplineShortName}*`[{typeStr}]`\n`{lessonNumber} `{classroom}\n` `{teachersNameFull}\n",

"text.subjects.today": "*Classes today*",
"text.subjects.tomorrow": "*Classes tomorrow*",
Expand Down Expand Up @@ -95,6 +96,8 @@
"page.more": "\ud83d\uddc2 *Additionally*",
"page.info": "\u2139\ufe0f *Information*\n\n\ud83d\uddff *Creator* - @cubicbyte\n\ud83c\udf10 *Source code* - [github.com/cubicbyte/dteubot](https://github.com/cubicbyte/dteubot)\n\nUse the @dteubot as a tool to get the schedule for every day.",
"page.schedule": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n{schedule}",
"page.schedule.empty": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n`—————————————————————————`\n\n` No lessons`\n\n`—————————————————————————`",
"page.schedule.empty.multiple_days": "`From` \ud83d\udcc5 {dateStart}\n`To ` \ud83d\udcc5 {dateEnd}\n\n`—————————————————————————`\n\n` No lessons`\n\n`—————————————————————————`",
"page.api_unavaliable": "Seems like the timetable site is down/not responding right now.\n\nPlease, try later.",
"page.calls": "\ud83d\udd53 *Calls schedule*\n\n{schedule}",
"page.admin_panel": "\ud83d\udee0 *Control panel*"
Expand Down
3 changes: 3 additions & 0 deletions langs/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"text.not_selected": "\u274c Не выбрано",
"text.group_incorrect": "\u274c Не удалось получить расписание для вашей группы\n\nПопробуйте выбрать другую.",
"text.from_cache": "Получено с кеша",
"text.schedule.period": "`———— ``{timeStart}`` ——— ``{timeEnd}`` ————`\n` `*{disciplineShortName}*`[{typeStr}]`\n`{lessonNumber} `{classroom}\n` `{teachersNameFull}\n",

"text.subjects.today": "*Пары сегодня*",
"text.subjects.tomorrow": "*Пары завтра*",
Expand Down Expand Up @@ -95,6 +96,8 @@
"page.more": "\ud83d\uddc2 *Дополнительно*",
"page.info": "\u2139\ufe0f *Информация*\n\n\ud83d\uddff *Создатель* - @cubicbyte\n\ud83c\udf10 *Исходный код* - [github.com/cubicbyte/dteubot](https://github.com/cubicbyte/dteubot)\n\nИспользуйте бота @dteubot как инструмент для получения расписания пар на каждый день.",
"page.schedule": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n{schedule}",
"page.schedule.empty": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n`—————————————————————————`\n\n` Пары отсутствуют`\n\n`—————————————————————————`",
"page.schedule.empty.multiple_days": "`От` \ud83d\udcc5 {dateStart}\n`До` \ud83d\udcc5 {dateEnd}\n\n`—————————————————————————`\n\n` Пары отсутствуют`\n\n`—————————————————————————`",
"page.api_unavaliable": "Похоже, сайт с расписанием сейчас не работает/не отвечает.\n\nПожалуйста, попробуйте позже.",
"page.calls": "\ud83d\udd53 *Расписание звонков*\n\n{schedule}",
"page.admin_panel": "\ud83d\udee0 *Панель управления*"
Expand Down
3 changes: 3 additions & 0 deletions langs/uk.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"text.not_selected": "\u274c Не вибрано",
"text.group_incorrect": "\u274c Не вдалося отримати розклад для вашої групи\n\nСпробуйте вибрати іншу.",
"text.from_cache": "Отримано з кешу",
"text.schedule.period": "`———— ``{timeStart}`` ——— ``{timeEnd}`` ————`\n` `*{disciplineShortName}*`[{typeStr}]`\n`{lessonNumber} `{classroom}\n` `{teachersNameFull}\n",

"text.subjects.today": "*Пари сьогодні*",
"text.subjects.tomorrow": "*Пари завтра*",
Expand Down Expand Up @@ -95,6 +96,8 @@
"page.more": "\ud83d\uddc2 *Додатково*",
"page.info": "\u2139\ufe0f *Інформація*\n\n\ud83d\uddff *Створив бота* - @cubicbyte\n\ud83c\udf10 *Початковий код* - [github.com/cubicbyte/dteubot](https://github.com/cubicbyte/dteubot)\n\nВикористовуйте бота @dteubot як інструмент для отримання розкладу пар на кожен день.",
"page.schedule": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n{schedule}",
"page.schedule.empty": "\ud83d\udcc5 {date} \ud83d\udcc5\n\n`—————————————————————————`\n\n` Пари відсутні`\n\n`—————————————————————————`",
"page.schedule.empty.multiple_days": "`Від` \ud83d\udcc5 {dateStart}\n`До ` \ud83d\udcc5 {dateEnd}\n\n`—————————————————————————`\n\n` Пари відсутні`\n\n`—————————————————————————`",
"page.api_unavaliable": "Схоже, сайт з розкладом зараз не працює/не відповідає.\n\nБудь ласка, спробуйте пізніше.",
"page.calls": "\ud83d\udd53 *Розклад дзвінків*\n\n{schedule}",
"page.admin_panel": "\ud83d\udee0 *Панель управління*"
Expand Down

0 comments on commit 5df43c0

Please sign in to comment.