Module edupage_api.timetables

Classes

class Lesson (period: Optional[int], start_time: datetime.time, end_time: datetime.time, duration: int, subject: Optional[Subject], classes: Optional[List[Class]], groups: Optional[List[str]], teachers: Optional[List[EduTeacher]], classrooms: Optional[List[Classroom]], curriculum: Optional[str], online_lesson_link: Optional[str], is_cancelled: bool, is_event: bool)

Lesson(period: Optional[int], start_time: datetime.time, end_time: datetime.time, duration: int, subject: Optional[edupage_api.subjects.Subject], classes: Optional[List[edupage_api.classes.Class]], groups: Optional[List[str]], teachers: Optional[List[edupage_api.people.EduTeacher]], classrooms: Optional[List[edupage_api.classrooms.Classroom]], curriculum: Optional[str], online_lesson_link: Optional[str], is_cancelled: bool, is_event: bool)

Expand source code
@dataclass
class Lesson:
    period: Optional[int]
    start_time: time
    end_time: time
    duration: int
    subject: Optional[Subject]
    classes: Optional[List[Class]]
    groups: Optional[List[str]]
    teachers: Optional[List[EduTeacher]]
    classrooms: Optional[List[Classroom]]
    curriculum: Optional[str]
    online_lesson_link: Optional[str]
    is_cancelled: bool
    is_event: bool

    def is_online_lesson(self) -> bool:
        return self.online_lesson_link is not None

    @ModuleHelper.online_lesson
    def sign_into_lesson(self, edupage: EdupageModule):
        request_url = f"https://{edupage.subdomain}.edupage.org/dashboard/eb.php"

        response = edupage.session.get(request_url)

        gse_hash = response.content.decode().split("gsechash=")[1].split('"')[1]

        request_url = f"https://{edupage.subdomain}.edupage.org/dashboard/server/onlinelesson.js?__func=getOnlineLessonOpenUrl"
        today = datetime.today()
        post_data = {
            "__args": [
                None,
                {
                    "click": True,
                    "date": today.strftime("%Y-%m-%d"),
                    "ol_url": self.online_lesson_link,
                    "subjectid": self.subject_id,
                },
            ],
            "__gsh": gse_hash,
        }

        response = edupage.session.post(request_url, json=post_data)
        return json.loads(response.content.decode()).get("reload") is not None

Class variables

var classes : Optional[List[Class]]
var classrooms : Optional[List[Classroom]]
var curriculum : Optional[str]
var duration : int
var end_time : datetime.time
var groups : Optional[List[str]]
var is_cancelled : bool
var is_event : bool
var period : Optional[int]
var start_time : datetime.time
var subject : Optional[Subject]
var teachers : Optional[List[EduTeacher]]

Methods

def is_online_lesson(self) ‑> bool
def sign_into_lesson(self, edupage: EdupageModule)
class Timetable (lessons: List[Lesson])

Timetable(lessons: List[edupage_api.timetables.Lesson])

Expand source code
@dataclass
class Timetable:
    lessons: List[Lesson]

    def __iter__(self):
        return iter(self.lessons)

    def get_lesson_at_time(self, time: time):
        for lesson in self.lessons:
            if time >= lesson.start_time and time <= lesson.end_time:
                return lesson

    def get_next_lesson_at_time(self, time: time):
        for lesson in self.lessons:
            if time < lesson.start_time:
                return lesson

    def get_next_online_lesson_at_time(self, time: time):
        for lesson in self.lessons:
            if time < lesson.start_time and lesson.is_online_lesson():
                return lesson

    def get_first_lesson(self):
        if len(self.lessons) > 0:
            return self.lessons[0]

    def get_last_lesson(self):
        if len(self.lessons) > 0:
            return self.lessons[-1]

Class variables

var lessons : List[Lesson]

Methods

def get_first_lesson(self)
def get_last_lesson(self)
def get_lesson_at_time(self, time: datetime.time)
def get_next_lesson_at_time(self, time: datetime.time)
def get_next_online_lesson_at_time(self, time: datetime.time)
class Timetables (edupage: EdupageModule)
Expand source code
class Timetables(Module):
    def get_school_year(self):
        dp = self.edupage.data.get("dp")

        if dp is None:
            raise MissingDataException("You have no dp! (try logging in again)")

        return dp.get("year")

    def __get_timetable_data(self, target_id: int, table: str, date: date):
        request_data = {
            "__args": [
                None,
                {
                    "year": self.get_school_year(),
                    "datefrom": date.strftime("%Y-%m-%d"),
                    "dateto": date.strftime("%Y-%m-%d"),
                    "table": table,
                    "id": str(target_id),
                    "showColors": True,
                    "showIgroupsInClasses": True,
                    "showOrig": True,
                    "log_module": "CurrentTTView",
                },
            ],
            "__gsh": self.edupage.gsec_hash,
        }

        request_url = (
            f"https://{self.edupage.subdomain}.edupage.org/"
            "timetable/server/currenttt.js?__func=curentttGetData"
        )

        timetable_data = self.edupage.session.post(
            request_url, json=request_data
        ).content.decode()
        timetable_data = json.loads(timetable_data)

        timetable_data_response = timetable_data.get("r")
        timetable_data_error = timetable_data_response.get("error")

        if timetable_data_response is None:
            raise MissingDataException("The server returned an incorrect response.")

        if timetable_data_error is not None:
            raise RequestError(
                f"Edupage returned an error response: {timetable_data_error}"
            )

        return timetable_data_response.get("ttitems")

    def __get_date_plan(self, date: date):
        csrf_request_url = (
            f"https://{self.edupage.subdomain}.edupage.org/dashboard/eb.php?mode=ttday"
        )
        csrf_response = self.edupage.session.get(csrf_request_url)

        gpid = csrf_response.text.split("gpid=")[1].split("&")[0]
        gsh = csrf_response.text.split("gsh=")[1].split('"')[0]

        next_gpid = int(gpid) + 1

        url = f"https://{self.edupage.subdomain}.edupage.org/gcall"
        curriculum_response = self.edupage.session.post(
            url,
            data=RequestUtil.encode_form_data(
                {
                    "gpid": str(next_gpid),
                    "gsh": gsh,
                    "action": "loadData",
                    "user": self.edupage.get_user_id(),
                    "changes": "{}",
                    "date": date.strftime("%Y-%m-%d"),
                    "dateto": date.strftime("%Y-%m-%d"),
                    "_LJSL": "4096",
                }
            ),
            headers={"Content-Type": "application/x-www-form-urlencoded"},
        )

        response_start = self.edupage.get_user_id() + '",'
        response_end = ",["

        curriculum_json = curriculum_response.text.split(response_start)[1].rsplit(
            response_end, 1
        )[0]

        data = json.loads(curriculum_json)

        dates = data.get("dates")
        date_plans = dates.get(date.strftime("%Y-%m-%d"))
        if date_plans is None:
            raise MissingDataException()

        return date_plans.get("plan")

    def __parse_timetable(self, plan):
        lessons = []
        for lesson in plan:
            if "header" in lesson and (
                not lesson.get("header")
                or lesson.get("header")[0].get("cmd") == "addlesson_t"
            ):
                continue

            period_str = lesson.get("uniperiod")
            period = int(period_str) if period_str.isdigit() else None

            start_time_str = lesson.get("starttime").replace("24:00", "23:59")
            start_time = (
                time(*map(int, start_time_str.split(":"))) if start_time_str else None
            )

            end_time_str = lesson.get("endtime").replace("24:00", "23:59")
            end_time = (
                time(*map(int, end_time_str.split(":"))) if end_time_str else None
            )

            duration = lesson.get("durationperiods", 1)

            subject_id = lesson.get("subjectid")
            subject = Subjects(self.edupage).get_subject(subject_id)

            classes = [
                edu_class
                for class_id in lesson.get("classids", [])
                if (edu_class := Classes(self.edupage).get_class(class_id)) is not None
            ]

            groups = [group for group in lesson.get("groupnames") if group != ""]

            teachers = [
                teacher
                for teacher_id in lesson.get("teacherids", [])
                if (teacher := People(self.edupage).get_teacher(teacher_id)) is not None
            ]

            classrooms = [
                classroom
                for classroom_id in lesson.get("classroomids", [])
                if (classroom := Classrooms(self.edupage).get_classroom(classroom_id))
                is not None
            ]

            is_cancelled = (
                lesson.get("removed")
                or lesson.get("type") == "absent"
                or lesson.get("type") == ""
            )
            is_event = (
                lesson.get("type") == "event"
                or lesson.get("type") == "out"
                or lesson.get("main")
            ) or False

            online_lesson_link = lesson.get("ol_url")

            try:
                curriculum = lesson.get("flags", {}).get("dp0", {}).get(
                    "note_wd"
                ) or lesson.get("flags", {}).get("event", {}).get("name")
            except AttributeError:
                curriculum = None

            lesson_object = Lesson(
                period,
                start_time,
                end_time,
                duration,
                subject,
                classes or None,
                groups or None,
                teachers or None,
                classrooms or None,
                curriculum or None,
                online_lesson_link,
                is_cancelled,
                is_event,
            )
            lessons.append(lesson_object)

        return Timetable(lessons)

    @ModuleHelper.logged_in
    def get_my_timetable(self, date: date) -> Optional[Timetable]:
        plan = self.__get_date_plan(date)
        return self.__parse_timetable(plan)

    @ModuleHelper.logged_in
    def get_timetable(
        self,
        target: Union[EduTeacher, EduStudent, Class, Classroom],
        date: date,
    ) -> Optional[Timetable]:

        lookup = {
            EduTeacher: ("teachers", "person_id"),
            EduStudent: ("students", "person_id"),
            Class: ("classes", "class_id"),
            Classroom: ("classrooms", "classroom_id"),
        }

        table, target_id_attr = lookup.get(type(target))
        target_id = getattr(target, target_id_attr)

        try:
            timetable_data = self.__get_timetable_data(target_id, table, date)
        except RequestError as e:
            if "insuficient" in str(e).lower():
                raise InsufficientPermissionsException(f"Missing permissions: {str(e)}")
        except Exception as e:
            raise UnknownServerError(f"There was an unknown error: {str(e)}")

        return self.__parse_timetable(timetable_data)

Ancestors

Methods

def get_my_timetable(self, date: datetime.date) ‑> Optional[Timetable]
def get_school_year(self)
def get_timetable(self, target: Union[EduTeacherEduStudentClassClassroom], date: datetime.date) ‑> Optional[Timetable]