Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 28 additions & 12 deletions bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ def _parse_channel_role_map(env_val: str) -> Dict[int, int]:
2: int(os.getenv("GRADE2_ROLE_ID", "1334466986419163187")),
}

STUDENT_COUNCIL_CHANNEL_ID = int(
os.getenv("STUDENT_COUNCIL_CHANNEL_ID", "1542518682880839680")
SUBMISSION_NOTIFY_CHANNEL_IDS: List[int] = _parse_id_list(
os.getenv(
"SUBMISSION_NOTIFY_CHANNEL_IDS",
"1542518682880839680,1490575679786455111",
)
)

POLL_INTERVAL = int(os.getenv("POLL_INTERVAL", "30"))
Expand All @@ -81,6 +84,7 @@ def _parse_channel_role_map(env_val: str) -> Dict[int, int]:
EMBED_COLOR = 0xE8B84B
FOOTER_TEXT = "GSM 릴스 봇"

# 신청 시작 시각 (한국 시간 기준 오후 4시 20분)
KST = timezone(timedelta(hours=9))
OPEN_HOUR = int(os.getenv("OPEN_HOUR", "16"))
OPEN_MINUTE = int(os.getenv("OPEN_MINUTE", "20"))
Expand Down Expand Up @@ -147,6 +151,11 @@ def _make_progress_bar(enrolled: int, capacity: int, width: int = 10) -> str:


def _compute_open_at_iso(approved_at_utc: datetime) -> str:
"""강연 승인 시각(approved_at) 기준으로 신청 시작 시각을 계산해 UTC ISO 문자열로 반환한다.

규칙: 승인 시각이 그날 오후 4시 20분(KST) 이전이면 그날 4시 20분에 시작하고,
이미 지났으면 다음날 4시 20분으로 넘어간다.
"""
approved_kst = approved_at_utc.astimezone(KST)
open_kst = approved_kst.replace(
hour=OPEN_HOUR, minute=OPEN_MINUTE, second=0, microsecond=0
Expand Down Expand Up @@ -306,6 +315,7 @@ async def send_to_all_notify_channels(
async def send_confirmed_notification(
lecture: Dict[str, Any], message: str, embed: discord.Embed
) -> None:
"""개설 확정 알림 전용 발송 함수. 멘션 없이 메시지만 보낸다."""
channel_ids = set(STATIC_NOTIFY_CHANNEL_ROLE_MAP) | set(
GRADE_AWARE_NOTIFY_CHANNEL_IDS
)
Expand All @@ -324,16 +334,18 @@ async def send_confirmed_notification(


async def send_to_student_council(embed: discord.Embed) -> None:
channel = bot.get_channel(STUDENT_COUNCIL_CHANNEL_ID)
if channel:
try:
await channel.send(embed=embed)
except Exception as e:
print(f"[전송 에러] 학생회 채널로 메시지 전송 실패: {e}")
else:
print(
f"[채널 없음] {STUDENT_COUNCIL_CHANNEL_ID} — 봇이 이 채널을 못 찾음(권한/캐시 확인 필요)"
)
"""신청서 접수 알림 채널들로 멘션 없이 임베드만 전송한다."""
for channel_id in SUBMISSION_NOTIFY_CHANNEL_IDS:
channel = bot.get_channel(channel_id)
if channel:
try:
await channel.send(embed=embed)
except Exception as e:
print(f"[전송 에러] 채널 {channel_id}로 메시지 전송 실패: {e}")
else:
print(
f"[채널 없음] {channel_id} — 봇이 이 채널을 못 찾음(권한/캐시 확인 필요)"
)


async def _process_due_open_notifications(lectures: List[Dict[str, Any]]) -> None:
Expand All @@ -345,6 +357,7 @@ async def _process_due_open_notifications(lectures: List[Dict[str, Any]]) -> Non
lectures_by_id = {str(lec["id"]): lec for lec in lectures}

for due in due_list:
# 먼저 notified 처리해서, 강연을 못 찾아도 다음 폴링에서 또 시도하지 않도록 한다.
mark_open_notified(due["lecture_id"])

lecture = lectures_by_id.get(due["lecture_id"])
Expand Down Expand Up @@ -445,6 +458,9 @@ async def before_poll() -> None:

if lecture.get("status") == "OPEN":
mark_notified(lecture_id, "new", lecture["title"])
# 봇 재시작 시점에 이미 존재하던 강연은 신청 시작 알림 대상에서 제외한다.
# (주의: DB가 초기화된 상태로 재시작되면, 실제로 안 나갔던 알림도
# 이미 보낸 것으로 처리될 수 있음 - 근본 해결은 DB 영구 저장 설정)
schedule_open_notification(
lecture_id, now_iso, lecture["title"], notified=1
)
Expand Down
Loading