Start version control for Frokostbot

Including a roadmap, which also acts as sort of a TODO.

At this point, the MVP is successfully running.
This commit is contained in:
Mikkel Munch Mortensen 2023-03-03 14:44:57 +01:00
commit 8d49e24ed3
4 changed files with 195 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
.env
frokostbot.sh

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
browser-cookie3==0.17.0
requests==2.28.2

20
roadmap.md Normal file
View file

@ -0,0 +1,20 @@
# Frokostbot Roadmap
## Release an MVP that post today's menu to Slack.
Requirements:
[x] Extract menu from SharePoint.
[x] Process menu to improve presentation with emojis.
[x] Post menu to Slack.
## Improve the post by including a photo of the menu.
Requirements:
[ ] Ask Google Translate to translate menu from Danish to English.
[ ] Ask Crayion to generate images of the menu in English.
[ ] Include a random image from the Crayion results as an attachment in
the Slack post.
## Improve the post with an extended description.
Requirements:
[ ] Ask ChatGPT (or similar service) to provide a ~50 word, mouthwatering
presentation of today's menu.
[ ] Include the presentation in the Slack post.

171
slack.py Normal file
View file

@ -0,0 +1,171 @@
"""
Post today's menu to Slack.
This is done by parsing the JSON data from SharePoint.
"""
import datetime
import json
import os
import sys
import random
from urllib import error, parse, request
import browser_cookie3
import requests
# Load configuration.
try:
IS_LIVE = bool(os.environ.get("IS_LIVE"))
SLACK_ERROR_HOOK = os.environ["SLACK_ERROR_HOOK"]
SLACK_SUCCESS_HOOK = (
os.environ["SLACK_SUCCESS_HOOK"] if IS_LIVE else SLACK_ERROR_HOOK
)
SHAREPOINT_URL = os.environ["SHAREPOINT_URL"]
MENU_URL = os.environ["MENU_URL"]
except KeyError as e:
sys.stderr.write(f"Unable to load configuration for {e}.\n")
sys.exit(1)
sys.stdout.write("Configuration loaded.\n")
# Set up and execute request to SharePoint.
cookies = browser_cookie3.firefox(
domain_name="sharepoint.com"
)
headers = {
"Accept": "application/json;odata=verbose",
"Content-Type": "application/json;odata=verbose",
}
request_data = {
"parameters": {
"__metadata": {
"type": "SP.RenderListDataParameters"
},
"AddRequiredFields": True,
"AllowMultipleValueFilterForTaxonomyFields": True,
"FilterOutChannelFoldersInDefaultDocLib": True,
"RenderOptions": 5707271,
}
}
response = requests.post(
SHAREPOINT_URL,
headers=headers,
cookies=cookies,
json=request_data,
)
data = response.json()
sys.stdout.write("Data retrieved from SharePoint.\n")
# Extract today's menu from the SharePoint data.
today = datetime.date.today().strftime("%d-%m-%Y")
menu = None
if "error" in data:
message = plain_message = f"Error: {data['error']['message']['value']}"
hook_url = SLACK_ERROR_HOOK
sys.stderr.write(f"SharePoint {message}\n")
else:
hook_url = SLACK_SUCCESS_HOOK
for entry in data["ListData"]["Row"]:
if entry.get("DAto") == today:
menu = entry
break
if menu is None:
sys.stderr.write("Unable to find the menu of today :(\n")
sys.exit(1)
menu = menu["Menutekst"]
sys.stdout.write(f"The menu of today ({today}) is: {menu}\n")
# Determine appropriate emojis for the menu.
emojis = []
for emoji, keywords in {
"flag-in": ["indisk", "indien"],
"hamburger": ["burger"],
"fish": ["fisk", "laks", "rødspætte", "sej "],
"shrimp": ["reje"],
"pig2": ["skinke", "gris"],
"cow": ["hakkebøf"],
"cow2": ["kalv", "okse"],
"chicken": ["kylling", "chicken"],
"turkey": ["kalkun"],
"rabbit2": [" hare"],
"rooster": ["coq au vin"],
"falafel": ["falafel"],
"hot_pepper": ["chili", "hot sauce"],
"onion": ["løg"],
"mango": ["mango"],
"mushroom": ["svampe", "kantarel", "champignon"],
"beans": ["bønne"],
"sandwich": ["sandwich"],
"stuffed_flatbread": ["pita"],
"pie": ["tærte"],
"hotdog": ["hotdog"],
"wine_glass": ["coq au vin"],
"bowl_with_spoon": ["suppe"],
"stew": ["gryde", "gullasch"],
"rice": [" ris", "ris "],
"ramen": ["nudler"],
"cloud": ["sky"],
"potato": ["kartoffel", "kartofler"],
"apple": ["æble"],
"baguette_bread": ["flute"],
"flag-dk": ["tillykke", "fødselsdag"],
"wave": ["farvel"],
"gift_heart": ["valentines"],
}.items():
for keyword in keywords:
if keyword in menu.lower():
emojis.append(emoji)
break
if emojis:
emojis = f":{': :'.join(emojis)}:"
sys.stdout.write(f"Emojis determined: {emojis}\n")
else:
emojis = ""
sys.stdout.write("No emojis determined.\n")
# Pick an introduction for the menu.
introduction = random.choice([
"Dagens menu er",
"I dag forkæler kantinen os med",
"Du kan godt glæde dig til senere! For vi skal have",
"Der bliver knoklet i køkkenet for at blive klar til at servere",
"Klokken 11:30 har kantinen fremtryllet en lækker omgang",
])
sys.stdout.write(f"Introduction picked: {introduction}\n")
# Compose message for Slack.
plain_message = f"{introduction} {menu}"
menu_url = MENU_URL
message = f"{introduction} {emojis} <{menu_url}|*{menu}*>".strip()
payload = {
"text": plain_message,
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": message,
},
},
],
}
sys.stdout.write("Posting menu to Slack...\n")
hook = request.Request(
hook_url,
data=json.dumps(payload).encode("utf-8"),
headers={
"Content-Type": "application/json",
},
method="POST",
)
try:
response = request.urlopen(hook)
except error.HTTPError as e:
sys.stderr.write(f"{e}\n")
sys.exit(1)
sys.stdout.write("Done :)\n")