matplobbot-shared 0.1.30__py3-none-any.whl → 0.1.31__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of matplobbot-shared might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: matplobbot-shared
3
- Version: 0.1.30
3
+ Version: 0.1.31
4
4
  Summary: Shared library for the Matplobbot ecosystem (database, services, i18n).
5
5
  Author: Ackrome
6
6
  Author-email: ivansergeyevich@gmail.com
@@ -2,9 +2,9 @@ shared_lib/__init__.py,sha256=Wxuw1wbvCOsKqs6WfIQ05cx_vndhPs6rH2krMatFRqA,45
2
2
  shared_lib/database.py,sha256=vGiCxk1m_xZxaJQtjQPC_7G2Wxnu-ptWx5Z7q_XDIGs,20706
3
3
  shared_lib/i18n.py,sha256=VBWQWVF-k_HDiidYo_RUPyUCM7oL897z5hOw9jvOoYY,1762
4
4
  shared_lib/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- shared_lib/services/schedule_service.py,sha256=l4kffo866Pzj-rVNqAL-vMVYhB-Arfgl_bzwnNIVA9M,2441
5
+ shared_lib/services/schedule_service.py,sha256=UIyfNqXLJPsstGR8tGhbZ_hnK64QNxbaB-fUc7itX34,4355
6
6
  shared_lib/services/university_api.py,sha256=Ui-zjfKOHCCf2Imh8CNtVOWegwuep7IB8gO9IKNUrrE,1898
7
- matplobbot_shared-0.1.30.dist-info/METADATA,sha256=i0itMsVkSh3YoPt8uMPoifKOXd5DgXBTc9alPnT6ez0,395
8
- matplobbot_shared-0.1.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- matplobbot_shared-0.1.30.dist-info/top_level.txt,sha256=L8mrC50YWCe19jmh_zrUZFvXSkhsnES5K6y027G1838,11
10
- matplobbot_shared-0.1.30.dist-info/RECORD,,
7
+ matplobbot_shared-0.1.31.dist-info/METADATA,sha256=4b8ZQlFh79zZWjllQEuBRj2Vil3v0pPr4CUr6nMLg7o,395
8
+ matplobbot_shared-0.1.31.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
+ matplobbot_shared-0.1.31.dist-info/top_level.txt,sha256=L8mrC50YWCe19jmh_zrUZFvXSkhsnES5K6y027G1838,11
10
+ matplobbot_shared-0.1.31.dist-info/RECORD,,
@@ -1,10 +1,14 @@
1
1
  # bot/services/schedule_service.py
2
2
 
3
3
  from typing import List, Dict, Any
4
- from datetime import datetime, date
4
+ from datetime import datetime, date, time
5
5
  from collections import defaultdict
6
+ from ics import Calendar, Event
7
+ from zoneinfo import ZoneInfo
6
8
 
7
- names_shorter = defaultdict(lambda: 'Неизвестно')
9
+ from shared_lib.i18n import translator
10
+
11
+ names_shorter = defaultdict(lambda: 'Unknown')
8
12
  to_add = {
9
13
  'Практические (семинарские) занятия': 'Семинар',
10
14
  'Лекции': 'Лекция',
@@ -15,38 +19,79 @@ names_shorter.update(to_add)
15
19
 
16
20
 
17
21
 
18
- def format_schedule(schedule_data: List[Dict[str, Any]], lang: str, entity_name: str, start_date: date) -> str:
22
+ def format_schedule(schedule_data: List[Dict[str, Any]], lang: str, entity_name: str, entity_type: str, start_date: date, is_week_view: bool = False) -> str:
19
23
  """Formats a list of lessons into a readable daily schedule."""
20
24
  if not schedule_data:
21
- return f"🗓 *Расписание для \"{entity_name}\"*\n\nНа запрошенный день занятий нет."
25
+ # Different message for single day vs week
26
+ no_lessons_key = "schedule_no_lessons_week" if is_week_view else "schedule_no_lessons_day"
27
+ return f"🗓 *Расписание для \"{entity_name}\"*\n\n{translator.gettext(lang, no_lessons_key)}"
22
28
 
23
29
  # Group lessons by date
24
- days = {}
30
+ days = defaultdict(list)
25
31
  for lesson in schedule_data:
26
- date_str = lesson['date']
27
- if date_str not in days:
28
- days[date_str] = []
29
- days[date_str].append(lesson)
32
+ days[lesson['date']].append(lesson)
30
33
 
31
- # Find the first day with lessons that is on or after the start_date
34
+ formatted_days = []
35
+ # Iterate through sorted dates to build the full schedule string
32
36
  for date_str, lessons in sorted(days.items()):
33
37
  date_obj = datetime.strptime(date_str, "%Y-%m-%d").date()
34
- if date_obj >= start_date:
35
- # Found the first relevant day, format it and return immediately.
36
- day_header = f"🗓 *Расписание на {date_obj.strftime('%d.%m.%Y')} для \"{entity_name}\"*"
37
-
38
- formatted_lessons = []
39
- for lesson in sorted(lessons, key=lambda x: x['beginLesson']):
40
- formatted_lessons.append(
41
- f"`{lesson['beginLesson']} - {lesson['endLesson']} | {lesson['auditorium']}`\n"
42
- f"{lesson['discipline']} | {names_shorter[lesson['kindOfWork']]}\n"
43
- # f"{lesson['kindOfWork']}\n"
44
- # f"{lesson['auditorium']} ({lesson['building']})\n"
45
- f"{lesson['lecturer_title'].replace('_',' ')}\n"
46
- f"{lesson['lecturerEmail']}\n"
47
- )
38
+
39
+ day_header = f"*{date_obj.strftime('%A, %d.%m.%Y')}*"
40
+
41
+ formatted_lessons = []
42
+ for lesson in sorted(lessons, key=lambda x: x['beginLesson']):
43
+ lesson_details = [
44
+ f"`{lesson['beginLesson']} - {lesson['endLesson']}`",
45
+ f"{lesson['discipline']} | {names_shorter[lesson['kindOfWork']]}"
46
+ ]
47
+
48
+ if entity_type == 'group':
49
+ lesson_details.append(f"*{lesson['auditorium']}* | {lesson['lecturer_title'].replace('_',' ')}")
50
+ elif entity_type == 'person': # Lecturer
51
+ lesson_details.append(f"*{lesson['auditorium']}* | {lesson.get('group', 'Группа не указана')}")
52
+ elif entity_type == 'auditorium':
53
+ lesson_details.append(f"{lesson.get('group', 'Группа не указана')} | {lesson['lecturer_title'].replace('_',' ')}")
54
+ else: # Fallback to a generic format
55
+ lesson_details.append(f"*{lesson['auditorium']}* | {lesson['lecturer_title'].replace('_',' ')}")
56
+
57
+ formatted_lessons.append("\n".join(lesson_details))
58
+
59
+ formatted_days.append(f"{day_header}\n" + "\n\n".join(formatted_lessons))
60
+
61
+ main_header = f"🗓 *Расписание для \"{entity_name}\"*"
62
+ return f"{main_header}\n\n" + "\n\n---\n\n".join(formatted_days)
63
+
64
+ def generate_ical_from_schedule(schedule_data: List[Dict[str, Any]], entity_name: str) -> str:
65
+ """
66
+ Generates an iCalendar (.ics) file string from schedule data.
67
+ """
68
+ cal = Calendar()
69
+ moscow_tz = ZoneInfo("Europe/Moscow")
70
+
71
+ if not schedule_data:
72
+ return cal.serialize()
73
+
74
+ for lesson in schedule_data:
75
+ try:
76
+ event = Event()
77
+ event.name = f"{lesson['discipline']} ({names_shorter[lesson['kindOfWork']]})"
48
78
 
49
- return f"{day_header}\n" + "\n\n".join(formatted_lessons)
79
+ lesson_date = datetime.strptime(lesson['date'], "%Y-%m-%d").date()
80
+ start_time = time.fromisoformat(lesson['beginLesson'])
81
+ end_time = time.fromisoformat(lesson['endLesson'])
82
+
83
+ event.begin = datetime.combine(lesson_date, start_time, tzinfo=moscow_tz)
84
+ event.end = datetime.combine(lesson_date, end_time, tzinfo=moscow_tz)
50
85
 
51
- # If no lessons were found in the entire fetched range
52
- return f"🗓 *Расписание для \"{entity_name}\"*\n\nВ ближайшую неделю занятий не найдено."
86
+ event.location = f"{lesson['auditorium']}, {lesson['building']}"
87
+
88
+ description_parts = [f"Преподаватель: {lesson['lecturer_title'].replace('_',' ')}"]
89
+ if 'group' in lesson: description_parts.append(f"Группа: {lesson['group']}")
90
+ event.description = "\n".join(description_parts)
91
+
92
+ cal.events.add(event)
93
+ except (ValueError, KeyError) as e:
94
+ logging.warning(f"Skipping lesson due to parsing error: {e}. Lesson data: {lesson}")
95
+ continue
96
+
97
+ return cal.serialize()