306 lines
9.9 KiB
Python
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()
|
|
|