NEW: choose CC, list resources and create TT

This commit is contained in:
Jean-Claude 2022-09-21 17:42:46 +02:00
commit 81907e4c88
Signed by: jeanclaude
GPG Key ID: 8A300F57CBB9F63E
4 changed files with 268 additions and 0 deletions

10
config Normal file
View File

@ -0,0 +1,10 @@
CURRENT_COURSE_LINK_DST: $HOME/CurrentCourse
COURSES_ROOT_DIR: $HOME/Documents/Studies/Eth/Semester7
INFO_FILE: info.yaml
TIMETABLE_FILE: timetable.yaml
CALENDAR: Timetable
SEMESTER: HS22
SEMESTER_START: 2022-09-19
SEMESTER_END: 2022-12-23

4
info.yaml Normal file
View File

@ -0,0 +1,4 @@
title: 'Information Security Lab'
short: 'ISL'
web: 'https://web.ethz.ch'
moodle: 'https://moodle.ethz.ch'

236
main.py Executable file
View File

@ -0,0 +1,236 @@
#!/bin/python3
import argparse
from datetime import datetime
from datetime import timedelta
from datetime import date
import os
import sys
import yaml
from pathlib import Path
from rofi import Rofi
import subprocess
import time
APPNAME = "StudyManager"
CONFIG_HOME = Path(os.environ["XDG_CONFIG_HOME"]) / APPNAME
CONFIG_FILE = CONFIG_HOME / "config"
CACHE_HOME = Path(os.environ["XDG_CACHE_HOME"]) / APPNAME
_config = None
parser = argparse.ArgumentParser(description="Helps to manage your studies.")
parser.add_argument(
"-c", "--chose", action="store_true", help="Chose new Current Course."
)
parser.add_argument(
"-l", "--list", action="store_true", help="List resources of Current Course."
)
parser.add_argument(
"-t",
"--timetable",
action="store_true",
help="Insert (/Update) Current Course's timetable into calendar.",
)
args = vars(parser.parse_args())
def config():
global _config
if _config is None:
if not CONFIG_FILE.exists():
print(f"Config file {CONFIG_FILE} does not exist. Please create it")
sys.exit(1)
with open(CONFIG_FILE, "r") as f:
_config = yaml.safe_load(f)
return _config
def onChose():
dst = Path(os.path.expandvars(config()["CURRENT_COURSE_LINK_DST"]))
coursesRootDir = Path(os.path.expandvars(config()["COURSES_ROOT_DIR"]))
courses = [x.stem for x in coursesRootDir.iterdir() if x.is_dir()]
index, key = Rofi().select("Select Current Course", courses)
# Return on aborted input
if key == -1:
return
src = coursesRootDir / courses[index]
assert src.exists()
try:
os.symlink(src, dst)
except FileExistsError:
os.remove(dst)
os.symlink(src, dst)
def onList():
import pyperclip
currentCourse = Path(os.path.expandvars(config()["CURRENT_COURSE_LINK_DST"]))
assert currentCourse.exists()
infoFile = currentCourse / config()["INFO_FILE"]
if not infoFile.exists():
print(
f"{infoFile} does not exists for course {currentCourse.stem}. There is nothing to list."
)
return
with open(infoFile, "r") as f:
content = yaml.safe_load(f)
contentList = [f"{key}: {value}" for (key, value) in content.items()]
index, key = Rofi().select("Select line to copy", contentList)
# Return on aborted input
if key == -1:
return
selectedVal = list(content.values())[index]
pyperclip.copy(selectedVal)
def onTimetable():
currentCourse = Path(os.path.expandvars(config()["CURRENT_COURSE_LINK_DST"]))
assert currentCourse.exists()
timetableFile = currentCourse / config()["TIMETABLE_FILE"]
infoFile = currentCourse / config()["INFO_FILE"]
if not timetableFile.exists():
print(
f"{timetableFile} does not exists for course {currentCourse.stem}. Not possible to create timetable."
)
return
if not infoFile.exists():
print(
f"{infoFile} does not exists for course {currentCourse.stem}. Not possible to create timetable."
)
return
with open(timetableFile, "r") as f:
timetables = list(yaml.safe_load(f).items())
with open(infoFile, "r") as f:
info = yaml.safe_load(f)
semesterStart = config()["SEMESTER_START"]
semesterEnd = config()["SEMESTER_END"]
semesterEnd = semesterEnd + timedelta(days=1) # khal until is exclusive
days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
calendar = config()["CALENDAR"]
categories = f"{config()['SEMESTER']},{info['short']}" # No space between categories as they are removed anyways
# Check if timetable entry has already been created in the calendar
out = subprocess.run(
["khal", "search", f"--include-calendar={calendar}", categories],
stdout=subprocess.PIPE,
).stdout
if out not in [b"", b"\n"]:
print(f"Possibly colliding timetable entry exists: {out.decode('utf-8')}")
while True:
choice = input("Do you want to delete them? YES/NO\n").lower()
if choice in ["yes", "y"]:
# Handle interactive deletion prompt by khal (https://stackoverflow.com/a/50438585/5464989)
input_buffer = sys.stdin # a buffer to get the user input from
output_buffer = sys.stdout # a buffer to write khal's output to
proc = subprocess.Popen(
[
"khal",
"edit",
"--show-past",
f"--include-calendar{calendar}",
categories,
],
stdin=subprocess.PIPE, # pipe its STDIN so we can write to it
stdout=output_buffer, # pipe directly to the output_buffer
universal_newlines=True,
)
time.sleep(0.5) # give some time for khal to forward its stdout
print(
"", end="", file=output_buffer, flush=True
) # print the input prompt
print(
input_buffer.readline(), file=proc.stdin, flush=True
) # forward the user input
elif choice in ["no", "n"]:
break
else:
print("Please respond with 'yes' or 'no'")
# Iterate over all lectures/exercises and create entry for each of them
cmds = []
for (_, e) in timetables: # Drop key of tuple
title = f"{info['short']} {e['type']}"
location = e["location"]
until = semesterEnd.strftime("%d/%m/%Y")
firstOccurenceDate = semesterStart + timedelta(days=days.index(e["day"]))
startDate = firstOccurenceDate.strftime("%d/%m/%Y")
startTime = e["start"]
endTime = e["end"]
cmd = [
"khal",
"new",
f"--calendar={calendar}",
f"--location='{location}'",
f"--categories='{categories}'",
"--repeat=weekly",
f"--until={until}",
startDate,
startTime,
endTime,
title,
]
cmds.append(cmd)
while True:
commandList = "\n".join([" ".join(c) for c in cmds]) ## Prepare for printing
choice = input(
"Do you want to execute the following commands? YES/NO:\n"
+ commandList
+ "\n"
).lower()
if choice in ["yes", "y"]:
for c in cmds:
subprocess.call(c)
print("Done")
return
elif choice in ["no", "n"]:
print("Noting to do. Exiting.")
return
else:
print("Please respond with 'yes' or 'no'\n")
if __name__ == "__main__":
if args["chose"]:
onChose()
elif args["list"]:
onList()
elif args["timetable"]:
onTimetable()
else:
pass

18
timetable.yaml Normal file
View File

@ -0,0 +1,18 @@
V:
day: 'Mon'
start: '16:00'
end: '18:00'
location: 'ML D 28'
type: 'V'
E:
day: 'Wed'
start: '08:00'
end: '09:00'
location: 'CAB G 11'
type: 'E'
P:
day: 'Thu'
start: '16:00'
end: '19:00'
location: 'CHN E 42'
type: 'P'