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

361 lines
12 KiB
Python
Raw Normal View History

__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
import MySQLdb as mysql
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))
self.handler.append(MRegexHandler("Peter evenementen info",
self.info_callback))
self.handler.append(MRegexHandler("Peter evenementen chat",
self.chat_callback))
self.handler.append(MRegexHandler("Peter evenementen deelnemers",
self.participants_callback))
# 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 connect_database(self):
# Connect to database
return mysql.connect(
user = self.config['database_credentials']['username'],
password = self.config['database_credentials']['password'],
database = self.config['database_credentials']['database'],
host = self.config['database_credentials']['host'])
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.
"""
mysql_db = self.connect_database()
mysql_cursor = mysql_db.cursor()
# Grab all events from database that start in the future
select_sql = """SELECT dat_id, dat_cat_id,
dat_headline, dat_begin, dat_end
FROM adm_dates
WHERE dat_begin >'{}'""".format(
dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
mysql_cursor.execute(select_sql)
# Fetch events
results = mysql_cursor.fetchall()
# 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
for row in results:
# First, check if a message on this event was already sent
sqlite_cursor.execute(select_sql.format(row[0]))
if sqlite_cursor.fetchall():
# Do nothing. This event was already processed
pass
else:
# This appears to be a new event. Process it!
# Generate links
base_date_url = "{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/")
view_link = "{}dates.php?id={}&view_mode=html&"
view_link += "view=detail&headline={}"
view_link = view_link.format(base_date_url, row[0], row[2])
function_link = "{}dates_function.php?mode={}&dat_id={}&"
attend_link = function_link.format(base_date_url, '3', row[0])
maybe_link = function_link.format(base_date_url, '7', row[0])
cancel_link = function_link.format(base_date_url, '4', row[0])
# First, write to SQLite database that it is processed
sqlite_cursor.execute(
insert_sql, {
'dat_id':row[0],
'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 row[1] 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(
row[3].strftime("%d-%m-%Y"),
row[3].strftime("%H:%M"),
row[2],
view_link,
attend_link,
maybe_link,
cancel_link))
# Commit and close queries
sqlite_db.commit()
sqlite_db.close()
# Close MySQL
mysql_db.close()
# Sleep
time.sleep(self.config['update_time_span'] * 60)
def list_callback(self, room, event):
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;
attend_link = function_link.format(base_date_url, '3', event.id)
html_message += "<li>"
html_message += self.messages['list_event_item'].format(
event.start_time.strftime("%d-%m-%Y"),
event.start_time.strftime("%H:%M"),
event.name,
event.id,
attend_link)
html_message += "</li>"
html_message += "</ul>"
# Send message
room.send_html(html_message)
def info_callback(self, room, event):
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:
date_url = "{}{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/dates.php?id=",
self.adm.events[id_event].id)
html_message = self.messages['info_event'].format(
date_url,
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)
# Send message
room.send_html(html_message)
except KeyError:
room.send_html(self.messages['unknown_event'])
def participants_callback(self, room, event):
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()