-
Notifications
You must be signed in to change notification settings - Fork 0
/
substitution.py
150 lines (119 loc) · 4.55 KB
/
substitution.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
"""This script includes classes and functions about the 'Vertretungsplan' page."""
import re
from datetime import datetime
from attrs import define, field
from selectolax.parser import HTMLParser
from ..constants import LOGGER, URL
from ..exceptions import CriticalElementWasNotFoundError
from ..helpers.html_logger import HTMLLogger
from ..helpers.request import Request
@define
class SubstitutionPlan:
"""The substitution plan page in a data type.
Parameters
----------
date : datetime.datetime
Date of the substitution plan.
substitutions : list[Substitution]
The individual substitutions.
info : str
``info`` is the box with the title "Allgemein" that exists sometimes.
"""
@define
class Substitution:
"""The individual substitution data (table row).
Parameters
----------
substitute : str
Often abbreviation of the substitute.
teacher : str
Often abbreviation of the teacher.
hours : str
When is it in school hours.
class_name : str
Name of the classes.
subject : str
The subject is rarely given.
room : str
Room of the substitution.
notice : str
More info about the substitution.
"""
substitute: field(type=str)
teacher: field(type=str)
hours: field(type=str)
class_name: field(type=str)
subject: field(type=str)
room: field(type=str)
notice: field(type=str)
date: field(type=datetime)
info: field(type=str)
substitutions: field(factory=list, type=list[Substitution])
def _get_substitution_info() -> dict[str, str]:
"""Return the notice (if available) and date of the substitution plan.
Returns
-------
dict[str, str]
The data
"""
page = Request.get(URL.substitution_plan)
html = HTMLParser(page.text)
# TODO
notice_element = html.css_first(
".infos > tbody:nth-child(1) > tr:nth-child(2) > td:nth-child(1)"
)
try:
# Remove whitespace at the beginning and end.
notice = re.sub(r"^[\n][ \t]+|[\n][ \t]+$", "", notice_element.text())
except AttributeError:
notice = None
date_element = html.css_first("div#content div.panel-body h3")
try:
date = re.findall(r"(\d\d\.\d\d\.\d\d\d\d)", date_element.text())[0]
except AttributeError as err:
HTMLLogger.log_missing_element(
html.html, "get_substitution_info()", "/", "date"
)
msg = "Critical date element was not found, something is definitely wrong! Please file a bug with the html_logs.txt file."
raise CriticalElementWasNotFoundError(msg) from err
LOGGER.info(f"Substitution info: Successfully got info. Notice is {bool(notice)}.")
return {"notice": notice, "date": date}
def _get_substitutions() -> SubstitutionPlan:
"""Return the whole substitution plan of the current day.
Returns
-------
SubstitutionPlan
"""
try:
info = _get_substitution_info()
except CriticalElementWasNotFoundError as err:
raise err
# Script: /module/vertretungsplan/js/my.js
# `ganzerPlan` = If you want the entire plan or only stuff for you.
# Recommended is the entire plan because the creators of the
# plan can mess up.
# `tag` = The day of the plan, often there are plans for the current and next day.
# `kuerzel`: `Abbreviation of substitution` = Which substitution should be shown?
### `a` function param:
# `a`: `my` = Does nothing, "standard" function.
# `protokoll` = Returns: {"status":-1,"statustext":"Kein Zugriff!"}, used to create substitution plans.
data = {"ganzerPlan": "true", "tag": info["date"]}
# Lanis also adds the param `a`: `my` but it does nothing.
substitution_raw_data = Request.post(URL.substitution_plan, data=data)
plan = SubstitutionPlan(
datetime.strptime(info["date"], "%d.%m.%Y").date(), info["notice"], []
)
# Map JSON to Substitution.
for data in substitution_raw_data.json():
substitution_data = SubstitutionPlan.Substitution(
substitute=data["Vertreter"],
teacher=data["Lehrer"],
hours=data["Stunde"],
class_name=data["Klasse"],
subject=data["Fach"],
room=data["Raum"],
notice=data["Hinweis"] if data["Hinweis"] else None,
)
plan.substitutions.append(substitution_data)
LOGGER.info("Get substitution plan: Success.")
return plan