Initial commit of software
This commit includes the matrix bot API (https://github.com/shawnanastasio/python-matrix-bot-api/) and the first proof of concept that the plugin API works. Furthermore, it includes the first version of a plugin that acquires event from an Admidio setup (https://admidio.org).
This commit is contained in:
parent
979ba24711
commit
57499db3f5
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,7 @@
|
|||||||
|
# Config
|
||||||
|
config.json
|
||||||
|
*.db
|
||||||
|
|
||||||
# ---> Python
|
# ---> Python
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
13
README.md
13
README.md
@ -1,3 +1,12 @@
|
|||||||
# matrix-chatbot
|
This chatbot is based on [github.com/shawnanastasio/python-matrix-bot-api](https://github.com/shawnanastasio/python-matrix-bot-api/) which was published under GPL-3.0. It works with on the [Matrix network](https://matrix.org).
|
||||||
|
|
||||||
An extensible Python chatbot that is compatible with the Matrix protocol
|
|
||||||
|
For now, this README only contains notes.
|
||||||
|
|
||||||
|
## Requirements:
|
||||||
|
|
||||||
|
MySQLdb
|
||||||
|
|
||||||
|
## Write about:
|
||||||
|
* File structure of plugins and structure of the class
|
||||||
|
* Create help function for bot and for all plugins
|
||||||
|
17
config.json.example
Normal file
17
config.json.example
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"bot_credentials": {
|
||||||
|
"username": "",
|
||||||
|
"password": "",
|
||||||
|
"server": ""
|
||||||
|
},
|
||||||
|
|
||||||
|
"character": {
|
||||||
|
"name": "Peter",
|
||||||
|
"avatar": "images/profilepic.jpg",
|
||||||
|
"avatar_mime": "image/jpeg"
|
||||||
|
},
|
||||||
|
|
||||||
|
"plugins": [
|
||||||
|
"events"
|
||||||
|
]
|
||||||
|
}
|
BIN
images/profilepic.jpg
Normal file
BIN
images/profilepic.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 358 KiB |
0
matrix_bot_api/__init__.py
Normal file
0
matrix_bot_api/__init__.py
Normal file
13
matrix_bot_api/help
Normal file
13
matrix_bot_api/help
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<h3>Peter's help</h3>
|
||||||
|
Als je een zin start met <i>Peter</i> word ik geactiveerd!
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
Ik heb verschillende submodules die je kunt gebruiken. Start een submodule door <i>Peter <submodule naam> <commando></i>. Neem als voorbeeld de evenementen module. Om een lijst van de komende 10 evenementen te verkrijgen, type <i>Peter evenementen lijst</i>.
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><i>help</i>: laat dit bericht zien.</li>
|
||||||
|
</ul>
|
||||||
|
|
197
matrix_bot_api/matrix_bot_api.py
Normal file
197
matrix_bot_api/matrix_bot_api.py
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
import traceback
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
from matrix_client.client import MatrixClient
|
||||||
|
from matrix_client.api import MatrixRequestError, MatrixHttpApi
|
||||||
|
from matrix_client.user import User
|
||||||
|
|
||||||
|
from matrix_bot_api.mregex_handler import MRegexHandler
|
||||||
|
|
||||||
|
HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'help')
|
||||||
|
|
||||||
|
private_message = "Hey {}! Ik heb je even een privébericht gestuurd 🙂"
|
||||||
|
|
||||||
|
def eprint(*args, **kwargs):
|
||||||
|
print(*args, file=sys.stderr, **kwargs)
|
||||||
|
|
||||||
|
class MatrixBotAPI:
|
||||||
|
# rooms - List of rooms ids to operate in, or None to accept all rooms
|
||||||
|
def __init__(self, config, rooms=None):
|
||||||
|
self.username = config['bot_credentials']['username']
|
||||||
|
|
||||||
|
# Authenticate with given credentials
|
||||||
|
self.client = MatrixClient(config['bot_credentials']['server'])
|
||||||
|
try:
|
||||||
|
self.token = self.client.login_with_password(
|
||||||
|
config['bot_credentials']['username'],
|
||||||
|
config['bot_credentials']['password'])
|
||||||
|
except MatrixRequestError as e:
|
||||||
|
print(e)
|
||||||
|
if e.code == 403:
|
||||||
|
print("Bad username/password")
|
||||||
|
except Exception as e:
|
||||||
|
print("Invalid server URL")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
self.api = MatrixHttpApi(
|
||||||
|
config['bot_credentials']['server'],
|
||||||
|
token=self.token)
|
||||||
|
|
||||||
|
# Store allowed rooms
|
||||||
|
self.rooms = rooms
|
||||||
|
|
||||||
|
# Store empty list of handlers
|
||||||
|
self.handlers = []
|
||||||
|
|
||||||
|
# If rooms is None, we should listen for invites and automatically
|
||||||
|
# accept them
|
||||||
|
if rooms is None:
|
||||||
|
self.client.add_invite_listener(self.handle_invite)
|
||||||
|
self.rooms = []
|
||||||
|
|
||||||
|
# Add all rooms we're currently in to self.rooms and add their
|
||||||
|
# callbacks
|
||||||
|
for room_id, room in self.client.get_rooms().items():
|
||||||
|
room.add_listener(self.handle_message)
|
||||||
|
self.rooms.append(room_id)
|
||||||
|
else:
|
||||||
|
# Add the message callback for all specified rooms
|
||||||
|
for room in self.rooms:
|
||||||
|
room.add_listener(self.handle_message)
|
||||||
|
|
||||||
|
# This flag can be set by the calling function to cancel all threads
|
||||||
|
# of all plugins
|
||||||
|
self.cancel = False
|
||||||
|
|
||||||
|
# Store empty list of plugins
|
||||||
|
self.plugins = []
|
||||||
|
|
||||||
|
|
||||||
|
# Try to import plugins. All plugins must be located in the
|
||||||
|
# ./plugins directory
|
||||||
|
modules = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
for plugin in config['plugins']:
|
||||||
|
modules.append(
|
||||||
|
importlib.import_module(
|
||||||
|
"plugins.{0}.{0}".format(plugin), package = None))
|
||||||
|
except:
|
||||||
|
eprint("Importing one or more of the plugins did not go well!")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
# Loop through the available modules and add their handler variables
|
||||||
|
for i, module in enumerate(modules):
|
||||||
|
# Create new instance of plugin and append to plugins array
|
||||||
|
self.plugins.append(module.Plugin(self))
|
||||||
|
|
||||||
|
# Add handler of newly created instance to bot
|
||||||
|
self.add_handler(self.plugins[i].handler)
|
||||||
|
|
||||||
|
# Run setup
|
||||||
|
self.setup(config)
|
||||||
|
|
||||||
|
# Add callback for help function
|
||||||
|
self.help_handler = MRegexHandler("Peter help", self.help)
|
||||||
|
self.add_handler(self.help_handler)
|
||||||
|
|
||||||
|
def setup(self, config):
|
||||||
|
"""This function only runs once, ever. It initializes an SQLite
|
||||||
|
database, sets the bot's avatar, and name"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Try to make new directory
|
||||||
|
os.mkdir("data")
|
||||||
|
|
||||||
|
# Get user instance
|
||||||
|
self.user = self.client.get_user(self.username)
|
||||||
|
|
||||||
|
# Set username
|
||||||
|
self.user.set_display_name(config['character']['name'])
|
||||||
|
|
||||||
|
# Open, upload, and set avatar
|
||||||
|
f = open(config['character']['avatar'], mode="rb")
|
||||||
|
|
||||||
|
avatar = self.client.upload(f, config['charactar']['avatar_mime'])
|
||||||
|
self.user.set_avatar_url(avatar)
|
||||||
|
|
||||||
|
except FileExistsError:
|
||||||
|
# Do nothing, data directory already exists
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_message_private_public(self, room, event, message):
|
||||||
|
orig_room = room
|
||||||
|
found_room = False
|
||||||
|
|
||||||
|
for room_id, room in self.client.get_rooms().items():
|
||||||
|
joined_members = room.get_joined_members()
|
||||||
|
|
||||||
|
# Check for rooms with only two members
|
||||||
|
if len(joined_members) == 2:
|
||||||
|
# Check if sender is in that room
|
||||||
|
for member in joined_members:
|
||||||
|
if event['sender'] == member.user_id:
|
||||||
|
found_room = True
|
||||||
|
|
||||||
|
if found_room:
|
||||||
|
# If the flag is set, we do not need to check further rooms
|
||||||
|
break
|
||||||
|
|
||||||
|
# Send help message to an existing room or to a new room
|
||||||
|
if found_room:
|
||||||
|
room.send_html(message)
|
||||||
|
else:
|
||||||
|
room = self.client.create_room(invitees=[event['sender']]);
|
||||||
|
room.send_html(message)
|
||||||
|
|
||||||
|
if room != orig_room:
|
||||||
|
display_name_sender = self.api.get_display_name(event['sender'])
|
||||||
|
orig_room.send_text(private_message.format(display_name_sender))
|
||||||
|
|
||||||
|
def help(self, room, event):
|
||||||
|
"""Prints a general help message and then grabs all help
|
||||||
|
messages from the different plugins
|
||||||
|
"""
|
||||||
|
|
||||||
|
help_text = open(HELP_LOCATION, mode="r").read()
|
||||||
|
|
||||||
|
for plugin in self.plugins:
|
||||||
|
help_text += plugin.help()
|
||||||
|
|
||||||
|
self.send_message_private_public(room, event, help_text)
|
||||||
|
|
||||||
|
def add_handler(self, handler):
|
||||||
|
self.handlers.append(handler)
|
||||||
|
|
||||||
|
def handle_message(self, room, event):
|
||||||
|
# Make sure we didn't send this message
|
||||||
|
if re.match("@" + self.username, event['sender']):
|
||||||
|
return
|
||||||
|
|
||||||
|
# Loop through all installed handlers and see if they need to be called
|
||||||
|
for handler in self.handlers:
|
||||||
|
if handler.test_callback(room, event):
|
||||||
|
# This handler needs to be called
|
||||||
|
try:
|
||||||
|
handler.handle_callback(room, event)
|
||||||
|
except:
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def handle_invite(self, room_id, state):
|
||||||
|
print("Got invite to room: " + str(room_id))
|
||||||
|
print("Joining...")
|
||||||
|
room = self.client.join_room(room_id)
|
||||||
|
|
||||||
|
# Add message callback for this room
|
||||||
|
room.add_listener(self.handle_message)
|
||||||
|
|
||||||
|
# Add room to list
|
||||||
|
self.rooms.append(room)
|
||||||
|
|
||||||
|
def start_polling(self):
|
||||||
|
# Starts polling for messages
|
||||||
|
self.client.start_listener_thread()
|
||||||
|
return self.client.sync_thread
|
25
matrix_bot_api/mcommand_handler.py
Normal file
25
matrix_bot_api/mcommand_handler.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
Defines a matrix bot handler for commands
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
from matrix_bot_api.mhandler import MHandler
|
||||||
|
|
||||||
|
|
||||||
|
class MCommandHandler(MHandler):
|
||||||
|
|
||||||
|
# command - String of command to handle
|
||||||
|
# handle_callback - Function to call if message contains command
|
||||||
|
# cmd_char - Character that denotes a command. '!' by default
|
||||||
|
def __init__(self, command, handle_callback, cmd_char='!'):
|
||||||
|
MHandler.__init__(self, self.test_command, handle_callback)
|
||||||
|
self.command = command
|
||||||
|
self.cmd_char = cmd_char
|
||||||
|
|
||||||
|
# Function called by Matrix bot api to determine whether or not to handle this message
|
||||||
|
def test_command(self, room, event):
|
||||||
|
# Test the message to see if it has our command
|
||||||
|
if event['type'] == "m.room.message":
|
||||||
|
if re.match(self.cmd_char + self.command, event['content']['body']):
|
||||||
|
return True
|
||||||
|
return False
|
13
matrix_bot_api/mhandler.py
Normal file
13
matrix_bot_api/mhandler.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"""
|
||||||
|
Defines a Matrix bot message handler
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class MHandler(object):
|
||||||
|
# test_callback - function that takes a room and event and returns a boolean
|
||||||
|
# indicating whether we should pass the message on to handle_callback
|
||||||
|
#
|
||||||
|
# handle_callback - function that takes a room and event and handles them
|
||||||
|
def __init__(self, test_callback, handle_callback):
|
||||||
|
self.test_callback = test_callback
|
||||||
|
self.handle_callback = handle_callback
|
25
matrix_bot_api/mregex_handler.py
Normal file
25
matrix_bot_api/mregex_handler.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
"""
|
||||||
|
Defines a matrix bot handler that uses regex to determine if message should be handled
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
|
||||||
|
from matrix_bot_api.mhandler import MHandler
|
||||||
|
|
||||||
|
|
||||||
|
class MRegexHandler(MHandler):
|
||||||
|
|
||||||
|
# regex_str - Regular expression to test message against
|
||||||
|
#
|
||||||
|
# handle_callback - Function to call if messages matches regex
|
||||||
|
def __init__(self, regex_str, handle_callback):
|
||||||
|
MHandler.__init__(self, self.test_regex, handle_callback)
|
||||||
|
self.regex_str = regex_str
|
||||||
|
|
||||||
|
def test_regex(self, room, event):
|
||||||
|
# Test the message and see if it matches the regex
|
||||||
|
if event['type'] == "m.room.message":
|
||||||
|
if re.search(self.regex_str, event['content']['body']):
|
||||||
|
# The message matches the regex, return true
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
0
plugins/__init__.py
Normal file
0
plugins/__init__.py
Normal file
1
plugins/events/README.md
Normal file
1
plugins/events/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Insert description of event plugin.
|
0
plugins/events/__init__.py
Normal file
0
plugins/events/__init__.py
Normal file
13
plugins/events/config.json.example
Normal file
13
plugins/events/config.json.example
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"database_credentials": {
|
||||||
|
"username": "",
|
||||||
|
"password": "",
|
||||||
|
"database": ""
|
||||||
|
},
|
||||||
|
"cat_id_room_mapping": [
|
||||||
|
[[], ""],
|
||||||
|
[[], ""]
|
||||||
|
],
|
||||||
|
"update_time_span": 5,
|
||||||
|
"base_url_adm": ""
|
||||||
|
}
|
170
plugins/events/events.py
Normal file
170
plugins/events/events.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import os
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import sqlite3
|
||||||
|
import threading
|
||||||
|
import datetime as dt
|
||||||
|
import MySQLdb as mysql
|
||||||
|
|
||||||
|
from matrix_bot_api.mregex_handler import MRegexHandler
|
||||||
|
|
||||||
|
CONFIG_LOCATION = os.path.join(os.path.dirname(__file__), 'config.json')
|
||||||
|
HELP_LOCATION = os.path.join(os.path.dirname(__file__), 'help')
|
||||||
|
NEW_EVENT_LOCATION = os.path.join(os.path.dirname(__file__), 'new_event')
|
||||||
|
|
||||||
|
class Plugin:
|
||||||
|
""" Description of event plugin """
|
||||||
|
|
||||||
|
def __init__(self, bot):
|
||||||
|
# Load the configuration
|
||||||
|
with open(CONFIG_LOCATION) as json_data:
|
||||||
|
self.config = json.load(json_data)
|
||||||
|
|
||||||
|
# Define sensitivity
|
||||||
|
self.handler = MRegexHandler("Peter evenementen", self.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()
|
||||||
|
|
||||||
|
self.setup()
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
"""This function only runs once, ever. It initializes the necessary
|
||||||
|
SQLite tables."""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 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/bot.db')
|
||||||
|
sqlite_cursor = sqlite_db.cursor()
|
||||||
|
sqlite_cursor.execute(sql)
|
||||||
|
sqlite_db.commit()
|
||||||
|
sqlite_db.close()
|
||||||
|
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
# Table already exists, do nothing
|
||||||
|
pass
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Connect to database
|
||||||
|
mysql_db = mysql.connect(
|
||||||
|
user = self.config['database_credentials']['username'],
|
||||||
|
password = self.config['database_credentials']['password'],
|
||||||
|
database = self.config['database_credentials']['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()
|
||||||
|
|
||||||
|
mysql_db.close()
|
||||||
|
|
||||||
|
# Open SQLite database
|
||||||
|
sqlite_db = sqlite3.connect('data/bot.db')
|
||||||
|
|
||||||
|
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])
|
||||||
|
|
||||||
|
new_event = open(NEW_EVENT_LOCATION, mode="r").read()
|
||||||
|
|
||||||
|
# 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(
|
||||||
|
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()
|
||||||
|
|
||||||
|
# Sleep
|
||||||
|
#time.sleep(self.config['update_time_span'] * 60)
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
def callback(self, room, event):
|
||||||
|
room.send_text("Information ")
|
||||||
|
|
||||||
|
def help(self):
|
||||||
|
return open(HELP_LOCATION, mode="r").read()
|
7
plugins/events/help
Normal file
7
plugins/events/help
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<h5><i>evenementen</i></h5>
|
||||||
|
<ul>
|
||||||
|
<li><i>lijst</i>: creëer een lijst met de komende 10 evenementen. Als meer of minder evenementen nodig zijn, definieer het getal als <i>lijst <natuurlijk getal></i>. Dit commando laat ook het identificatienummer van evenementen zien.</li>
|
||||||
|
<li><i>info <ID></i>: laat informatie zien over het evenement met het identificatienummer <i><ID></i>. Titel, tijd, locatie, beschrijving en aan- en afmeldlinks worden getoond.</li>
|
||||||
|
<li><i>chat <ID></i>: maak een chatgroep aan voor alle leden die op dit moment op aanwezig of misschien staan in een evenement met het identificatienummer <i><ID></i>.</li>
|
||||||
|
<li><i>deelnemers <ID></i>: dit laat alle deelnemers zien die op dit moment op aanwezig of misschien staan voor een bepaald evenement met het identificatienummer <i><ID></i>.</li>
|
||||||
|
</ul>
|
11
plugins/events/new_event
Normal file
11
plugins/events/new_event
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<strong>@room er is zojuist een nieuw evenement aangemaakt! Op {} om {} zal "{}" plaatsvinden.</strong>
|
||||||
|
|
||||||
|
<br /><br />
|
||||||
|
|
||||||
|
Ben je aangemeld op de leden database in je favoriete browser? Klik dan hier:
|
||||||
|
<ul>
|
||||||
|
<li> <a href='{}'>om het evenement te bekijken</a> 👀
|
||||||
|
<li> <a href='{}'>om je op aanwezig te zetten</a> ✅
|
||||||
|
<li> <a href='{}'>om je op misschien te zetten</a> 🤷
|
||||||
|
<li> <a href='{}'>om je op afwezig te zetten</a> ⛔
|
||||||
|
</ul>
|
31
run.py
Executable file
31
run.py
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
This is Peter. Peter is using the Python Matrix Bot API
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Bot API import
|
||||||
|
from matrix_bot_api.matrix_bot_api import MatrixBotAPI
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Load the configuration
|
||||||
|
with open('config.json') as json_data:
|
||||||
|
config = json.load(json_data)
|
||||||
|
|
||||||
|
# Create an instance of the MatrixBotAPI
|
||||||
|
bot = MatrixBotAPI(config)
|
||||||
|
|
||||||
|
# Start polling
|
||||||
|
bot.start_polling()
|
||||||
|
|
||||||
|
# Infinitely read stdin to stall main thread while the bot runs in other
|
||||||
|
# threads.
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
input()
|
||||||
|
except:
|
||||||
|
bot.cancel = True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user