Commit b903c6ee authored by Dominik Woiwode's avatar Dominik Woiwode
Browse files

Merge branch 'grav' into 'pter2.0'

Grav

See merge request !1
parents 510a581a ae1fcd3a
.idea/
data/
\ No newline at end of file
data/
__pycache__
settings.py
\ No newline at end of file
......@@ -7,6 +7,7 @@ from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from enum import Enum
from pathlib import Path
from typing import Optional, Dict, List
......@@ -25,18 +26,30 @@ LDAP_PASSWORD = None
LDAP_MAIL = None
LDAP_NAME = None
IGNORED_TOPS = ["Anwesende", "Ständiges", "Termine", "Mitteilungen/Verschiedenes", "Schluss"]
GIT_REPO = None
GIT_REPO_PATH = None
GIT_NAME = None
GIT_EMAIL = None
GRAV_PROTOCOL_PATH = "pages/fachrat/02.protokolle/"
git = None
@dataclass
class Gremium:
name: str
fullName: str
template: str
def fullTemplate(self):
return str(Path(os.path.join(TEMPLATE_FOLDER, self.template)).absolute())
GREMIUM_FR = Gremium("finf", "pandoc.finf.tex")
GREMIUM_FSR = Gremium("fsr", "pandoc.fsr.tex")
GREMIUM_FR = Gremium("finf", "Fachrat Informatik", "pandoc.finf.tex")
GREMIUM_FSR = Gremium("fsr", "Fachschaftsrat Elektrotechnik und Informatik", "pandoc.fsr.tex")
@dataclass
......@@ -60,7 +73,6 @@ class MailParticipant:
# Helper Functions
def sendFRMail(text: str, subject: str, sender: MailParticipant, receivers: List[MailParticipant],
attachement: "BasePad" = None):
mail = MIMEMultipart()
......@@ -77,21 +89,113 @@ def sendFRMail(text: str, subject: str, sender: MailParticipant, receivers: List
with open(attachement.compiledPath, "rb") as d:
payload.set_payload(d.read())
encoders.encode_base64(payload)
payload.add_header('Content-Disposition', f"attachment; filename={attachement.displayName}")
payload.add_header('Content-Disposition',
f"attachment; filename={attachement.displayName}")
mail.attach(payload)
try:
server = smtplib.SMTP("mail.finf.uni-hannover.de", 587)
server.starttls()
server.login(sender.mail, LDAP_PASSWORD)
server.sendmail(sender.mail, [r.mail for r in receivers], mail.as_string())
server.sendmail(
sender.mail, [r.mail for r in receivers], mail.as_string())
server.quit()
print(f"Email \"{subject}\" an {receivers} erfolgreich versendet")
except smtplib.SMTPException:
print(f"Fehler beim Senden der Email \"{subject}\" von {sender} an {receivers}")
print(
f"Fehler beim Senden der Email \"{subject}\" von {sender} an {receivers}")
raise
# === Git Helper ===
class GitHelper:
def __init__(self, repository:str, repository_path:str):
self.repository = repository
self.repository_path = repository_path
def clone(self):
cmd = f'git clone {self.repository} {self.repository_path}'
os.system(cmd)
def forcePull(self):
cmd = f'git -C {self.repository_path} fetch origin master'
os.system(cmd)
cmd = f'git -C {self.repository_path} reset --hard origin/master'
os.system(cmd)
def update(self):
if os.path.exists(self.repository_path + "/.git"):
self.forcePull()
else:
self.clone()
def push(self):
cmd = f'git -C {self.repository_path} push origin master'
os.system(cmd)
def add(self, file: str):
cmd = f'git -C {self.repository_path} add {file}'
os.system(cmd)
def commit(self, msg: str):
cmd = f'git -C {self.repository_path} commit -m \"{msg}\"'
os.system(cmd)
def config(self, email, name):
cmd = f'git -C {self.repository_path} config user.name {name}'
os.system(cmd)
cmd = f'git -C {self.repository_path} config user.email {email}'
os.system(cmd)
class SemesterPart(Enum):
Summer = "Sommersemester"
Winter = "Wintersemester"
def short(self):
if self == SemesterPart.Summer:
return "SS"
return "WS"
@dataclass(unsafe_hash=True)
class Semester:
year: int
part: SemesterPart
def __post_init__(self):
self.displayName = f"{self.part.value} {self.year}"
self.gravPath = os.path.join(GIT_REPO_PATH, GRAV_PROTOCOL_PATH,
self._gravName(), "protocol_semester.de.md")
def _gravName(self):
return f"{self.year - 2000}{self.part.short()}"
@classmethod
def fromDate(cls, date: datetime.datetime) -> "Semester":
if 4 <= date.month < 10:
# Summer
return Semester(date.year, SemesterPart.Summer)
elif date.month >= 10:
# Winter
return Semester(date.year, SemesterPart.Winter)
else:
# Winter
return Semester(date.year - 1, SemesterPart.Winter)
def uploadToGrav(self):
if os.path.exists(self.gravPath):
return
os.makedirs(str(Path(self.gravPath).parent), exist_ok=True)
with open(self.gravPath, "w") as d:
d.write(f"---\ntitle: {self.displayName}\n---")
git.add(GRAV_PROTOCOL_PATH)
git.commit(f"Added {self.part.value} {self.year}")
git.push()
# === Source Types ===
class SourceTypes:
def __init__(self, url: str):
......@@ -132,6 +236,7 @@ class BasePad:
self.rawPath = rawPath or hashlib.md5(source.url.encode("utf-8"))
self.displayName = displayName or self.DEFAULT_DISPLAY_NAME()
self.compiledPath = None
self.folder = ""
def __repr__(self):
return f"{self.__class__.__name__}({self.source})"
......@@ -151,6 +256,7 @@ class BasePad:
content = self.source.retrieveContent()
if not override and os.path.exists(path):
raise FileExistsError(f"{path} already exists!")
os.makedirs(str(Path(path).parent), exist_ok=True)
with open(path, "w", encoding="utf-8") as d:
d.write(content)
self.rawPath = path
......@@ -160,7 +266,9 @@ class BasePad:
outFilePath = self.DEFAULT_COMPILED_PATH()
outPath = Path(outFilePath)
os.makedirs(outPath.parent, exist_ok=True)
metadataStr = " " + " ".join([f'-M {key}="{val}"' for key, val in self.metadata.items()])
metadataStr = " " + \
" ".join([f'-M {key}="{val}"' for key,
val in self.metadata.items()])
templateStr = ""
if template is None and hasattr(self, "gremium"):
templateStr = f' --template="{getattr(self, "gremium").fullTemplate()}" '
......@@ -173,6 +281,7 @@ class BasePad:
return ret
class ProtocolPad(BasePad):
def __init__(self, source: SourceTypes, *_, date: datetime.datetime = None,
isFachgruppenvollversammlung: bool = False, isApproved: bool = False, gremium: Gremium = None):
......@@ -180,13 +289,40 @@ class ProtocolPad(BasePad):
self.date = date
self.isApproved = isApproved
self.isFachgruppenvollversammlung = isFachgruppenvollversammlung
self.semester = None
super().__init__(source)
def __repr__(self):
return super(ProtocolPad, self).__repr__()[:-1] + f", {self.date})"
def DEFAULT_DISPLAY_NAME(self):
return f"Protokoll {self.gremium.name} {self.date.strftime('%Y-%m-%d')}" + " - Fachgruppenvollversammlung"*self.isFachgruppenvollversammlung
return f"Protokoll {self.gremium.name} {self.date.strftime('%Y-%m-%d')}" + " - Fachgruppenvollversammlung" * self.isFachgruppenvollversammlung
def DEFAULT_GRAV_PATH(self):
return os.path.join(GIT_REPO_PATH, GRAV_PROTOCOL_PATH,
self.semester._gravName(),
self.date.strftime("%Y-%m-%d") + "-fgvv" * self.isFachgruppenvollversammlung,
"default.de.md")
def parseTops(self):
# TODO: better top filter?
lines = self.source.retrieveContent().split("\n")
# with open(self.rawPath, "r", encoding="utf-8") as f:
# lines = f.read().split("\n")
tops = []
for l in lines:
# Change to regex?
# import re
# res = re.match("^## ([\w\d &!\"'§$%/\-+äöüß]+)\w*(\(\d\d:\d\d Uhr\))?", l)
# if res is not None:
# top = res.group(1)
if l.startswith("## "):
top = l.strip("#").rsplit("(")[0].strip()
if any(top in t or t in top for t in IGNORED_TOPS):
continue
tops.append(top)
return tops
def sendMailAsUnapproved(self) -> bool:
sender = MailParticipant(LDAP_MAIL, LDAP_NAME)
......@@ -226,11 +362,59 @@ class ProtocolPad(BasePad):
return False
return True
def uploadToCloud(self) -> bool:
def uploadToCloud(self):
pass
def uploadToGrav(self) -> bool:
pass
def uploadToGrav(self):
# Init semester
# TODO: better file management
self.semester.uploadToGrav()
if not os.path.exists(self.rawPath):
raise FileNotFoundError(f"{self.rawPath} doesn't exist")
# TODO: move conversion to another method?
with open(self.rawPath, "r", encoding="utf-8") as f:
lines = f.read().split("\n")
# Tops
tops = self.parseTops()
tops_text = ", ".join(tops)
# Header
if self.isFachgruppenvollversammlung:
name = "der Fachgruppenvollversammlung"
else:
name = f"des {self.gremium.fullName}"
header = ("---\n"
f"title: Protokoll {name} am {self.date.strftime('%d.%m.%Y')}\n"
f"date: {self.date.strftime('%d.%m.%Y')}\n"
f"tops: {tops_text}\n"
"---\n\n"
"[MINITOC]\n\n")
# Lines
lines_new = [header]
ignore = False
for l in lines:
if l.startswith("######"): # tags 'fr'
continue
if l == "---":
ignore = True
continue
if l == "...":
ignore = False
continue
if ignore:
continue
lines_new.append(l)
# Upload
os.makedirs(str(Path(self.DEFAULT_GRAV_PATH()).parent), exist_ok=True)
with open(self.DEFAULT_GRAV_PATH(), "w", encoding="utf-8") as f:
f.write("\n".join(lines_new))
git.add(GRAV_PROTOCOL_PATH)
git.commit(f"Added protocol {self.displayName}")
git.push()
class AttachementPad(BasePad):
......@@ -254,6 +438,7 @@ class PadCollection(BasePad):
Parsing the protocollink-Pad for urls.
"""
pads = dict()
semesters = dict()
currentFolder = ""
for line in self.source.retrieveContent().split("\n"):
if line.startswith("# "):
......@@ -264,6 +449,12 @@ class PadCollection(BasePad):
continue
if currentFolder not in pads:
pads[currentFolder] = list()
if isinstance(pad, ProtocolPad) and pad.date is not None:
semester = Semester.fromDate(pad.date)
if semester not in semesters:
semesters[semester] = semester
pad.semester = semester
pad.folder = currentFolder
pads[currentFolder].append(pad)
return pads
......@@ -297,7 +488,8 @@ class PadCollection(BasePad):
padType = ProtocolPad
kwargs["isApproved"] = isApproved
try:
date = datetime.datetime.strptime(comment[0].strip(), "%d.%m.%Y")
date = datetime.datetime.strptime(
comment[0].strip(), "%d.%m.%Y")
except Exception:
dateStr = url.split("protokoll")[-1][:8]
date = datetime.datetime.strptime(dateStr, "%Y%m%d")
......@@ -308,10 +500,20 @@ class PadCollection(BasePad):
return padType(src, **kwargs)
def initGit():
global git
if any(o is None for o in [GIT_REPO, GIT_REPO_PATH, GIT_EMAIL, GIT_NAME]):
raise RuntimeError("Git is not configured correctly")
git = GitHelper(GIT_REPO, GIT_REPO_PATH)
git.config(GIT_EMAIL, GIT_NAME)
git.update()
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description="Download and convert finf/fsr-protocols using pandoc")
parser = argparse.ArgumentParser(
description="Download and convert finf/fsr-protocols using pandoc")
parser.add_argument("-urls", nargs="+", type=str, default=[])
parser.add_argument("-pad", type=str, default=None)
# parser.add_argument("--prefixes", type=str, default="",
......
......@@ -5,10 +5,10 @@ import linkToPDF2 as pter
class ProtokollGUI(tk.Tk):
def __init__(self, rootPad:pter.SourceTypes):
def __init__(self, rootPad: pter.SourceTypes):
super().__init__(screenName="ProtokollHelper")
self.rootPad = pter.PadCollection(rootPad)
print(self.rootPad.getPads())
# print(self.rootPad.getPads())
self.folders = dict()
self.folderIndex = 0
......@@ -18,8 +18,10 @@ class ProtokollGUI(tk.Tk):
self.topRow = tk.Frame(self)
self.topRow.pack(fill=tk.X, expand=True)
self.folderLabel = tk.Label(self.topRow)
self.leftButton = tk.Button(self.topRow, text="<", state=tk.DISABLED, command=self.updateFolderIndex(-1))
self.rightButton = tk.Button(self.topRow, text=">", command=self.updateFolderIndex(1))
self.leftButton = tk.Button(
self.topRow, text="<", state=tk.DISABLED, command=self.updateFolderIndex(-1))
self.rightButton = tk.Button(
self.topRow, text=">", command=self.updateFolderIndex(1))
self.leftButton.pack(side=tk.LEFT)
self.folderLabel.pack(side=tk.LEFT, fill=tk.X, expand=True)
......@@ -31,7 +33,7 @@ class ProtokollGUI(tk.Tk):
self.updatePadFrame()
def updateFolderIndex(self, i):
def wrapper(*args,**kwargs):
def wrapper(*args, **kwargs):
self.folderIndex = (self.folderIndex + i) % len(self.folders)
self.updatePadFrame()
......@@ -40,42 +42,49 @@ class ProtokollGUI(tk.Tk):
def updatePadFrame(self):
folderName = list(self.folders.keys())[self.folderIndex]
self.folderLabel.configure(text=folderName)
self.currentPads = [p for p in self.folders[folderName] if isinstance(p, pter.ProtocolPad)]
self.currentPads = [p for p in self.folders[folderName]
if isinstance(p, pter.ProtocolPad)]
for i, pad in enumerate(self.currentPads):
assert isinstance(pad, pter.ProtocolPad)
tk.Label(self.padFrame, text=pad.source.url,anchor=tk.W, bg="red").grid(row=i,column=0, sticky=tk.W) # URL
tk.Label(self.padFrame, text=pad.date,anchor=tk.W, bg="blue").grid(row=i,column=1) # Date
tk.Label(self.padFrame, text=pad.source.url, anchor=tk.W,
bg="red").grid(row=i, column=0, sticky=tk.W) # URL
tk.Label(self.padFrame, text=pad.date, anchor=tk.W,
bg="blue").grid(row=i, column=1) # Date
# Button Download
btnDownload = tk.Button(self.padFrame, text="Download", command=pad.download)
btnDownload = tk.Button(
self.padFrame, text="Download", command=pad.download)
btnDownload.grid(row=i, column=2)
# Button Compile
btnCompile = tk.Button(self.padFrame, text="Compile", command=pad.compile)
btnCompile = tk.Button(
self.padFrame, text="Compile", command=pad.compile)
btnCompile.grid(row=i, column=3)
# Button Mail FR
btnMailFR = tk.Button(self.padFrame, text="Vorläufige FR-Mail", command=pad.sendMailAsUnapproved)
btnMailFR = tk.Button(
self.padFrame, text="Vorläufige FR-Mail", command=pad.sendMailAsUnapproved)
btnMailFR.grid(row=i, column=4)
# Button Mail FR-Info
btnMailFRInfo = tk.Button(self.padFrame, text="FR-Info Mail", state=tk.DISABLED, command=pad.sendMailAsApproved)
btnMailFRInfo = tk.Button(
self.padFrame, text="FR-Info Mail", state=tk.DISABLED, command=pad.sendMailAsApproved)
btnMailFRInfo.grid(row=i, column=5)
# Button Website
btnWebsite = tk.Button(self.padFrame, text="Approved Website", state=tk.DISABLED, command=pad.uploadToGrav)
btnWebsite = tk.Button(
self.padFrame, text="Approved Website", command=pad.uploadToGrav)
btnWebsite.grid(row=i, column=6)
# Button Cloud
btnCloud = tk.Button(self.padFrame, text="Approved Cloud", state=tk.DISABLED, command=pad.uploadToCloud)
btnCloud = tk.Button(self.padFrame, text="Approved Cloud",
state=tk.DISABLED, command=pad.uploadToCloud)
btnCloud.grid(row=i, column=7)
if __name__ == '__main__':
# gui = ProtokollGUI(pter.LocalCache("data/rootPad.md"))
gui = ProtokollGUI(pter.CodiMD("https://pad.finf.uni-hannover.de/protokolllinks_terces"))
pter.DEFAULT_GREMIUM = pter.GREMIUM_FR
pter.initGit()
gui = ProtokollGUI(pter.CodiMD(
"https://pad.finf.uni-hannover.de/protokolllinks_terces"))
gui.mainloop()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment