Created
April 7, 2022 14:16
-
-
Save v1nc/1238b25a41a71e4e10737d2050d46542 to your computer and use it in GitHub Desktop.
Moodle Telegram Notifier
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Telegram Moodle Notificatior | |
Get notifications for moodle events via telegram. | |
""" | |
import sys | |
from datetime import datetime, timedelta, date | |
import requests | |
import icalendar | |
import validators | |
from dateutil.rrule import * | |
from requests.auth import HTTPBasicAuth | |
import json | |
import requests | |
import config | |
TG_BOT_TOKEN = "" # Bot token you get from @botfather | |
TG_CHAT_ID = "-100" # Chat ID of a chat that the bot can write into | |
MOODLE_URL = "" # Your Moodle Calendar URL, exported from e.g. https://moodle.your-domain.de/calendar/export.php? | |
def send(bot_message): | |
""" Send telegram message to chat """ | |
send_text = f"https://api.telegram.org/bot{TG_BOT_TOKEN}/sendMessage?chat_id={TG_CHAT_ID}&disable_web_page_preview=True&parse_mode=Markdown&text={bot_message}" | |
response = requests.get(send_text) | |
return response.json() | |
def verify_url(url): | |
""" Verify a calendar URL """ | |
return validators.url(url) | |
def decode_component(component, component_name): | |
""" Decode a calendar component """ | |
try: | |
return component.decoded(component_name) | |
except KeyError: | |
return None | |
def check_event(component): | |
""" Check if component is a real event """ | |
items = component.property_items() | |
if len(items) > 0 and len(items[0]) > 0: | |
return items[0][1] == b'VEVENT' | |
return False | |
def extract_categories(lines): | |
""" Extract categories from the component manually """ | |
for line in lines: | |
if "CATEGORIES:" in line: | |
return line.split("CATEGORIES:")[1] | |
def decode_event(component): | |
""" Decode entities of a component """ | |
event = {} | |
event["summary"] = decode_component(component,"SUMMARY").decode().strip() | |
event["categories"] = extract_categories(component.content_lines()).strip() | |
event["date"] = decode_component(component, "DTEND").replace(tzinfo=None)+ timedelta(hours=2) | |
event["date_string"] = event["date"].strftime("%H:%M") | |
try: | |
event["uid"] = decode_component(component,"UID").decode() | |
except Exception: | |
event["uid"] = event["summary"]+event["categories"] | |
return event | |
def download_ical(url): | |
""" Download a calendar file from URL """ | |
if not verify_url(url): | |
print("invalid ical url") | |
return False | |
try: | |
response = requests.get(url, allow_redirects=True) | |
gcal = icalendar.Calendar.from_ical(response.content) | |
return gcal | |
except Exception as exception: | |
print(exception) | |
return False | |
# load json about already send messages | |
try: | |
with open('moodle_uids.json') as json_file: | |
send_icals = json.load(json_file) | |
except Exception: | |
send_icals = [] | |
# download calendar file | |
ical_calendar = download_ical(MOODLE_URL) | |
if not ical_calendar: | |
print("error") | |
sys.exit(0) | |
# check all calendar events | |
for component in ical_calendar.walk(): | |
# only check real events | |
if check_event(component): | |
# get event details into array | |
event = decode_event(component) | |
# check if event is tomorrow and not already send | |
today = date.today() | |
tomorrow = date.today() + timedelta(days=1) | |
if not event["uid"] in send_icals and event["date"].date() == tomorrow: | |
# create message string with markdown | |
string = f"*Termin Morgen {event['date_string']} Uhr:*\r\n\r\n{event['categories']}\r\n➡️ *{event['summary']}*" | |
# send telegram message | |
print(send(string)) | |
# save event uid | |
send_icals.append(event["uid"]) | |
# save send message to file | |
with open('moodle_uids.json', 'w') as outfile: | |
json.dump(send_icals, outfile) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment