diff options
Diffstat (limited to '')
-rwxr-xr-x | code_check.sh | 2 | ||||
-rw-r--r-- | cycles.json | 177 | ||||
-rwxr-xr-x | sendmail-test.py | 253 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/daily.py (renamed from daily.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/grant.py (renamed from grant.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/inspire_approve.py (renamed from inspire_approve.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/inspire_dl.py (renamed from inspire_dl.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/legacy_wikipedia.py (renamed from legacy_wikipedia.py) | 0 | ||||
-rw-r--r-- | sjdbmk/menuparser.py (renamed from menuparser.py) | 5 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/msal_skeleton.py (renamed from msal_skeleton.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/pack.py (renamed from pack.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/sendmail.py (renamed from sendmail.py) | 17 | ||||
-rw-r--r-- | sjdbmk/sendmail2.py (renamed from sendmail2.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/serve.py (renamed from serve.py) | 0 | ||||
-rw-r--r--[-rwxr-xr-x] | sjdbmk/weekly.py (renamed from weekly.py) | 19 |
15 files changed, 19 insertions, 454 deletions
diff --git a/code_check.sh b/code_check.sh index 750288e..aeb87b5 100755 --- a/code_check.sh +++ b/code_check.sh @@ -1,3 +1,3 @@ #!/bin/sh mypy --strict . -pylint --disable C0301,W0511,C0114,C0115,C0116,R0913,R0914,C0209,W1201,E1205,R0915,R1728,W0613,C0200,R0912,R1702,E1101,W0621,R1718,R0801,W3101,W1514 *.py +pylint --disable C0301,W0511,C0114,C0115,C0116,R0913,R0914,C0209,W1201,E1205,R0915,R1728,W0613,C0200,R0912,R1702,E1101,W0621,R1718,R0801,W3101,W1514,C0206 *.py diff --git a/cycles.json b/cycles.json deleted file mode 100644 index 59c9e64..0000000 --- a/cycles.json +++ /dev/null @@ -1,177 +0,0 @@ -{
- "comment": "This should be replaced by the Outlook Shared Calendar interpretation script later, but should suffice for now.",
- "2023-09-04": "A",
- "2023-09-05": "B",
- "2023-09-06": "C",
- "2023-09-07": "D",
- "2023-09-08": "E",
- "2023-09-11": "F",
- "2023-09-12": "A",
- "2023-09-13": "B",
- "2023-09-14": "C",
- "2023-09-15": "D",
- "2023-09-18": "E",
- "2023-09-19": "F",
- "2023-09-20": "A",
- "2023-09-21": "B",
- "2023-09-22": "C",
- "2023-09-25": "D",
- "2023-09-26": "E",
- "2023-09-27": "F",
- "2023-09-28": "A",
- "2023-10-09": "B",
- "2023-10-10": "C",
- "2023-10-11": "D",
- "2023-10-12": "E",
- "2023-10-13": "F",
- "2023-10-16": "A",
- "2023-10-17": "B",
- "2023-10-18": "C",
- "2023-10-19": "D",
- "2023-10-20": "E",
- "2023-10-23": "F",
- "2023-10-24": "A",
- "2023-10-25": "B",
- "2023-10-26": "C",
- "2023-10-30": "D",
- "2023-10-31": "E",
- "2023-11-01": "F",
- "2023-11-02": "A",
- "2023-11-03": "B",
- "2023-11-06": "C",
- "2023-11-07": "D",
- "2023-11-08": "E",
- "2023-11-09": "F",
- "2023-11-10": "A",
- "2023-11-13": "B",
- "2023-11-14": "C",
- "2023-11-15": "D",
- "2023-11-20": "E",
- "2023-11-21": "F",
- "2023-11-22": "A",
- "2023-11-23": "B",
- "2023-11-24": "C",
- "2023-11-27": "D",
- "2023-11-28": "E",
- "2023-11-29": "F",
- "2023-11-30": "A",
- "2023-12-04": "B",
- "2023-12-05": "C",
- "2023-12-06": "D",
- "2023-12-07": "E",
- "2023-12-08": "F",
- "2023-12-11": "A",
- "2023-12-12": "B",
- "2023-12-13": "C",
- "2023-12-14": "D",
- "2023-12-15": "E",
- "2023-12-18": "F",
- "2023-12-19": "A",
- "2023-12-20": "B",
- "2023-12-21": "C",
- "2024-01-08": "D",
- "2024-01-09": "E",
- "2024-01-10": "F",
- "2024-01-11": "A",
- "2024-01-12": "B",
- "2024-01-15": "C",
- "2024-01-16": "D",
- "2024-01-17": "E",
- "2024-01-18": "F",
- "2024-01-19": "A",
- "2024-01-22": "B",
- "2024-01-23": "C",
- "2024-01-24": "D",
- "2024-01-25": "E",
- "2024-01-26": "F",
- "2024-01-29": "A",
- "2024-01-30": "B",
- "2024-01-31": "C",
- "2024-02-01": "D",
- "2024-02-19": "E",
- "2024-02-20": "F",
- "2024-02-21": "A",
- "2024-02-22": "B",
- "2024-02-23": "C",
- "2024-02-26": "D",
- "2024-02-27": "E",
- "2024-02-28": "F",
- "2024-02-29": "A",
- "2024-03-01": "B",
- "2024-03-04": "C",
- "2024-03-05": "D",
- "2024-03-06": "E",
- "2024-03-07": "F",
- "2024-03-08": "A",
- "2024-03-11": "B",
- "2024-03-12": "C",
- "2024-03-13": "D",
- "2024-03-14": "E",
- "2024-03-15": "F",
- "2024-03-18": "A",
- "2024-03-19": "B",
- "2024-03-20": "C",
- "2024-03-21": "D",
- "2024-03-22": "E",
- "2024-03-25": "F",
- "2024-03-26": "A",
- "2024-03-27": "B",
- "2024-03-28": "C",
- "2024-03-29": "D",
- "2024-04-09": "E",
- "2024-04-10": "F",
- "2024-04-11": "A",
- "2024-04-12": "B",
- "2024-04-15": "C",
- "2024-04-16": "D",
- "2024-04-17": "E",
- "2024-04-18": "F",
- "2024-04-19": "A",
- "2024-04-22": "B",
- "2024-04-23": "C",
- "2024-04-24": "D",
- "2024-04-25": "E",
- "2024-04-26": "F",
- "2024-04-29": "A",
- "2024-04-30": "B",
- "2024-05-02": "C",
- "2024-05-03": "D",
- "2024-05-06": "E",
- "2024-05-07": "F",
- "2024-05-08": "A",
- "2024-05-09": "B",
- "2024-05-10": "C",
- "2024-05-13": "D",
- "2024-05-14": "E",
- "2024-05-15": "F",
- "2024-05-16": "A",
- "2024-05-17": "B",
- "2024-05-20": "C",
- "2024-05-21": "D",
- "2024-05-22": "E",
- "2024-05-23": "F",
- "2024-05-24": "A",
- "2024-05-27": "B",
- "2024-05-28": "C",
- "2024-05-29": "D",
- "2024-05-30": "E",
- "2024-05-31": "F",
- "2024-06-03": "A",
- "2024-06-04": "B",
- "2024-06-05": "C",
- "2024-06-06": "D",
- "2024-06-07": "E",
- "2024-06-11": "F",
- "2024-06-12": "A",
- "2024-06-13": "B",
- "2024-06-14": "C",
- "2024-06-17": "D",
- "2024-06-18": "E",
- "2024-06-19": "F",
- "2024-06-20": "A",
- "2024-06-21": "B",
- "2024-06-24": "C",
- "2024-06-25": "D",
- "2024-06-26": "E",
- "2024-06-27": "F"
-}
diff --git a/sendmail-test.py b/sendmail-test.py deleted file mode 100755 index 7d366fb..0000000 --- a/sendmail-test.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 -# -# Send the Daily Bulletin the next morning -# Copyright (C) 2024 Runxi Yu <https://runxiyu.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <https://www.gnu.org/licenses/>. -# - -from __future__ import annotations -from configparser import ConfigParser -from typing import Optional -from pprint import pprint -import datetime -import zoneinfo -import argparse -import os - -import requests -import msal # type: ignore - - -def acquire_token(app: msal.PublicClientApplication, config: ConfigParser) -> str: - result = app.acquire_token_by_username_password( - config["credentials"]["username"], - config["credentials"]["password"], - scopes=config["credentials"]["scope"].split(" "), - ) - - if "access_token" in result: - assert isinstance(result["access_token"], str) - return result["access_token"] - raise ValueError("Authentication error in password login") - - -def sendmail( - token: str, - subject: str, - body: str, - to: list[str], - bcc: list[str], - cc: list[str], - when: Optional[datetime.datetime] = None, - content_type: str = "HTML", - importance: str = "Normal", - reply_to: Optional[str] = None, -) -> str: - data = { - "subject": subject, - "importance": importance, - "body": {"contentType": content_type, "content": body}, - "toRecipients": [{"emailAddress": {"address": a}} for a in to], - "ccRecipients": [{"emailAddress": {"address": a}} for a in cc], - "bccRecipients": [{"emailAddress": {"address": a}} for a in bcc], - } - - if when is not None: - if when.tzinfo is None: - raise TypeError("Naive datetimes are no longer supported") - utcwhen = when.astimezone(datetime.timezone.utc) - isoval = utcwhen.isoformat(timespec="seconds").replace("+00:00", "Z") - data["singleValueExtendedProperties"] = [ - {"id": "SystemTime 0x3FEF", "value": isoval} - ] - - if not reply_to: - response = requests.post( - "https://graph.microsoft.com/v1.0/me/messages", - json=data, - headers={ - "Authorization": "Bearer %s" % token, - "Prefer": 'IdType="ImmutableId"', - }, - timeout=20, - ).json() - else: - response = requests.post( - "https://graph.microsoft.com/v1.0/me/messages/%s/createReply" % reply_to, - json=data, - headers={ - "Authorization": "Bearer %s" % token, - "Prefer": 'IdType="ImmutableId"', - }, - timeout=20, - ).json() - - try: - msgid = response["id"] - except KeyError: - pprint(response) - raise ValueError("Unable to add email to drafts") - - assert isinstance(msgid, str) - - response2 = requests.post( - "https://graph.microsoft.com/v1.0/me/messages/%s/send" % msgid, - headers={"Authorization": "Bearer " + token}, - timeout=20, - ) - - if response2.status_code != 202: - pprint(response2.content.decode("utf-8", "replace")) - raise ValueError( - "Graph response to messages/%s/send returned something other than 202 Accepted" - % response["id"], - ) - - return msgid - - -def main() -> None: - parser = argparse.ArgumentParser(description="Daily Bulletin Sender") - parser.add_argument( - "-d", - "--date", - default=None, - help="the date of the bulletin to send, in local time, in YYYY-MM-DD; defaults to tomorrow", - ) - parser.add_argument( - "-r", - "--reply", - action="store_true", - help="Reply to the previous bulletin when sending (BROKEN)", - ) - parser.add_argument( - "--config", default="config.ini", help="path to the configuration file" - ) - args = parser.parse_args() - config = ConfigParser() - config.read(args.config) - if args.date: - date = datetime.datetime.strptime(args.date, "%Y-%m-%d").replace( - tzinfo=zoneinfo.ZoneInfo(config["general"]["timezone"]) - ) - else: - date = datetime.datetime.now( - zoneinfo.ZoneInfo(config["general"]["timezone"]) - ) + datetime.timedelta(days=1) - - os.chdir(config["general"]["build_path"]) - - html_filename = "sjdb-%s.html" % date.strftime("%Y%m%d") - with open(html_filename, "r", encoding="utf-8") as html_fd: - html = html_fd.read() - - app = msal.PublicClientApplication( - config["credentials"]["client_id"], - authority=config["credentials"]["authority"], - ) - token = acquire_token(app, config) - - if not args.reply: - a = sendmail( - token, - subject=config["sendmail"]["subject_format"] - % date.strftime(config["sendmail"]["subject_date_format"]), - body=html, - to=config["sendmail"]["to_1"].split(" "), - cc=[], - bcc=["s22537@ykpaoschool.cn"], - when=date.replace( - hour=17, - minute=20, - second=0, - microsecond=0, - ), - content_type="HTML", - importance="Normal", - ) - assert a - with open("last-a.txt", "w") as fd: - fd.write(a) - b = sendmail( - token, - subject=config["sendmail"]["subject_format"] - % date.strftime(config["sendmail"]["subject_date_format"]), - body=html, - to=config["sendmail"]["to_2"].split(" "), - cc=[], - bcc=["s22537@ykpaoschool.cn"], - when=date.replace( - hour=17, - minute=20, - second=0, - microsecond=0, - ), - content_type="HTML", - importance="Normal", - ) - assert b - with open("last-b.txt", "w") as fd: - fd.write(b) - else: - with open("last-a.txt", "r") as fd: - last_a = fd.read().strip() - a = sendmail( - token, - subject=config["sendmail"]["subject_format"] - % date.strftime(config["sendmail"]["subject_date_format"]), - body=html, - to=config["sendmail"]["to_1"].split(" "), - cc=[], - bcc=["s22537@ykpaoschool.cn"], - when=date.replace( - hour=17, - minute=20, - second=0, - microsecond=0, - ), - content_type="HTML", - importance="Normal", - reply_to=last_a, - ) - assert a - with open("last-a.txt", "w") as fd: - fd.write(a) - with open("last-b.txt", "r") as fd: - last_b = fd.read().strip() - b = sendmail( - token, - subject=config["sendmail"]["subject_format"] - % date.strftime(config["sendmail"]["subject_date_format"]), - body=html, - to=config["sendmail"]["to_2"].split(" "), - cc=[], - bcc=["s22537@ykpaoschool.cn"], - when=date.replace( - hour=17, - minute=20, - second=0, - microsecond=0, - ), - content_type="HTML", - importance="Normal", - reply_to=last_b, - ) - assert b - with open("last-b.txt", "w") as fd: - fd.write(b) - - -if __name__ == "__main__": - main() diff --git a/daily.py b/sjdbmk/daily.py index ce21bce..ce21bce 100755..100644 --- a/daily.py +++ b/sjdbmk/daily.py diff --git a/grant.py b/sjdbmk/grant.py index d55d9d6..d55d9d6 100755..100644 --- a/grant.py +++ b/sjdbmk/grant.py diff --git a/inspire_approve.py b/sjdbmk/inspire_approve.py index 98d202c..98d202c 100755..100644 --- a/inspire_approve.py +++ b/sjdbmk/inspire_approve.py diff --git a/inspire_dl.py b/sjdbmk/inspire_dl.py index 631ea44..631ea44 100755..100644 --- a/inspire_dl.py +++ b/sjdbmk/inspire_dl.py diff --git a/legacy_wikipedia.py b/sjdbmk/legacy_wikipedia.py index c2f60a1..c2f60a1 100755..100644 --- a/legacy_wikipedia.py +++ b/sjdbmk/legacy_wikipedia.py diff --git a/menuparser.py b/sjdbmk/menuparser.py index 71b7f6f..7413ff0 100644 --- a/menuparser.py +++ b/sjdbmk/menuparser.py @@ -17,10 +17,11 @@ # along with this program. If not, see <https://www.gnu.org/licenses/>. # -import openpyxl from typing import Optional, Any +import openpyxl + def menu_item_fix(s: str) -> Optional[str]: if not s: @@ -88,7 +89,7 @@ def parse_menus(filename: str) -> dict[str, dict[str, dict[str, list[str]]]]: row = rows[i] if not isinstance(row[1].value, str): continue - elif "BREAKFAST" in row[1].value: + if "BREAKFAST" in row[1].value: final["Breakfast"] = parse_meal_table( rows, i, diff --git a/msal_skeleton.py b/sjdbmk/msal_skeleton.py index 3261341..3261341 100755..100644 --- a/msal_skeleton.py +++ b/sjdbmk/msal_skeleton.py diff --git a/pack.py b/sjdbmk/pack.py index 902e256..902e256 100755..100644 --- a/pack.py +++ b/sjdbmk/pack.py diff --git a/sendmail.py b/sjdbmk/sendmail.py index c118c77..ddd6f32 100755..100644 --- a/sendmail.py +++ b/sjdbmk/sendmail.py @@ -30,6 +30,11 @@ import requests import msal # type: ignore +def open_and_readlines(filename: str) -> list[str]: + with open(filename, "r") as fd: + return fd.readlines() + + def acquire_token(app: msal.PublicClientApplication, config: ConfigParser) -> str: result = app.acquire_token_by_username_password( config["credentials"]["username"], @@ -96,9 +101,9 @@ def sendmail( try: msgid = response["id"] - except KeyError: + except KeyError as exc: pprint(response) - raise ValueError("Unable to add email to drafts") + raise ValueError("Unable to add email to drafts") from exc assert isinstance(msgid, str) @@ -169,7 +174,7 @@ def main() -> None: cc=config["sendmail"]["cc_1"].split(" "), bcc=[ w.strip() - for w in open(config["sendmail"]["bcc_1_file"], "r").readlines() + for w in open_and_readlines(config["sendmail"]["bcc_1_file"]) if w.strip() ], when=date.replace( @@ -193,7 +198,7 @@ def main() -> None: cc=config["sendmail"]["cc_2"].split(" "), bcc=[ w.strip() - for w in open(config["sendmail"]["bcc_2_file"], "r").readlines() + for w in open_and_readlines(config["sendmail"]["bcc_2_file"]) if w.strip() ], when=date.replace( @@ -220,7 +225,7 @@ def main() -> None: cc=config["sendmail"]["cc_1"].split(" "), bcc=[ w.strip() - for w in open(config["sendmail"]["bcc_1_file"], "r").readlines() + for w in open_and_readlines(config["sendmail"]["bcc_1_file"]) if w.strip() ], when=date.replace( @@ -247,7 +252,7 @@ def main() -> None: cc=config["sendmail"]["cc_2"].split(" "), bcc=[ w.strip() - for w in open(config["sendmail"]["bcc_2_file"], "r").readlines() + for w in open_and_readlines(config["sendmail"]["bcc_2_file"]) if w.strip() ], when=date.replace( diff --git a/sendmail2.py b/sjdbmk/sendmail2.py index 6cfda8c..6cfda8c 100644 --- a/sendmail2.py +++ b/sjdbmk/sendmail2.py diff --git a/serve.py b/sjdbmk/serve.py index 492e443..492e443 100755..100644 --- a/serve.py +++ b/sjdbmk/serve.py diff --git a/weekly.py b/sjdbmk/weekly.py index 3923aa8..9c0a0c9 100755..100644 --- a/weekly.py +++ b/sjdbmk/weekly.py @@ -55,18 +55,6 @@ import menuparser logger = logging.getLogger(__name__) -class MealTableShapeError(ValueError): - pass - - -def zero_list(lt: list[Any]) -> list[Any]: - return [(zero_list(i) if (isinstance(i, list)) else "") for i in lt] - - -def equal_shapes(a: list[Any], b: list[Any]) -> bool: - return zero_list(a) == zero_list(b) - - def generate( datetime_target: datetime.datetime, # expected to be local time the_week_ahead_url: str, @@ -130,7 +118,7 @@ def generate( logger.info("The Week Ahead already exists at %s" % the_week_ahead_filename) menu_filename = "menu-%s.xlsx" % datetime_target.strftime("%Y%m%d") - if not (os.path.isfile(menu_filename)): + if not os.path.isfile(menu_filename): logger.info("Menu not found, downloading") download_menu( token, @@ -489,8 +477,8 @@ def download_menu( matched_groups[0], "%b" # issues here are probably locales ).month subject_1st_day = int(matched_groups[1]) - except ValueError: - raise ValueError(hit["resource"]["subject"], matched_groups[0]) + except ValueError as exc: + raise ValueError(hit["resource"]["subject"], matched_groups[0]) from exc if ( subject_1st_month == datetime_target.month and subject_1st_day == datetime_target.day @@ -519,6 +507,7 @@ def download_menu( with open(menu_filename, "wb") as w: w.write(pb) + break else: raise ValueError("No proper attachment found in email") |