__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']) def check_new_event_thread(self): while not self.bot.cancel: self.check_new_event() def check_new_event(self): """ Check every minutes for new events in the database. Since the check will only be performed every 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.get_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 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 += "
" # Send message room.send_html(html_message) # Close DB connection mysql_db.close() def info_callback(self, room, event): room.send_text("Info") def chat_callback(self, room, event): room.send_text("Chat") def participants_callback(self, room, event): room.send_text("Deelnemers") 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()