plugable-matrix-bot/plugins/admidio_events/admidio_events.py
Dennis Potter 06868d67ce
Added info event feature
The bot is now able to return information about a certain event to a room.
2019-01-27 17:58:24 +01:00

306 lines
9.9 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 datetime as dt
import MySQLdb as mysql
from matrix_bot_api.mregex_handler import MRegexHandler
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)
# 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 om %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
datetime_now = dt.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
mysql_db = self.connect_database()
mysql_cursor = mysql_db.cursor()
select_sql = f"""SELECT dat_id, dat_cat_id,
dat_headline, dat_begin, dat_end
FROM adm_dates
WHERE dat_begin >'{datetime_now}'
ORDER BY dat_begin
LIMIT {number_events}"""
mysql_cursor.execute(select_sql)
# Fetch events
results = mysql_cursor.fetchall()
# Set header
html_message = self.messages['list_events_head'].format(number_events)
# Loop through fetched events
html_message += "<br /><ul>"
for row in results:
base_date_url = "{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/")
function_link = "{}dates_function.php?mode={}&dat_id={}&"
attend_link = function_link.format(base_date_url, '3', row[0])
html_message += "<li>"
html_message += self.messages['list_event_item'].format(
row[3].strftime("%d-%m-%Y om %H:%M"),
row[2],
row[0],
attend_link)
html_message += "</li>"
html_message += "</ul>"
# Send message
room.send_html(html_message)
# Close DB connection
mysql_db.close()
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
mysql_db = self.connect_database()
mysql_cursor = mysql_db.cursor()
select_sql = f"""SELECT dat_id, dat_headline, dat_description,
dat_begin, dat_end
FROM adm_dates
WHERE dat_id = {id_event}"""
mysql_cursor.execute(select_sql)
# Fetch events
row = mysql_cursor.fetchall()
date_url = "{}{}{}".format(
self.config['base_url_adm'],
"/adm_program/modules/dates/dates.php?id=",
row[0][0])
html_message = self.messages['info_event'].format(
date_url,
row[0][1],
row[0][3].strftime("%d-%m-%Y om %H:%M"),
row[0][4].strftime("%d-%m-%Y om %H:%M"),
row[0][2])
# Send message
room.send_html(html_message)
# Close DB connection
mysql_db.close()
def participants_callback(self, room, event):
room.send_text("Deelnemers")
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()