Compare commits

..

8 Commits

8 changed files with 53 additions and 13 deletions

View File

@ -14,7 +14,7 @@ PRETTY = PrettyLogger(LOGGER)
try: try:
import keyring import keyring
except ImportError: except ImportError:
PRETTY.warning("Keyring module not found, KeyringAuthenticator won't work!") pass
class TfaAuthenticator: class TfaAuthenticator:

View File

@ -74,6 +74,8 @@ class KitShibbolethAuthenticator(IliasAuthenticator):
form = soup.find("form", {"class": "full content", "method": "post"}) form = soup.find("form", {"class": "full content", "method": "post"})
action = form["action"] action = form["action"]
csrf_token = form.find("input", {"name": "csrf_token"})["value"]
# Equivalent: Enter credentials in # Equivalent: Enter credentials in
# https://idp.scc.kit.edu/idp/profile/SAML2/Redirect/SSO # https://idp.scc.kit.edu/idp/profile/SAML2/Redirect/SSO
LOGGER.debug("Attempt to log in to Shibboleth using credentials") LOGGER.debug("Attempt to log in to Shibboleth using credentials")
@ -82,6 +84,7 @@ class KitShibbolethAuthenticator(IliasAuthenticator):
"_eventId_proceed": "", "_eventId_proceed": "",
"j_username": self._auth.username, "j_username": self._auth.username,
"j_password": self._auth.password, "j_password": self._auth.password,
"csrf_token": csrf_token
} }
soup = soupify(sess.post(url, data=data)) soup = soupify(sess.post(url, data=data))

View File

@ -40,6 +40,7 @@ class IliasElementType(Enum):
REGULAR_FILE = "REGULAR_FILE" REGULAR_FILE = "REGULAR_FILE"
VIDEO_FILE = "VIDEO_FILE" VIDEO_FILE = "VIDEO_FILE"
FORUM = "FORUM" FORUM = "FORUM"
MEETING = "MEETING"
EXTERNAL_LINK = "EXTERNAL_LINK" EXTERNAL_LINK = "EXTERNAL_LINK"
def is_folder(self) -> bool: def is_folder(self) -> bool:
@ -241,6 +242,8 @@ class IliasCrawler:
entries_to_process += self._crawl_video_directory(entry.path, url) entries_to_process += self._crawl_video_directory(entry.path, url)
continue continue
PRETTY.warning(f"Unknown type: {entry.entry_type}!")
return result return result
def _crawl_folder(self, folder_path: Path, url: str) -> List[IliasCrawlerEntry]: def _crawl_folder(self, folder_path: Path, url: str) -> List[IliasCrawlerEntry]:
@ -269,6 +272,25 @@ class IliasCrawler:
if element_type == IliasElementType.REGULAR_FILE: if element_type == IliasElementType.REGULAR_FILE:
result += self._crawl_file(folder_path, link, abs_url) result += self._crawl_file(folder_path, link, abs_url)
elif element_type == IliasElementType.MEETING:
meeting_name = str(element_path.name)
date_portion_str = meeting_name.split(" - ")[0]
date_portion = demangle_date(date_portion_str)
if not date_portion:
result += [IliasCrawlerEntry(element_path, abs_url, element_type, None)]
continue
rest_of_name = meeting_name
if rest_of_name.startswith(date_portion_str):
rest_of_name = rest_of_name[len(date_portion_str):]
new_name = datetime.datetime.strftime(date_portion, "%Y-%m-%d, %H:%M") \
+ rest_of_name
new_path = Path(folder_path, _sanitize_path_name(new_name))
result += [
IliasCrawlerEntry(new_path, abs_url, IliasElementType.REGULAR_FOLDER, None)
]
elif element_type is not None: elif element_type is not None:
result += [IliasCrawlerEntry(element_path, abs_url, element_type, None)] result += [IliasCrawlerEntry(element_path, abs_url, element_type, None)]
else: else:
@ -320,6 +342,8 @@ class IliasCrawler:
""" """
# pylint: disable=too-many-return-statements # pylint: disable=too-many-return-statements
found_parent: Optional[bs4.Tag] = None
# We look for the outer div of our inner link, to find information around it # We look for the outer div of our inner link, to find information around it
# (mostly the icon) # (mostly the icon)
for parent in link_element.parents: for parent in link_element.parents:
@ -350,6 +374,9 @@ class IliasCrawler:
if str(img_tag["src"]).endswith("frm.svg"): if str(img_tag["src"]).endswith("frm.svg"):
return IliasElementType.FORUM return IliasElementType.FORUM
if str(img_tag["src"]).endswith("sess.svg"):
return IliasElementType.MEETING
return IliasElementType.REGULAR_FOLDER return IliasElementType.REGULAR_FOLDER
@staticmethod @staticmethod

View File

@ -122,9 +122,22 @@ class IliasDownloader:
tmp_file = self._tmp_dir.new_path() tmp_file = self._tmp_dir.new_path()
while not self._try_download(info, tmp_file): download_successful = False
LOGGER.info("Retrying download: %r", info) for _ in range(0, 3):
try:
if not self._try_download(info, tmp_file):
LOGGER.info("Re-Authenticating due to download failure: %r", info)
self._authenticator.authenticate(self._session) self._authenticator.authenticate(self._session)
else:
download_successful = True
break
except IOError as e:
PRETTY.warning(f"I/O Error when downloading ({e}). Retrying...",)
LOGGER.info("Retrying download for %s", info.path)
if not download_successful:
PRETTY.error(f"Download of file {info.path} failed too often! Skipping it...")
return
dst_path = self._organizer.accept_file(tmp_file, info.path) dst_path = self._organizer.accept_file(tmp_file, info.path)
if dst_path and info.modification_date: if dst_path and info.modification_date:

View File

@ -3,13 +3,10 @@ Contains a few logger utility functions and implementations.
""" """
import logging import logging
from pathlib import Path from typing import Optional
from typing import List, Optional
from rich import print as rich_print
from rich._log_render import LogRender from rich._log_render import LogRender
from rich.console import Console from rich.console import Console
from rich.panel import Panel
from rich.style import Style from rich.style import Style
from rich.text import Text from rich.text import Text
from rich.theme import Theme from rich.theme import Theme

View File

@ -116,7 +116,7 @@ class Organizer(Location):
if self._is_marked(dst): if self._is_marked(dst):
PRETTY.warning(f"File {str(dst_absolute)!r} was already written!") PRETTY.warning(f"File {str(dst_absolute)!r} was already written!")
conflict = ConflictType.MARKED_FILE_OVERWRITTEN conflict = ConflictType.MARKED_FILE_OVERWRITTEN
if self._resolve_conflict(f"Overwrite file?", dst_absolute, conflict, default=False): if self._resolve_conflict("Overwrite file?", dst_absolute, conflict, default=False):
PRETTY.ignored_file(dst_absolute, "file was written previously") PRETTY.ignored_file(dst_absolute, "file was written previously")
return None return None

View File

@ -37,7 +37,7 @@ Ensure that you have at least Python 3.8 installed.
To install PFERD or update your installation to the latest version, run this To install PFERD or update your installation to the latest version, run this
wherever you want to install or have already installed PFERD: wherever you want to install or have already installed PFERD:
``` ```
$ pip install git+https://github.com/Garmelon/PFERD@v2.5.0 $ pip install git+https://github.com/Garmelon/PFERD@v2.5.3
``` ```
The use of [venv] is recommended. The use of [venv] is recommended.
@ -60,8 +60,8 @@ $ mkdir Vorlesungen
$ cd Vorlesungen $ cd Vorlesungen
$ python3 -m venv .venv $ python3 -m venv .venv
$ .venv/bin/activate $ .venv/bin/activate
$ pip install git+https://github.com/Garmelon/PFERD@v2.5.0 $ pip install git+https://github.com/Garmelon/PFERD@v2.5.3
$ curl -O https://raw.githubusercontent.com/Garmelon/PFERD/v2.5.0/example_config.py $ curl -O https://raw.githubusercontent.com/Garmelon/PFERD/v2.5.3/example_config.py
$ python3 example_config.py $ python3 example_config.py
$ deactivate $ deactivate
``` ```

View File

@ -2,7 +2,7 @@ from setuptools import find_packages, setup
setup( setup(
name="PFERD", name="PFERD",
version="2.5.0", version="2.5.3",
packages=find_packages(), packages=find_packages(),
install_requires=[ install_requires=[
"requests>=2.21.0", "requests>=2.21.0",