Files
airflow-coolify/scripts/edoxid_calendar_database.py
Power BI Dev e0a6efd204 fix python 3.8 compat for edoxid calendar sync
apache/airflow:2.7.1 base image ships Python 3.8, which doesn't have
zoneinfo (3.9+) and can't evaluate `X | Y` / list[X] type hints at
runtime (3.10+). Add `from __future__ import annotations` everywhere
and swap zoneinfo -> pytz (already a dependency in this repo).
2026-07-27 22:10:10 +07:00

96 lines
3.5 KiB
Python

from __future__ import annotations
from datetime import date, datetime
import pymysql
import pymysql.cursors
from scripts.edoxid_calendar_config import DbConfig
class Database:
"""Koneksi READ-ONLY ke doxid2022 (DB aplikasi eDOXID) pakai user
`calendar_sync_ro` yang cuma punya grant SELECT ke submissions/verificators/users.
Tidak pernah menulis apa pun ke DB ini."""
def __init__(self, config: DbConfig):
self._conn = pymysql.connect(
host=config.host,
port=config.port,
user=config.username,
password=config.password,
database=config.database,
cursorclass=pymysql.cursors.DictCursor,
autocommit=True,
)
def close(self) -> None:
self._conn.close()
def get_scheduled_submissions(self, min_date: str = "today") -> list[dict]:
"""Submission yang sudah punya jadwal sidang (schedule IS NOT NULL),
dibatasi >= min_date supaya tidak menyapu semua histori lama.
min_date: 'today' atau string 'YYYY-MM-DD'.
"""
cutoff = date.today() if min_date == "today" else datetime.strptime(min_date, "%Y-%m-%d").date()
with self._conn.cursor() as cur:
cur.execute(
"""
SELECT s.id, s.schedule, s.room, s.title, s.type_id,
u.name AS student_name, u.email AS student_email, u.unique_id AS student_nim
FROM submissions s
JOIN users u ON u.id = s.student_id
WHERE s.schedule IS NOT NULL
AND s.schedule >= %s
""",
(cutoff,),
)
submissions = cur.fetchall()
if not submissions:
return []
ids = [s["id"] for s in submissions]
placeholders = ",".join(["%s"] * len(ids))
# Diurutkan v.id supaya "Pembimbing 1/2" & "Penguji 1/2" konsisten
# dengan urutan input aslinya.
with self._conn.cursor() as cur:
cur.execute(
f"""
SELECT v.submission_id, v.type, u.name, u.email
FROM verificators v
JOIN users u ON u.id = v.user_id
WHERE v.submission_id IN ({placeholders})
AND v.type IN ('Pembimbing', 'Penguji')
AND u.email IS NOT NULL AND u.email != ''
ORDER BY v.id
""",
ids,
)
verificator_rows = cur.fetchall()
verificators_by_submission: dict[int, list[dict]] = {}
for row in verificator_rows:
verificators_by_submission.setdefault(row["submission_id"], []).append(
{"type": row["type"], "name": row["name"], "email": row["email"]}
)
for submission in submissions:
submission["verificators"] = verificators_by_submission.get(submission["id"], [])
return submissions
def get_ids_with_active_schedule(self) -> set[int]:
"""ID semua submission yang MASIH punya schedule (tanpa filter tanggal).
Dipakai KHUSUS untuk deteksi orphan/cancelled — supaya sidang yang
tanggalnya sudah lewat (tapi memang belum dibatalkan) tidak salah
dianggap "cancelled" dan event Calendar-nya ikut terhapus, gara-gara
filter min_date di get_scheduled_submissions() menyisihkannya.
"""
with self._conn.cursor() as cur:
cur.execute("SELECT id FROM submissions WHERE schedule IS NOT NULL")
return {row["id"] for row in cur.fetchall()}