plugable-matrix-bot/plugins/admidio_events/admidio_events.py

374 lines
12 KiB
Python

__author__ = "Dennis Potter"
__copyright__ = "Copyright 2019, Dennis Potter"
__credits__ = ["Dennis Potter"]
__license__ = "GPL-3.0"
__version__ = "0.5.0"
__maintainer__ = "Dennis Potter"
__email__ = "dennis@dennispotter.eu"
import os
import hjson
import time
import sqlite3
import threading
import importlib
import sys
import datetime as dt
from matrix_bot_api.mregex_handler import MRegexHandler
sys.path.insert(0, os.path.dirname(__file__))
import admidio_python_api.admidio as admidio
import admidio_python_api.group as group
MESSAGES_DIR = os.path.join(os.path.dirname(__file__), 'messages')
DATA_DIR = os.path.join(os.path.dirname(__file__),'../../data/events')
CONFIG_LOCATION = os.path.join(os.path.dirname(__file__), 'config.hjson')
DATA_LOCATION = DATA_DIR + '/data.db'
HELP_LOCATION = MESSAGES_DIR + '/help'
MESSAGES_LOCATION = MESSAGES_DIR + '/messages.dutch.hjson'
class Plugin:
""" This plugin grabs events from Admidio (https://admidio.org)
and lets users interact with the data
"""
def __init__(self, bot):
# Load the configuration
with open(CONFIG_LOCATION) as hjson_data:
self.config = hjson.load(hjson_data)
# Load all messages for this plugin
with open(MESSAGES_LOCATION) as hjson_data:
self.messages = hjson.load(hjson_data)
self.adm = admidio.Admidio(
self.config['database_credentials']['host'],
self.config['database_credentials']['username'],
self.config['database_credentials']['password'],
self.config['database_credentials']['database'],
self.config['database_credentials']['adm_prefix'])
# Define sensitivity
self.handler = []
self.handler.append(MRegexHandler(
"Peter evenementen lijst",
self.list_callback,
bot))
self.handler.append(MRegexHandler(
"Peter evenementen info",
self.info_callback,
bot))
self.handler.append(MRegexHandler(
"Peter evenementen chat",
self.chat_callback,
bot))
self.handler.append(MRegexHandler(
"Peter evenementen deelnemers",
self.participants_callback,
bot))
# Save parent bot
self.bot = bot
# Start thread to check events
self.event_thread = threading.Thread(target=self.check_new_event_thread)
self.event_thread.start()
def ready_block(self):
while (not self.adm.ready):
time.sleep(1)
def check_new_event_thread(self):
while not self.bot.cancel:
self.check_new_event()
def check_new_event(self):
""" Check every <X> minutes for new events in the database.
Since the check will only be performed every <X> minutes, the
connection to the database will not be kept open.
As soon as an event is posted to the defined room, its ID is
saved in an SQLite database.
"""
# Refresh everything
self.adm.refresh()
# Open SQLite database
sqlite_db = sqlite3.connect(DATA_LOCATION)
sqlite_cursor = sqlite_db.cursor()
# Define query to SELECT event from SQLite DB
select_sql = """SELECT dat_id
FROM events
WHERE dat_id = {}"""
insert_sql = """INSERT INTO events(dat_id, datetime_posted)
VALUES(:dat_id, :datetime_posted)"""
# Loop through event
now = dt.datetime.now()
events = (x for (k,x) in self.adm.events.items() if x.start_time > now)
for (i, event) in enumerate(events):
# First, check if a message on this event was already sent
sqlite_cursor.execute(select_sql.format(event.id))
if sqlite_cursor.fetchall():
# Do nothing. This event was already processed
pass
else:
# This appears to be a new event. Process it!
# Generate links
links = self.generate_links(event.id, event.name)
# First, write to SQLite database that it is processed
sqlite_cursor.execute(
insert_sql, {
'dat_id':event.id,
'datetime_posted':
dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")})
# Check role ID of event and check if config defines
# where it should be shared.
for mapping in self.config['cat_id_room_mapping']:
if event.cat_id in mapping[0]:
# We got a winner!
for i, room in self.bot.client.rooms.items():
if room.display_name in mapping[1]:
room.send_html(
self.messages["new_event"].format(
event.start_time.strftime("%d-%m-%Y"),
event.start_time.strftime("%H:%M"),
event.name,
links['view'],
links['attend'],
links['maybe'],
links['cancel']))
# Commit and close queries
sqlite_db.commit()
sqlite_db.close()
# Sleep
time.sleep(self.config['update_time_span'] * 60)
def generate_links(self, event_id, event_name):
links = dict()
# Define the base URL for users to attend
base_dat_url = "{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/")
links['view'] = "{}dates.php?id={}&view_mode=html&"
links['view'] += "view=detail&headline={}"
links['view'] = links['view'].format(base_dat_url, event_id, event_name)
function_link = "{}dates_function.php?mode={}&dat_id={}&"
links['attend'] = function_link.format(base_dat_url, '3', event_id)
links['maybe'] = function_link.format(base_dat_url, '7', event_id)
links['cancel'] = function_link.format(base_dat_url, '4', event_id)
return links
def list_callback(self, room, event):
self.ready_block()
number_events = False
for word in event['content']['body'].split():
try:
number_events = int(word)
break
except:
pass
if not number_events:
number_events = 10
elif number_events <= 0 or number_events > 100:
room.send_text(self.messages['list_event_num_err'])
number_events = 10
base_date_url = "{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/")
function_link = "{}dates_function.php?mode={}&dat_id={}&"
now = dt.datetime.now()
events = (x for (k,x) in self.adm.events.items() if x.start_time > now)
# Set header
html_message = self.messages['list_events_head'].format(number_events)
# Loop through fetched events
html_message += "<br /><ul>"
for (i, event) in enumerate(events):
if (i >= number_events):
break;
# Generate links
links = self.generate_links(event.id, event.name)
html_message += "<li>"
html_message += self.messages['list_event_item'].format(
event.start_time.strftime("%d-%m-%Y"),
event.start_time.strftime("%H:%M"),
links['view'],
event.name,
event.id)
html_message += "</li>"
html_message += "</ul>"
# Send message
room.send_html(html_message)
def info_callback(self, room, event):
self.ready_block()
id_event = False
for word in event['content']['body'].split():
try:
id_event = int(word)
break
except:
pass
if not id_event or id_event < 0:
room.send_html(self.messages['info_event_id_err'])
return
try:
# Generate links
links = self.generate_links(
self.adm.events[id_event].id,
self.adm.events[id_event].name)
# Assemble message
html_message = self.messages['info_event'].format(
links['view'],
self.adm.events[id_event].name,
self.adm.events[id_event].start_time.strftime("%d-%m-%Y"),
self.adm.events[id_event].start_time.strftime("%H:%M"),
self.adm.events[id_event].end_time.strftime("%d-%m-%Y"),
self.adm.events[id_event].end_time.strftime("%H:%M"),
self.adm.events[id_event].description,
links['attend'],
links['maybe'],
links['cancel'])
# Send message
room.send_html(html_message)
except KeyError:
room.send_html(self.messages['unknown_event'])
def participants_callback(self, room, event):
self.ready_block()
id_event = False
for word in event['content']['body'].split():
try:
id_event = int(word)
break
except:
pass
if not id_event or id_event < 0:
room.send_html(self.messages['info_event_id_err'])
return
try:
# Set header
html_message = self.messages['event_participants_head'].format(
len(self.adm.events[id_event].getAllAttend()),
self.adm.events[id_event].number_of_guests,
self.adm.events[id_event].name)
# Attend
html_message += "<br />"
html_message += self.messages['event_participants_attend'];
# Loop through fetched participants
html_message += "<ul>"
for member in self.adm.events[id_event].getAllAttend():
html_message += "<li>"
html_message += member[1].username
html_message += "</li>"
html_message += "</ul>"
# Maybe
html_message += self.messages['event_participants_maybe'];
# Loop through fetched participants
html_message += "<ul>"
for member in self.adm.events[id_event].getAllMaybe():
html_message += "<li>"
html_message += member[1].username
html_message += "</li>"
html_message += "</ul>"
# Not attend
html_message += self.messages['event_participants_not_attend'];
# Loop through fetched participants
html_message += "<ul>"
for member in self.adm.events[id_event].getAllNotAttend():
html_message += "<li>"
html_message += member[1].username
html_message += "</li>"
html_message += "</ul>"
room.send_html(html_message)
except KeyError:
room.send_html(self.messages['unknown_event'])
def chat_callback(self, room, event):
room.send_text("Chat")
def help(self):
return open(HELP_LOCATION, mode="r").read()
def setup():
"""This function runs only, ever. It initializes the necessary
SQLite tables."""
# Try to make a new directory
os.mkdir(DATA_DIR)
# Define query to INSERT event table to SQLite DB
sql = """CREATE TABLE 'events' (
'dat_id' integer,
'datetime_posted' datetime);"""
# Open, execute, commit, and close SQLite database
sqlite_db = sqlite3.connect(DATA_LOCATION)
sqlite_cursor = sqlite_db.cursor()
sqlite_cursor.execute(sql)
sqlite_db.commit()
sqlite_db.close()