Refactor project structure and enhance Docker configuration
- Updated `.dockerignore` to exclude test and development artifacts, optimizing the Docker image size. - Refactored `main.py` to delegate execution to `duty_teller.run.main()`, simplifying the entry point. - Introduced a new `duty_teller` package to encapsulate core functionality, improving modularity and organization. - Enhanced `pyproject.toml` to define a script for running the application, streamlining the execution process. - Updated README documentation to reflect changes in project structure and usage instructions. - Improved Alembic environment configuration to utilize the new package structure for database migrations.
This commit is contained in:
86
duty_teller/services/group_duty_pin_service.py
Normal file
86
duty_teller/services/group_duty_pin_service.py
Normal file
@@ -0,0 +1,86 @@
|
||||
"""Group duty pin: current duty message text, next shift end, pin CRUD. All accept session."""
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from duty_teller.db.repository import (
|
||||
get_current_duty,
|
||||
get_next_shift_end,
|
||||
get_group_duty_pin,
|
||||
save_group_duty_pin,
|
||||
delete_group_duty_pin,
|
||||
get_all_group_duty_pin_chat_ids,
|
||||
)
|
||||
|
||||
|
||||
def format_duty_message(duty, user, tz_name: str) -> str:
|
||||
"""Build the text for the pinned message. duty, user may be None."""
|
||||
if duty is None or user is None:
|
||||
return "Сейчас дежурства нет."
|
||||
try:
|
||||
tz = ZoneInfo(tz_name)
|
||||
except Exception:
|
||||
tz = ZoneInfo("Europe/Moscow")
|
||||
tz_name = "Europe/Moscow"
|
||||
start_dt = datetime.fromisoformat(duty.start_at.replace("Z", "+00:00"))
|
||||
end_dt = datetime.fromisoformat(duty.end_at.replace("Z", "+00:00"))
|
||||
start_local = start_dt.astimezone(tz)
|
||||
end_local = end_dt.astimezone(tz)
|
||||
offset_sec = (
|
||||
start_local.utcoffset().total_seconds() if start_local.utcoffset() else 0
|
||||
)
|
||||
sign = "+" if offset_sec >= 0 else "-"
|
||||
h, r = divmod(abs(int(offset_sec)), 3600)
|
||||
m = r // 60
|
||||
tz_hint = f"UTC{sign}{h:d}:{m:02d}, {tz_name}"
|
||||
time_range = (
|
||||
f"{start_local.strftime('%d.%m.%Y %H:%M')} — "
|
||||
f"{end_local.strftime('%d.%m.%Y %H:%M')} ({tz_hint})"
|
||||
)
|
||||
lines = [
|
||||
f"🕐 Дежурство: {time_range}",
|
||||
f"👤 {user.full_name}",
|
||||
]
|
||||
if user.phone:
|
||||
lines.append(f"📞 {user.phone}")
|
||||
if user.username:
|
||||
lines.append(f"@{user.username}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def get_duty_message_text(session: Session, tz_name: str) -> str:
|
||||
"""Get current duty from DB and return formatted message."""
|
||||
now = datetime.now(timezone.utc)
|
||||
result = get_current_duty(session, now)
|
||||
if result is None:
|
||||
return "Сейчас дежурства нет."
|
||||
duty, user = result
|
||||
return format_duty_message(duty, user, tz_name)
|
||||
|
||||
|
||||
def get_next_shift_end_utc(session: Session) -> datetime | None:
|
||||
"""Return next shift end as naive UTC datetime for job scheduling."""
|
||||
return get_next_shift_end(session, datetime.now(timezone.utc))
|
||||
|
||||
|
||||
def save_pin(session: Session, chat_id: int, message_id: int) -> None:
|
||||
"""Save or update the pinned message record for a chat."""
|
||||
save_group_duty_pin(session, chat_id, message_id)
|
||||
|
||||
|
||||
def delete_pin(session: Session, chat_id: int) -> None:
|
||||
"""Remove the pinned message record when the bot leaves the group."""
|
||||
delete_group_duty_pin(session, chat_id)
|
||||
|
||||
|
||||
def get_message_id(session: Session, chat_id: int) -> int | None:
|
||||
"""Return message_id for the pin in this chat, or None."""
|
||||
pin = get_group_duty_pin(session, chat_id)
|
||||
return pin.message_id if pin else None
|
||||
|
||||
|
||||
def get_all_pin_chat_ids(session: Session) -> list[int]:
|
||||
"""Return all chat_ids that have a pinned duty message (for restoring jobs on startup)."""
|
||||
return get_all_group_duty_pin_chat_ids(session)
|
||||
Reference in New Issue
Block a user