from configparser import ConfigParser # For reading the config.ini file from shutil import copy # For creating a new config.ini file from requests import request # For using the Trello API import smtplib, ssl, email # For sending emails ### Constants TRELLO_API_CARDS_URL = "https://api.trello.com/1/boards/{id}/cards" ### # TODO: Set up actual logging def log(text: str): print(text) def read_config() -> dict: """ Reads the file config.ini. If the there is no file, it will create one. If the file has empty fields, it will notify the user and end the program. RETURNS ------- - dict The contents of the config.ini file. """ config = ConfigParser() # Reads the file and checks if it exists if config.read('config.ini') == []: copy("config.ini.sample","config.ini") log("Creating config.ini file") exit() # Creates the dict and removes the "DEFAULTS" section config_dict = { key: dict(value) for key,value in dict(config).items() if key != "DEFAULT" } # Checks if every field is filled out all_filled_out = all( all(v2 != '' for _,v2 in v1.items()) for _,v1 in config_dict.items() ) if not all_filled_out: log("Empty fields in config.ini") exit() return config_dict def get_trello_cards(config: dict) -> list[dict]: """ Uses the Trello API to get every card from the board, and extracts the important information. PARAMETERS ---------- - config: dict The config file data. Uses this for the board ID, and the API key and token. RETURNS ------- - list[dict] A list of each card, with the following information: card id, name of the card, when the last activity on the card was performed, the IDs of whatever members are assigned, and the labels the card has. """ url = TRELLO_API_CARDS_URL.format(id=config["Trello"]["boardid"]) query = { 'key': config["Trello"]["apikey"], 'token': config["Trello"]["apitoken"] } # Calling the API response = request( "GET", url, params=query ) # Making a list of cards with relevant information cards = [ { "id": card["id"], "name": card["name"], "lastActivity": card["dateLastActivity"], "memberIDs": card["idMembers"], "labels": [label["name"] for label in card["labels"]] } for card in response.json() ] return cards def flag_out_of_date_cards(cards: list[dict]) -> list[dict]: """ Flags cards as out of date, if they exceed the deadline. PARAMETERS ---------- - cards: list[dict] The list of cards. RETURNS ------- - list[dict] The same list of cards, but with an out_of_date boolean field. """ pass def generate_reports(cards: list[dict]) -> tuple[str,list]: """ Generates the PDF reports for each user. Each report will be found at ./reports/TIMESTAMP/USERID.pdf PARAMETERS ---------- - cards: list[dict] The list of cards. RETURNS ------- - str The timestamp used for the folder in which the reports are generated. - list The list of users reports were generated for. """ pass def get_emails(config: dict, user_ids: list[str]) -> dict: """ Uses the Trello API to find the email addresses of the given users. PARAMETERS ---------- - config: dict The config file data. Uses this for the board ID, and the API key and token. - user_ids: list[str] A list of user IDs. RETURNS ------- - dict A dict where each user ID is the key and the value is their email. """ pass def send_emails(config: dict, users: dict, timestamp: str) -> None: """ Sending out emails. PARAMETERS ---------- - config: dict The config file data. Uses this for the SMTP server, port, username, and password. - users: dict Each user ID and the email connected to it. - timestamp: str The timestamp used to create the folder that the reports are in. """ # Create a secure SSL context context = ssl.create_default_context() # Logging in server_url = config["SMTP"]["server"] port = config["SMTP"]["port"] username = config["SMTP"]["username"] password = config["SMTP"]["password"] with smtplib.SMTP_SSL(server_url, port, context=context) as server: server.login(username, password) # Looping through each user and sending them an email with the pdf for user_id, receiver in users.items(): pdf_path = f"reports/{timestamp}/{user_id}.pdf" subject = "Trello Report" body = "Here is your Trello Report" # Preparing the message message = email.mime.multipart.MIMEMultipart() message["From"] = username message["To"] = receiver message["Subject"] = subject message.attach(email.mime.text.MIMEText(body, "plain")) # Open PDF file in binary mode, and attach it to the email with open(pdf_path, "rb") as file_pointer: part = email.mime.base.MIMEBase("application", "octet-stream") part.set_payload(file_pointer.read()) # Encode file in ASCII characters to send by email email.encoders.encode_base64(part) # Add header as key/value pair to attachment part part.add_header( "Content-Disposition", f"attachment; filename= TrelloReport-{user_id}-{timestamp}.pdf", ) # Add attachment to message and convert message to string message.attach(part) text = message.as_string() server.sendmail(username, receiver, text) def main(): # Reading the config file config = read_config() # Getting the cards from Trello cards = get_trello_cards(config) # Flagging the cards if they've exceeded their deadline cards = flag_out_of_date_cards(cards) # Generate the PDF reports timestamp, user_ids = generate_reports(cards) # Get the email address of each user users = get_emails(config, user_ids) # Send out the emails send_emails(config, users, timestamp) if __name__ == "__main__": main()