diff --git a/.gitignore b/.gitignore index d752223..53685d2 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ build/* edupage_api.egg-info edupage_api.egg-info/* test.py +tests USERNAME PASSWORD \ No newline at end of file diff --git a/README.md b/README.md index fceca22..40ebf7d 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,13 @@ except LoginDataParsingException: ``` # Documentation -The docs are available [here](https://edupage-api.hrabcak.eu/) +The docs are available [here](https://ivanhrabcak.github.io/edupage-api/) # I have a problem or an idea! - If you find any issue with this code, or it doesn't work please, let us know by opening an [issue](https://github.com/ivanhrabcak/edupage-api/issues/new/choose)! - Feel free to suggest any other features! Just open an [issue with the _Feature Request_ tag](https://github.com/ivanhrabcak/edupage-api/issues/new?labels=feature+request&template=feature_request.md&title=%5BFeature+request%5D+). - If you, even better, have fixed the issue, added a new feature, or made something work better, please, open a [pull request](https://github.com/ivanhrabcak/edupage-api/compare)! + +# Discord +https://discord.gg/fg6zBu9ZAn diff --git a/docs/messages.html b/docs/messages.html index 251c1c7..de28c82 100644 --- a/docs/messages.html +++ b/docs/messages.html @@ -72,7 +72,7 @@
edupage_api.messages
edupage_api.people
+def get_id(self)
+
def get_id(self):
+ if not self.__student_only:
+ return super().get_id()
+ else:
+ return super().get_id().replace("Student", "StudentOnly")
+
+def set_student_only(self, student_only: bool)
+
def set_student_only(self, student_only: bool):
+ self.__student_only = student_only
+
class EduStudentSkeleton
@@ -968,12 +1022,14 @@ EduStudent
-
+
-
diff --git a/edupage_api/__init__.py b/edupage_api/__init__.py
index 7515b68..23ed3d2 100644
--- a/edupage_api/__init__.py
+++ b/edupage_api/__init__.py
@@ -20,6 +20,7 @@
from edupage_api.substitution import Substitution, TimetableChange
from edupage_api.timeline import TimelineEvent, TimelineEvents
from edupage_api.timetables import Timetable, Timetables
+from edupage_api.parent import Parent
class Edupage(EdupageModule):
@@ -36,6 +37,7 @@ def __init__(self, request_timeout=5):
self.is_logged_in = False
self.subdomain = None
self.gsec_hash = None
+ self.username = None
self.session = requests.session()
self.session.request = functools.partial(self.session.request, timeout=request_timeout)
@@ -234,6 +236,21 @@ def get_next_ringing_time(self, date_time: datetime) -> RingingTime:
RingingTime: The type (break or lesson) and time of the next ringing.
"""
return RingingTimes(self).get_next_ringing_time(date_time)
+
+ def switch_to_child(self, child: Union[EduAccount, int]):
+ """Switch to an account of a child - can only be used on parent accounts
+
+ Args:
+ child (EduAccount | int): The account or `person_id` of the child you want to switch to
+
+ Note: When you switch to a child account, all other methods will return data
+ as if you were logged in as `child`
+ """
+ Parent(self).switch_to_child(child)
+
+ def switch_to_parent(self):
+ """Switches back to your parent account - can only be used on parent accounts"""
+ Parent(self).switch_to_parent()
@classmethod
def from_session_id(cls, session_id: str, subdomain: str):
@@ -250,4 +267,4 @@ def from_session_id(cls, session_id: str, subdomain: str):
Login(instance).reload_data(subdomain, session_id)
- return instance
+ return instance
\ No newline at end of file
diff --git a/edupage_api/exceptions.py b/edupage_api/exceptions.py
index 47b84c6..f9ccf1c 100644
--- a/edupage_api/exceptions.py
+++ b/edupage_api/exceptions.py
@@ -48,5 +48,14 @@ class InvalidLunchData(Exception):
class Base64DecodeError(Exception):
pass
-class InvalidRecipientsExceiption(Exception):
+class InvalidRecipientsException(Exception):
+ pass
+
+class InvalidChildException(Exception):
+ pass
+
+class UnknownServerError(Exception):
+ pass
+
+class NotParentException(Exception):
pass
\ No newline at end of file
diff --git a/edupage_api/login.py b/edupage_api/login.py
index c0ac3e3..2e90dfd 100644
--- a/edupage_api/login.py
+++ b/edupage_api/login.py
@@ -44,6 +44,7 @@ def login_auto(self, username: str, password: str):
self.__parse_login_data(data)
self.edupage.subdomain = data.split("-->")[0].split(" ")[-1]
+ self.edupage.username = username
def login(self, username: str, password: str, subdomain: str):
"""Login while specifying the subdomain to log into.
@@ -78,8 +79,9 @@ def login(self, username: str, password: str, subdomain: str):
self.__parse_login_data(response.content.decode())
self.edupage.subdomain = subdomain
+ self.edupage.username = username
- def reload_data(self, subdomain: str, session_id: str):
+ def reload_data(self, subdomain: str, session_id: str, username: str):
request_url = f"https://{subdomain}.edupage.org/user"
self.edupage.session.cookies.set("PHPSESSID", session_id)
@@ -89,5 +91,6 @@ def reload_data(self, subdomain: str, session_id: str):
try:
self.__parse_login_data(response.content.decode())
self.edupage.subdomain = subdomain
+ self.edupage.username = username
except (TypeError, JSONDecodeError) as e:
raise BadCredentialsException(f"Invalid session id: {e}")
diff --git a/edupage_api/messages.py b/edupage_api/messages.py
index 0d60281..512f308 100644
--- a/edupage_api/messages.py
+++ b/edupage_api/messages.py
@@ -1,7 +1,7 @@
from typing import Union
import json
-from edupage_api.exceptions import InvalidRecipientsExceiption, RequestError
+from edupage_api.exceptions import InvalidRecipientsException, RequestError
from edupage_api.module import Module
from edupage_api.people import EduAccount
from edupage_api.compression import RequestData
@@ -12,7 +12,7 @@ def send_message(self, recipients: Union[list[EduAccount], EduAccount, list[str]
if isinstance(recipients, list):
if len(recipients) == 0:
- raise InvalidRecipientsExceiption("The recipients parameter is empty!")
+ raise InvalidRecipientsException("The recipients parameter is empty!")
if type(recipients[0]) == EduAccount:
recipient_string = ";".join([r.get_id() for r in recipients])
@@ -44,6 +44,6 @@ def send_message(self, recipients: Union[list[EduAccount], EduAccount, list[str]
changes = response.get("changes")
if changes == [] or changes is None:
- raise RequestError("Failed to send message (edupage returned an empty 'changes' array)")
+ raise RequestError("Failed to send message (edupage returned an empty 'changes' array) - https://github.com/ivanhrabcak/edupage-api/issues/62")
return int(changes[0].get("timelineid"))
\ No newline at end of file
diff --git a/edupage_api/module.py b/edupage_api/module.py
index 18901d5..4e40676 100644
--- a/edupage_api/module.py
+++ b/edupage_api/module.py
@@ -8,7 +8,7 @@
from edupage_api.exceptions import (MissingDataException,
NotAnOnlineLessonError,
- NotLoggedInException)
+ NotLoggedInException, NotParentException)
class EdupageModule:
@@ -17,6 +17,7 @@ class EdupageModule:
data: dict
is_logged_in: bool
gsec_hash: str
+ username: str
class Module:
@@ -103,3 +104,18 @@ def __impl(self, *method_args, **method_kwargs):
return method(self, *method_args, **method_kwargs)
return __impl
+
+ """
+ Throws NotParentException if someone uses a method with this decorator
+ and is not using a parent account
+ """
+ @staticmethod
+ def is_parent(method):
+ @wraps(method)
+ def __impl(self: Module, *method_args, **method_kwargs):
+ if "Rodic" not in self.edupage.get_user_id():
+ raise NotParentException()
+
+ return method(self, *method_args, **method_kwargs)
+
+ return __impl
diff --git a/edupage_api/parent.py b/edupage_api/parent.py
new file mode 100644
index 0000000..4f5622c
--- /dev/null
+++ b/edupage_api/parent.py
@@ -0,0 +1,34 @@
+from typing import Union
+from edupage_api.module import Module, ModuleHelper
+from edupage_api.people import EduAccount
+from edupage_api.exceptions import InvalidChildException, UnknownServerError
+
+class Parent(Module):
+ @ModuleHelper.logged_in
+ @ModuleHelper.is_parent
+ def switch_to_child(self, child: Union[EduAccount, int]):
+ params = {
+ "studentid": child.person_id if type(child) == EduAccount else child
+ }
+
+ url = f"https://{self.edupage.subdomain}.edupage.org/login/switchchild"
+ response = self.edupage.session.get(url, params=params)
+
+ if response.text != "OK":
+ raise InvalidChildException(f"{response.text}: Invalid child selected! (not your child?)")
+
+ @ModuleHelper.logged_in
+ @ModuleHelper.is_parent
+ def switch_to_parent(self):
+ # variable name is from edupage's code :/
+ rid = f"edupage;{self.edupage.subdomain};{self.edupage.username}"
+
+ params = {
+ "rid": rid
+ }
+
+ url = f"https://{self.edupage.subdomain}.edupage.org/login/edupageChange"
+ response = self.edupage.session.get(url, params=params)
+
+ if "EdupageLoginFailed" in response.url:
+ raise UnknownServerError()
diff --git a/edupage_api/people.py b/edupage_api/people.py
index 0f9070e..32fe417 100644
--- a/edupage_api/people.py
+++ b/edupage_api/people.py
@@ -92,6 +92,17 @@ def __init__(self, person_id: int, name: str, gender: Gender, in_school_since: d
self.class_id = class_id
self.number_in_class = number_in_class
+ self.__student_only = False
+
+ def get_id(self):
+ if not self.__student_only:
+ return super().get_id()
+ else:
+ return super().get_id().replace("Student", "StudentOnly")
+
+ def set_student_only(self, student_only: bool):
+ self.__student_only = student_only
+
@dataclass
class EduStudentSkeleton:
diff --git a/setup.cfg b/setup.cfg
index 34ac1e4..28132ff 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = edupage_api
-version = 0.10.2
+version = 0.10.3
description = A python library for accessing your Edupage account
long_description = file: README.md
long_description_content_type = text/markdown