Loading .gitignore 0 → 100644 +3 −0 Original line number Diff line number Diff line teilnehmer.json pairs.dump mails/ No newline at end of file mail.py 0 → 100644 +52 −0 Original line number Diff line number Diff line """This module manages sending and saving mails. Most of the code is adopted from Jakob's implementation of a digital Kurswahl for the GT. Thank you for the help!""" import ssl from email import charset from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate from smtplib import SMTP from typing import Optional _connection: Optional[SMTP] = None # Encode utf-8 strings using utf-8, and not base-64 # See https://bugs.python.org/issue12552 charset.add_charset('utf-8', charset.SHORTEST) def open_connection(): global _connection _connection = SMTP("mail.urz.uni-heidelberg.de", 587) _connection.starttls(context=ssl.create_default_context()) def send_mail(msg: MIMEMultipart, auto_close_connection: bool = True): if _connection is None: open_connection() try: print(f"Sending to {msg['To']}...") _connection.send_message(msg) finally: if auto_close_connection: close_connection() def save_mail(file, msg): with open(file, "wb") as f: f.write(msg.as_bytes()) def generate_mail(recipient, content): msg = MIMEMultipart() msg["From"] = "knecht-robobert@cl.uni-heidelberg.de" msg["To"] = recipient msg["Date"] = formatdate(localtime=True) msg["Subject"] = "Wunderbares Winterwichteln" msg["Bcc"] = "knecht-robobert@cl.uni-heidelberg.de" text = MIMEText(content) msg.attach(text) return msg def close_connection(): global _connection _connection.quit() main.py 0 → 100644 +67 −0 Original line number Diff line number Diff line import argparse import os import json from mail import generate_mail, save_mail, open_connection, close_connection, send_mail from sampling import HamiltonSampler SAMPLERS = {"hamilton": HamiltonSampler} MAILDIR = "./mails" os.makedirs(MAILDIR, exist_ok=True) MAIL_TEMPLATE = "./src/assignment_mail.txt" def prepare_mail_content(giver, presentee): with open(MAIL_TEMPLATE, "r") as f: text = f.read() text = text.replace("{giver_name}", giver["name"]) for attribute in ["name", "fullname", "street", "city", "address_appendix"]: value = presentee[attribute] if attribute in presentee else "" text = text.replace(f"{{presentee_{attribute}}}", value) text = text.replace("{presentee_note}", f"Notiz der Person: {presentee['note']}" if "note" in presentee else "") return text if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("input", help="the input file containing the data of the participants") parser.add_argument("--sampling", choices=list(SAMPLERS.keys()), default="hamilton", help="The sampling strategy/algorithm for choosing pairs") args = parser.parse_args() # Load the people with open(args.input, "r") as f: people = json.load(f) print(f"Loaded {len(people)} participants") # Sample the pairs sampler = SAMPLERS[args.sampling](list(people.keys())) pairs = sampler.sample_pairs() with open("pairs.dump", "w") as f: json.dump(pairs, f, indent=4, ensure_ascii=False) # Generate mails mails = [] for pair in pairs: giver, presentee = people[pair[0]], people[pair[1]] mail_content = prepare_mail_content(giver, presentee) mail = generate_mail(pair[0], mail_content) mails.append(mail) save_mail(f"{MAILDIR}/{pair[0]}.eml", mail) # Ask for confirmation print(f"Created {len(mails)} mails. Please check them in the folder {MAILDIR}.") command = input(f"Enter \"confirm\" to automatically send the mails. Please don't terminate the program, or the pairs will be lost.\n") if command != "confirm": print("Aborting...") exit() # Send the mails print("Sending mails...") open_connection() for msg in mails: send_mail(msg, auto_close_connection=False) close_connection() No newline at end of file sampling.py 0 → 100644 +18 −0 Original line number Diff line number Diff line import random class Sampler(): def __init__(self, elements): self.elements = elements def sample_pairs(self): raise NotImplementedError() class HamiltonSampler(Sampler): def sample_pairs(self): pairs = [] e = self.elements[:] random.shuffle(e) for i in range(len(e)): pairs.append((e[i], e[i+1 if i+1 < len(e) else 0])) return pairs No newline at end of file src/assignment_mail.txt 0 → 100644 +25 −0 Original line number Diff line number Diff line Ho Ho Ho {giver_name}! Ich freue mich sehr, dass du am diesjährigen Wichteln teilnimmst! Du wichtelst für {presentee_name}. Sende das Paket also bitte so bald wie möglich an folgende Adresse: {presentee_fullname} {presentee_street} {presentee_address_appendix} {presentee_city} {presentee_note} Denke an genügend Porto, damit das Geschenk auch rechtzeitig ankommt! Damit das ganze schön anonym stattfinden kann, kannst du als Absendeadresse das Institut angeben, damit dein Paket im Notfall nicht verloren geht: Sekretariat, Raum 109a Im Neuenheimer Feld 325 69120 Heidelberg (Wenn das Paket allerdings nicht ausreichend frankiert ist, wird es natürlich trotzdem nicht angenommen werden können!) Winterliche Grüße und eine tolle vorlesungsfreie Zeit Knecht Robobert No newline at end of file Loading
.gitignore 0 → 100644 +3 −0 Original line number Diff line number Diff line teilnehmer.json pairs.dump mails/ No newline at end of file
mail.py 0 → 100644 +52 −0 Original line number Diff line number Diff line """This module manages sending and saving mails. Most of the code is adopted from Jakob's implementation of a digital Kurswahl for the GT. Thank you for the help!""" import ssl from email import charset from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate from smtplib import SMTP from typing import Optional _connection: Optional[SMTP] = None # Encode utf-8 strings using utf-8, and not base-64 # See https://bugs.python.org/issue12552 charset.add_charset('utf-8', charset.SHORTEST) def open_connection(): global _connection _connection = SMTP("mail.urz.uni-heidelberg.de", 587) _connection.starttls(context=ssl.create_default_context()) def send_mail(msg: MIMEMultipart, auto_close_connection: bool = True): if _connection is None: open_connection() try: print(f"Sending to {msg['To']}...") _connection.send_message(msg) finally: if auto_close_connection: close_connection() def save_mail(file, msg): with open(file, "wb") as f: f.write(msg.as_bytes()) def generate_mail(recipient, content): msg = MIMEMultipart() msg["From"] = "knecht-robobert@cl.uni-heidelberg.de" msg["To"] = recipient msg["Date"] = formatdate(localtime=True) msg["Subject"] = "Wunderbares Winterwichteln" msg["Bcc"] = "knecht-robobert@cl.uni-heidelberg.de" text = MIMEText(content) msg.attach(text) return msg def close_connection(): global _connection _connection.quit()
main.py 0 → 100644 +67 −0 Original line number Diff line number Diff line import argparse import os import json from mail import generate_mail, save_mail, open_connection, close_connection, send_mail from sampling import HamiltonSampler SAMPLERS = {"hamilton": HamiltonSampler} MAILDIR = "./mails" os.makedirs(MAILDIR, exist_ok=True) MAIL_TEMPLATE = "./src/assignment_mail.txt" def prepare_mail_content(giver, presentee): with open(MAIL_TEMPLATE, "r") as f: text = f.read() text = text.replace("{giver_name}", giver["name"]) for attribute in ["name", "fullname", "street", "city", "address_appendix"]: value = presentee[attribute] if attribute in presentee else "" text = text.replace(f"{{presentee_{attribute}}}", value) text = text.replace("{presentee_note}", f"Notiz der Person: {presentee['note']}" if "note" in presentee else "") return text if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("input", help="the input file containing the data of the participants") parser.add_argument("--sampling", choices=list(SAMPLERS.keys()), default="hamilton", help="The sampling strategy/algorithm for choosing pairs") args = parser.parse_args() # Load the people with open(args.input, "r") as f: people = json.load(f) print(f"Loaded {len(people)} participants") # Sample the pairs sampler = SAMPLERS[args.sampling](list(people.keys())) pairs = sampler.sample_pairs() with open("pairs.dump", "w") as f: json.dump(pairs, f, indent=4, ensure_ascii=False) # Generate mails mails = [] for pair in pairs: giver, presentee = people[pair[0]], people[pair[1]] mail_content = prepare_mail_content(giver, presentee) mail = generate_mail(pair[0], mail_content) mails.append(mail) save_mail(f"{MAILDIR}/{pair[0]}.eml", mail) # Ask for confirmation print(f"Created {len(mails)} mails. Please check them in the folder {MAILDIR}.") command = input(f"Enter \"confirm\" to automatically send the mails. Please don't terminate the program, or the pairs will be lost.\n") if command != "confirm": print("Aborting...") exit() # Send the mails print("Sending mails...") open_connection() for msg in mails: send_mail(msg, auto_close_connection=False) close_connection() No newline at end of file
sampling.py 0 → 100644 +18 −0 Original line number Diff line number Diff line import random class Sampler(): def __init__(self, elements): self.elements = elements def sample_pairs(self): raise NotImplementedError() class HamiltonSampler(Sampler): def sample_pairs(self): pairs = [] e = self.elements[:] random.shuffle(e) for i in range(len(e)): pairs.append((e[i], e[i+1 if i+1 < len(e) else 0])) return pairs No newline at end of file
src/assignment_mail.txt 0 → 100644 +25 −0 Original line number Diff line number Diff line Ho Ho Ho {giver_name}! Ich freue mich sehr, dass du am diesjährigen Wichteln teilnimmst! Du wichtelst für {presentee_name}. Sende das Paket also bitte so bald wie möglich an folgende Adresse: {presentee_fullname} {presentee_street} {presentee_address_appendix} {presentee_city} {presentee_note} Denke an genügend Porto, damit das Geschenk auch rechtzeitig ankommt! Damit das ganze schön anonym stattfinden kann, kannst du als Absendeadresse das Institut angeben, damit dein Paket im Notfall nicht verloren geht: Sekretariat, Raum 109a Im Neuenheimer Feld 325 69120 Heidelberg (Wenn das Paket allerdings nicht ausreichend frankiert ist, wird es natürlich trotzdem nicht angenommen werden können!) Winterliche Grüße und eine tolle vorlesungsfreie Zeit Knecht Robobert No newline at end of file