Some helper scripts for the day to day work with Ubuntu in WSL2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.6 KiB

from datetime import datetime, timedelta
from typing import Iterable
import click
import pyperclip
import requests
# typing
RawEvent = dict[str : tuple[str | datetime, str]]
Event = dict[str:str]
TableMetaData = dict[str:int]
ICAL_URL = "https://bwsyncandshare.kit.edu/remote.php/dav/public-calendars/69o9HEM9aeZnER8S/?export"
ICS_DATE_FORMAT = "%Y%m%dT%H%M%S"
GERMAN_DATE_FORMAT = "%d.%m.%Y %H:%M"
EARLIEST = datetime.now() - timedelta(days=30 * 3)
LATEST = datetime.now() + timedelta(days=30 * 6)
TABLE_COLUMN_ORDER = ("date", "location", "presenter")
# for mail sending
MAIL_RECIPIENTS = ",".join(
[
"cpistaff@imtek.de",
"andrealayedra@hotmail.com",
"jaro.homburger@biologie.uni-freiburg.de",
"kubilay.acar@continental.com",
"Mario.diehlmann@basf.com",
"paul.fernandez@fmf.uni-freiburg.de",
"sunil.shetty@uniklinik-freiburg.de",
"sofia.genoves94@gmail.com",
"sofia.genoves@yahoo.com.ar",
]
)
MAIL_SUBJECT = "Updated Group Meeting Schedule"
MAIL_START = """
Dear All,
There is an updated group-seminar schedule available:
"""
MAIL_END = """
If (and only if) you can't make it in person, you can join the presentations via zoom: https://uni-freiburg.zoom-x.de/j/62063730956?pwd=6poraREYWvuHkStuYDRvYhO4vhmTbt.1
Meeting-ID: 620 6373 0956
Code: Lm5xaDXPH
You can have a look in our group meeting calendar at: https://bwsyncandshare.kit.edu/apps/calendar/p/69o9HEM9aeZnER8S
Or on our wiki: https://wiki.cpi.imtek.uni-freiburg.de/SeminarSchedule
If you want to add the schedule to your calendar app of choice, please use this subscribe link: https://bwsyncandshare.kit.edu/remote.php/dav/public-calendars/69o9HEM9aeZnER8S/?export
Best,
Holgi
"""
# parsers
def _parse_text(ics_text: str) -> str:
text = ics_text.strip()
return text.replace("\\,", ",")
def _parse_presenter(ics_text: str) -> str:
text = _parse_text(ics_text)
first, sep, last = text.partition(":")
return first if not sep else last.strip()
def _parse_datetime(ics_text: str) -> str:
return datetime.strptime(ics_text.strip(), ICS_DATE_FORMAT)
def _format_datetime(date: datetime) -> str:
return datetime.strftime(date, GERMAN_DATE_FORMAT)
class Transformer:
def __init__(self, name, parser, formater):
self.name = name
self.parser = parser
self.formater = formater
vevent_transformer = {
"DTSTART": Transformer(
"date", parser=_parse_datetime, formater=_format_datetime
),
"LOCATION": Transformer("location", parser=_parse_text, formater=str),
"SUMMARY": Transformer("presenter", parser=_parse_presenter, formater=str),
}
def get_ics(url: str) -> str:
try:
response = requests.get(url)
except IndexError:
msg = f"Could not load calender from url"
raise IOError(msg)
return response.text
def extract_event_info(response: str) -> Iterable[Event]:
events = (
event
for event in _extract_event_info(response)
if EARLIEST < event["date"][0] < LATEST
)
for event in sorted(events, key=lambda d: d["date"]):
yield {key: values[1] for key, values in event.items()}
def _extract_event_info(response: str) -> Iterable[RawEvent]:
handle = (line for line in response.splitlines())
for line in handle:
if line.upper().startswith("BEGIN:VEVENT"):
yield extract_vevent(handle)
def extract_vevent(handle: Iterable[str]) -> RawEvent:
event = {}
for line in handle:
if line.upper().startswith("END:VEVENT"):
break
raw_key, _, raw_value = line.partition(":")
key, _, _ = raw_key.partition(";")
if t := vevent_transformer.get(key):
value = t.parser(raw_value)
text = t.formater(value)
event[t.name] = (value, text)
return event
def create_wiki_table(events: Iterable[Event]) -> str:
table_meta_data = _get_table_meta_data(events)
headers = {key: f"'''{key.capitalize()}'''" for key in TABLE_COLUMN_ORDER}
lines = [
_create_table_line(headers, table_meta_data, sep="||", bracket=True),
]
lines.extend(
_create_table_body(events, table_meta_data, sep="||", bracket=True)
)
return "\n".join(lines)
def create_email_table(events: Iterable[Event]) -> str:
table_meta_data = _get_table_meta_data(events)
lines = _create_table_body(events, table_meta_data, sep="|", bracket=False)
return "\n".join(lines)
def _create_table_body(
events: Iterable[Event], meta: TableMetaData, sep: str, *, bracket: bool
) -> list[str]:
return [_create_table_line(event, meta, sep=sep, bracket=bracket) for event in events]
def _create_table_line(
event: Event, meta: TableMetaData, sep: str, *, bracket: bool
) -> str:
columns = [event[key].ljust(meta[key]) for key in TABLE_COLUMN_ORDER]
inner = f" {sep} ".join(columns)
return f"{sep} {inner} {sep}" if bracket else inner
def _get_table_meta_data(events: Iterable[Event]) -> TableMetaData:
meta = {}
for event in events:
for key, value in event.items():
meta[key] = max(meta.get(key, 0), len(value))
return meta
@click.command()
def group_schedule():
ics_file = get_ics(ICAL_URL)
events = list(extract_event_info(ics_file))
wiki_table = create_wiki_table(events)
email_table = create_email_table(events)
components = [
wiki_table,
"",
"",
"",
MAIL_RECIPIENTS,
"",
MAIL_SUBJECT,
MAIL_START,
email_table,
MAIL_END,
]
text = "\n".join(components)
print(text)
pyperclip.copy(text)