first commit
This commit is contained in:
commit
3942e95765
52
README.md
Normal file
52
README.md
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
# Discord cardiParty webhook
|
||||||
|
|
||||||
|
This is a simple webhook to push new cardiParties into the cardiParty channel.
|
||||||
|
|
||||||
|
## install
|
||||||
|
|
||||||
|
1. Create and activate [virtual env](https://docs.python.org/3/library/venv.html)
|
||||||
|
2. Install requirements: `pip install -r requirements.txt`
|
||||||
|
3. Set up a cronjob
|
||||||
|
1. set the env values (see below)
|
||||||
|
2. set a time to run e.g. every 30 mins
|
||||||
|
3. set the command listed below under "Cron job command"
|
||||||
|
4. Test cronjob works
|
||||||
|
5. Relax
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
We run this on the newcardigan wordpress server.
|
||||||
|
|
||||||
|
1. With a cron job we call the civiCRM API use `cv` to grab the details of the latest cardiParty
|
||||||
|
2. We pipe that string into a python script
|
||||||
|
3. The script checks a custom RSS feed for new parties
|
||||||
|
4. If no new party, end
|
||||||
|
5. If new party,
|
||||||
|
1. save the guid to `latest_post.txt` for the next round of checking
|
||||||
|
2. use the image and title from the RSS feed and the details from the cv API call
|
||||||
|
3. publish via a webhook to Discord
|
||||||
|
|
||||||
|
## env values
|
||||||
|
|
||||||
|
We need to include some secrets via environment values:
|
||||||
|
|
||||||
|
**channel** is the channel ID (`DISCORD_CHANNEL`)
|
||||||
|
**token** is the secret token for the webhook (`DISCORD_TOKEN`)
|
||||||
|
**cardiparty_ping** is the ID of the `@cardiParty ping` role (`DISCORD_CARDIPARTY_PING`)
|
||||||
|
|
||||||
|
## Cron job command
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cv api4 Event.get '{"select":["title","address.city","start_date","summary"],"join":[["Address AS address","LEFT",["loc_block_id.address_id","=","address.id"]]],"orderBy":{"start_date":"DESC"},"limit":1}' | ./webhook.py
|
||||||
|
```
|
||||||
|
This should pipe a string like this into the script:
|
||||||
|
|
||||||
|
```
|
||||||
|
[{"id":108,"title":"Melbourne Art Library","address.city":"Melbourne","start_date":"2024-04-06 16:30:00","summary":"Melbourne Art Library (MAL) is a not-for-profit lending library that collects specialised art and design texts. They are proudly independent and are curious about what being a 'library' means."}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## RSS feed
|
||||||
|
|
||||||
|
The rss feed is `https://newcardigan.org/category/cardiparties/?feed=cardipartyfeed`.
|
||||||
|
|
||||||
|
This special `cardipartyfeed` is a slightly modified RSS2 feed. The only thing it does differently is include the featured image in an `enclosure` so that we can pick it up directly from the feed. See the newcardigan WordPress theme for how this works.
|
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# lazy request list ;)
|
||||||
|
feedparser
|
||||||
|
requests
|
60
webhook.py
Executable file
60
webhook.py
Executable file
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import feedparser
|
||||||
|
import requests
|
||||||
|
|
||||||
|
channel = os.getenv("DISCORD_CHANNEL")
|
||||||
|
token = os.getenv("DISCORD_TOKEN")
|
||||||
|
cardiparty_ping = os.getenv("DISCORD_CARDIPARTY_PING")
|
||||||
|
|
||||||
|
# get the latest cardiparty with image as enclosure
|
||||||
|
f = feedparser.parse("https://newcardigan.org/category/cardiparties/?feed=cardipartyfeed")
|
||||||
|
first = f.entries[0]
|
||||||
|
# check whether we have already seen this entry
|
||||||
|
with open("latest_post.txt", "r+") as f:
|
||||||
|
guid = f.read().strip()
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
if guid != first.guid:
|
||||||
|
# update the guid
|
||||||
|
with open("latest_post.txt", "w+") as f:
|
||||||
|
f.write(first.guid)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
api_response = sys.stdin.read() # read the API call output that was piped in
|
||||||
|
api_data = json.loads(api_response)[0]
|
||||||
|
|
||||||
|
title = api_data["title"]
|
||||||
|
city = api_data["address.city"]
|
||||||
|
start_date = api_data["start_date"]
|
||||||
|
summary = api_data["summary"]
|
||||||
|
start_date = datetime.fromisoformat(start_date).astimezone().strftime(
|
||||||
|
"%I:%M%p %a %d %b %Y"
|
||||||
|
).strip("0") # remove time zero padding if any
|
||||||
|
|
||||||
|
content = f"[<:newCardigan:1280097925149626419> **{title}**]({first.link})\n_{city}_\n_{start_date}_\n\n{summary}\n\n<@&{cardiparty_ping}>"
|
||||||
|
embeds = [{
|
||||||
|
"title": "Find out more and register!",
|
||||||
|
"url": first.link,
|
||||||
|
"color": 16741516,
|
||||||
|
"image": {
|
||||||
|
"url": first.enclosures[0].href
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
|
||||||
|
headers = {'user-agent': 'cardiParty-discord-bot/1.0.0'}
|
||||||
|
url = f"https://discord.com/api/webhooks/{channel}/{token}"
|
||||||
|
payload = {
|
||||||
|
"thread_name": f"{first.title} | {title}",
|
||||||
|
"content": content,
|
||||||
|
"embeds": embeds,
|
||||||
|
"allowed_mentions": { "roles": [cardiparty_ping] }
|
||||||
|
}
|
||||||
|
|
||||||
|
r = requests.post(url, json=payload, headers=headers)
|
||||||
|
r.raise_for_status() # if we got a 4xx response this will log it out
|
Loading…
Reference in a new issue