refactored into python3 script for discourse api
This commit is contained in:
parent
0fecad10ad
commit
d204f74d82
7 changed files with 148 additions and 105 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
invite.conf
|
16
README.md
16
README.md
|
@ -1,26 +1,18 @@
|
|||
# Einladung zum Plenum des Hackspace Jena e.V.
|
||||
|
||||
Das Repository enthält Dateien zum automatischen Versenden von Einladungsmails
|
||||
für das Plenum.
|
||||
Das Repository enthält Dateien zum automatischen Versenden von Einladungsmails für das Plenum.
|
||||
|
||||
Das Shellskript ermittelt den kommenden Donnerstag, prüft, ob es ein erster
|
||||
Donnerstag des Monats ist, und bricht sonst ab, ersetzt im Einladungstext (Datei
|
||||
`email_text`) Platzhalter mit dem Datum des kommenden Donnerstag und verschickt
|
||||
den Text als E-Mail.
|
||||
|
||||
Die Service- und Timer-Dateien lassen systemd das Skript einmal wöchentlich
|
||||
ausführen.
|
||||
Die Service- und Timer-Dateien lassen systemd das Skript einmal monatlich ausführen.
|
||||
|
||||
# Installation
|
||||
|
||||
Dieses Repository muss nach `/opt` in das Verzeichnis `plenumsinvite` kopiert
|
||||
werden:
|
||||
Dieses Repository soll nach `/opt` in das Verzeichnis `plenumsinvite` kopiert werden:
|
||||
|
||||
```
|
||||
mkdir -p /opt
|
||||
cd /opt
|
||||
git clone https://github.com/HackspaceJena/plenums_invite.git
|
||||
cd /plenums_invite
|
||||
cd plenums_invite
|
||||
```
|
||||
|
||||
Danach müssen die beiden systemd-Unit-Dateien nach `/etc/systemd/system`
|
||||
|
|
22
email_text
22
email_text
|
@ -1,22 +0,0 @@
|
|||
Hallo zusammen,
|
||||
|
||||
am PROSEDATE findet wieder unser monatliches Plenum statt.
|
||||
Wir treffen uns um 20 Uhr im virtuellen Raum unter:
|
||||
|
||||
https://talk.kabi.tk/krautspace
|
||||
|
||||
Für Vorbereitung und Protokoll gibt es wieder ein Pad, bitte
|
||||
tragt schon mal Themen ein, die Ihr gern besprechen würdet:
|
||||
|
||||
https://vereinte.verwirrung.institute/p/ksplenum-URLDATE
|
||||
|
||||
Ggf. muss das Pad erst noch vorbereitet werden, die Vorlage
|
||||
mit Anleitung findet Ihr hier:
|
||||
|
||||
https://vereinte.verwirrung.institute/p/ksplenum-template
|
||||
|
||||
Wir freuen uns auf zahlreiche Teilnehmer:innnen.
|
||||
|
||||
Mit den besten Grüßen,
|
||||
|
||||
das Einladeskript
|
22
invite.ics
22
invite.ics
|
@ -1,22 +0,0 @@
|
|||
BEGIN:VCALENDAR
|
||||
PRODID:-//KrautSpace Jena//KrautSpace Einladescript//DE
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
METHOD:PUBLISH
|
||||
BEGIN:VEVENT
|
||||
DTSTART:#DTSTART#
|
||||
DTEND:#DTEND#
|
||||
DTSTAMP:#DTSTAMP#
|
||||
UID:#DTSTAMP#@kraut.space
|
||||
SUMMARY:#SUMMARY#
|
||||
DESCRIPTION:Wir treffen uns um 20 Uhr im virtuellen Raum unter:\n#LOCATION#\n\nFür Vorbereitung und Protokoll gibt es wieder ein Pad, bitte tragt schon mal Themen ein, die Ihr gern besprechen würdet:\nhttps://vereinte.verwirrung.institute/p/ksplenum-#URLDATE#\n\nGgf. muss das Pad erst noch vorbereitet werden, die Vorlage mit Anleitung findet Ihr hier:\nhttps://vereinte.verwirrung.institute/p/ksplenum-template
|
||||
LOCATION:#LOCATION#
|
||||
ORGANIZER;ROLE=CHAIR;PARTSTAT=ACCEPTED;RSVP=FALSE:mailto:#FROM#
|
||||
CONFERENCE;VALUE=URI:#LOCATION#
|
||||
SEQUENCE:0
|
||||
STATUS:CONFIRMED
|
||||
CLASS:PUBLIC
|
||||
CATEGORIES:Meeting
|
||||
TRANSP:OPAQUE
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
112
invite.py
Executable file
112
invite.py
Executable file
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import configparser
|
||||
import datetime
|
||||
import logging
|
||||
import optparse
|
||||
import requests
|
||||
|
||||
class JsonObject(object):
|
||||
'''An object constructed from a JSON response'''
|
||||
|
||||
def __init__(self, json):
|
||||
self.update_attributes(json)
|
||||
|
||||
def __str__(self):
|
||||
return '{} with ID: {}'.format(self.__class__.__name__, self.id)
|
||||
|
||||
def __repr__(self):
|
||||
vars_string = str(self.__dict__)
|
||||
|
||||
replace = {': ': '=', '{': '', '}': ''}
|
||||
for key in replace:
|
||||
vars_string = vars_string.replace(key, replace[key])
|
||||
|
||||
return '{}({})'.format(self.__class__.__name__, vars_string)
|
||||
|
||||
def update_attributes(self, json):
|
||||
self.__dict__.update(json)
|
||||
|
||||
class Topic(JsonObject):
|
||||
|
||||
def __init__(self, client, **kwargs):
|
||||
self.client = client
|
||||
super().__init__(**kwargs)
|
||||
|
||||
class Client(object):
|
||||
|
||||
def __init__(self, host, api_username='', api_key=''):
|
||||
self.host = host
|
||||
|
||||
self.session = requests.Session()
|
||||
self.session.headers.update({
|
||||
'Api-Username': api_username,
|
||||
'Api-Key': api_key,
|
||||
})
|
||||
|
||||
# Class Methods
|
||||
def _request(self, method, path, params=None, data=None, json=None):
|
||||
response = self.session.request(
|
||||
method=method.upper(),
|
||||
url=requests.compat.urljoin(self.host, path),
|
||||
params=params,
|
||||
data=data,
|
||||
json=json,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
return response.json()
|
||||
|
||||
def create_topic(self, title, raw, category=None):
|
||||
response = self._request('POST', 'posts.json', json={
|
||||
'title': title,
|
||||
'raw': raw,
|
||||
'category': category,
|
||||
})
|
||||
|
||||
return Topic(client=self, json=response)
|
||||
|
||||
def main():
|
||||
op = optparse.OptionParser()
|
||||
op.add_option("-c", "--config", default="invite.conf")
|
||||
op.add_option("-v", "--verbose", action="store_true")
|
||||
options, args = op.parse_args()
|
||||
|
||||
config = configparser.ConfigParser()
|
||||
configfile = options.config
|
||||
if not config.read(configfile):
|
||||
op.error(f"Configuration file '{configfile}' not found or not readable.")
|
||||
|
||||
if options.verbose:
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
|
||||
client = Client(
|
||||
host = config['discourse']['uri'],
|
||||
api_username = config['discourse']['api_username'],
|
||||
api_key = config['discourse']['api_key']
|
||||
)
|
||||
|
||||
now = datetime.date.today()
|
||||
date = now + datetime.timedelta(3 - now.weekday())
|
||||
date_str = date.strftime('%d.%m.%Y')
|
||||
|
||||
subject = f'Einladung zum Plenum am {date_str}'
|
||||
msg_body = '''Hallo zusammen,
|
||||
|
||||
am Donnerstag findet wieder unser monatliches Plenum statt.
|
||||
Wir treffen uns um 20 Uhr im virtuellen Raum unter:
|
||||
|
||||
https://talk.kabi.tk/krautspace
|
||||
|
||||
Antwortet einfach hier auf diesen Post, wenn ihr etwas thematisieren möchtet.
|
||||
Wir freuen uns auf zahlreiche Teilnehmer:innnen.
|
||||
|
||||
Mit den besten Grüßen,
|
||||
|
||||
das Einladeskript'''
|
||||
client.create_topic(title=subject, raw=msg_body, category=7)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
47
invite.sh
47
invite.sh
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
## Configuration
|
||||
|
||||
from="office@krautspace.de"
|
||||
to=("hackspace-jena@lstsrv.org" "krautspace-announce@lstsrv.org")
|
||||
#replyto="hackspace-jena@lstsrv.org"
|
||||
subject="Einladung zum Plenum"
|
||||
location="https://talk.kabi.tk/krautspace"
|
||||
body_file=email_text # Use PROSEDATE for dd.mm.YYYY and URLDATE for YYYmmdd
|
||||
|
||||
## Find next Thursday
|
||||
date_fmt () { date -u -d "$2 next Thu" "$1"; }
|
||||
|
||||
## Check if next Thursday is the first of a month
|
||||
|
||||
if (( $(date_fmt +%_d) > 7 )); then
|
||||
echo "Invitation should be sent at most a week in advance."
|
||||
echo "Exiting without sending an inviation..."
|
||||
exit
|
||||
fi
|
||||
|
||||
## Send invitation
|
||||
|
||||
prose_date=$(date_fmt +%d.%m.%Y)
|
||||
url_date=$(date_fmt +%Y%m%d)
|
||||
|
||||
script_path=$(readlink -f "$0")
|
||||
source_directory=$(dirname "$script_path")
|
||||
|
||||
sed -E \
|
||||
-e "s/#DTSTART#/$(date_fmt +%Y%m%dT%H%M%SZ "TZ=\"Europe/Berlin\" 20:00")/" \
|
||||
-e "s/#DTEND#/$(date_fmt +%Y%m%dT%H%M%SZ "TZ=\"Europe/Berlin\" 21:00")/" \
|
||||
-e "s/#DTSTAMP#/$(date -u +%Y%m%dT%H%M%SZ)/" \
|
||||
-e "s/#SUMMARY#/KrautSpace Plenum/" \
|
||||
-e "s%#LOCATION#%${location}%" \
|
||||
-e "s/#FROM#/${from}/g" \
|
||||
-e "s/#URLDATE#/${url_date}/g" \
|
||||
-e 's/(^[^ ].{73}|.{73})/\1\r\n /g' \
|
||||
"$source_directory/invite.ics" > /tmp/invite.ics
|
||||
|
||||
sed -e "s/PROSEDATE/$prose_date/g" \
|
||||
-e "s/URLDATE/$url_date/g" \
|
||||
"$source_directory/$body_file" | EMAIL="$from" mutt -s "$subject" -a /tmp/invite.ics -- "${to[@]}"
|
||||
ret=$?
|
||||
rm -f /tmp/invite.ics
|
||||
exit $ret
|
|
@ -1,8 +1,37 @@
|
|||
[Unit]
|
||||
Description=Send invitation to Hackspace's Plenum
|
||||
Description=Send invitation to Hackspace's Announce Discourse
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/opt/plenums_invite/invite.sh
|
||||
ExecStart=/opt/plenums_invite/invite.py
|
||||
|
||||
WorkingDirectory=/opt/plenums_invite
|
||||
|
||||
UMask=077
|
||||
#DynamicUser=yes
|
||||
|
||||
PrivateDevices=yes
|
||||
PrivateUsers=yes
|
||||
PrivateTmp=yes
|
||||
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ProtectClock=yes
|
||||
ProtectKernelModules=yes
|
||||
ProtectKernelTunables=yes
|
||||
ProtectControlGroups=yes
|
||||
ProtectKernelLogs=yes
|
||||
ProtectProc=invisible
|
||||
ProcSubset=pid
|
||||
ProtectHostname=yes
|
||||
|
||||
ReadOnlyDirectories=/
|
||||
|
||||
NoNewPrivileges=true
|
||||
CapabilityBoundingSet=
|
||||
MemoryDenyWriteExecute=true
|
||||
RestrictRealtime=true
|
||||
RestrictNamespaces=true
|
||||
SystemCallArchitectures=native
|
||||
LockPersonality=yes
|
||||
RestrictAddressFamilies=AF_INET AF_INET6
|
||||
|
|
Loading…
Reference in a new issue