Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
706188827a | |||
2f3e887c83 |
19 changed files with 944 additions and 464 deletions
|
@ -99,6 +99,12 @@ Start by executing the command `kaikout` and enter Username and Password of an e
|
|||
$ kaikout
|
||||
```
|
||||
|
||||
You can also start KaikOut as follows:
|
||||
|
||||
```
|
||||
$ kaikout --jid ACCOUNT_JABBER_ID --password ACCOUNT_PASSWORD
|
||||
```
|
||||
|
||||
It is advised to use a dedicated extra account for KaikOut.
|
||||
|
||||
## Recommended Clients
|
||||
|
|
|
@ -6,37 +6,18 @@
|
|||
# See the file LICENSE for copying permission.
|
||||
|
||||
# from kaikout.about import Documentation
|
||||
from kaikout.utilities import Config, Toml
|
||||
from kaikout.utilities import Config
|
||||
# from kaikout.xmpp.chat import XmppChat
|
||||
from kaikout.xmpp.client import XmppClient
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
from erdhe import integrate_with_kaikout # Add this import
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
# import os
|
||||
# import slixmpp
|
||||
# import sys
|
||||
|
||||
def main():
|
||||
|
||||
directory = os.path.dirname(__file__)
|
||||
|
||||
# Copy data files
|
||||
directory_data = Config.get_default_config_directory()
|
||||
# TODO Utilize the actual data directory
|
||||
#directory_data = Config.get_default_data_directory()
|
||||
if not os.path.exists(directory_data):
|
||||
directory_assets = os.path.join(directory, 'assets')
|
||||
directory_assets_new = shutil.copytree(directory_assets, directory_data)
|
||||
print(f'Data directory {directory_assets_new} has been created and populated.')
|
||||
|
||||
# Copy settings files
|
||||
directory_settings = Config.get_default_config_directory()
|
||||
if not os.path.exists(directory_settings):
|
||||
directory_configs = os.path.join(directory, 'configs')
|
||||
directory_settings_new = shutil.copytree(directory_configs, directory_settings)
|
||||
print(f'Configuration directory {directory_settings_new} has been created and populated.')
|
||||
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser(description=XmppClient.__doc__)
|
||||
|
||||
|
@ -48,52 +29,39 @@ def main():
|
|||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
# Configure settings file
|
||||
file_settings = os.path.join(directory_settings, 'accounts.toml')
|
||||
if not os.path.exists(file_settings):
|
||||
directory_configs = os.path.join(directory, 'configs')
|
||||
file_settings_empty = os.path.join(directory_configs, 'accounts.toml')
|
||||
shutil.copyfile(file_settings_empty, file_settings)
|
||||
account_xmpp = Config.get_values('accounts.toml', 'xmpp')
|
||||
|
||||
data_settings = Toml.open_file(file_settings)
|
||||
|
||||
# Configure account
|
||||
data_settings_account = data_settings['xmpp']['client']
|
||||
|
||||
settings_account = {
|
||||
'alias': 'Set an Alias',
|
||||
'jid': 'Set a Jabber ID',
|
||||
'password': 'Input Password'
|
||||
}
|
||||
|
||||
for key in settings_account:
|
||||
data_settings_account_value = data_settings_account[key]
|
||||
if not data_settings_account_value:
|
||||
settings_account_message = settings_account[key]
|
||||
while not data_settings_account_value:
|
||||
if key == 'password':
|
||||
data_settings_account_value = getpass(f'{settings_account_message}: ')
|
||||
else:
|
||||
data_settings_account_value = input(f'{settings_account_message}: ')
|
||||
data_settings_account[key] = data_settings_account_value
|
||||
|
||||
Toml.save_file(file_settings, data_settings)
|
||||
if args.jid is None and not account_xmpp['client']['jid']:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None and not account_xmpp['client']['password']:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
# Try configuration file
|
||||
jid = data_settings_account['jid']
|
||||
password = data_settings_account['password']
|
||||
alias = data_settings_account['alias']
|
||||
# TODO
|
||||
#hostname = account_xmpp_client['hostname'] if 'hostname' in account_xmpp_client else None
|
||||
#port = account_xmpp_client['port'] if 'port' in account_xmpp_client else None
|
||||
hostname = port = None
|
||||
XmppClient(jid, password, hostname, port, alias)
|
||||
if 'client' in account_xmpp:
|
||||
jid = account_xmpp['client']['jid']
|
||||
password = account_xmpp['client']['password']
|
||||
alias = account_xmpp['client']['alias'] if 'alias' in account_xmpp['client'] else None
|
||||
hostname = account_xmpp['client']['hostname'] if 'hostname' in account_xmpp['client'] else None
|
||||
port = account_xmpp['client']['port'] if 'port' in account_xmpp['client'] else None
|
||||
XmppClient(jid, password, hostname, port, alias)
|
||||
|
||||
# Create the XMPP client
|
||||
xmpp_client = XmppClient(jid, password, hostname, port, alias)
|
||||
|
||||
# Integrate the welcome whisper feature
|
||||
welcomer = integrate_with_kaikout(xmpp_client)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
|
@ -26,8 +26,8 @@ BDAY = "20 June 2024"
|
|||
#DESC = ""
|
||||
|
||||
[xmpp.client]
|
||||
alias = ""
|
||||
jid = ""
|
||||
alias = "KaikOut"
|
||||
jid = "/KaikOut"
|
||||
password = ""
|
||||
|
||||
[tox]
|
|
@ -1,2 +0,0 @@
|
|||
[entries."xmppbl.org"]
|
||||
muc_bans_sha256 = []
|
|
@ -16,16 +16,16 @@ class Config:
|
|||
|
||||
|
||||
def get_default_data_directory():
|
||||
directory_home = os.environ.get('HOME')
|
||||
if directory_home:
|
||||
data_home = os.path.join(directory_home, '.local', 'share')
|
||||
if os.environ.get('HOME'):
|
||||
data_home = os.path.join(os.environ.get('HOME'), '.local', 'share')
|
||||
return os.path.join(data_home, 'kaikout')
|
||||
elif sys.platform == 'win32':
|
||||
data_home = os.environ.get('APPDATA')
|
||||
if data_home is None:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(
|
||||
os.path.dirname(__file__) + '/kaikout_data')
|
||||
else:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||
|
||||
|
||||
def get_default_config_directory():
|
||||
|
@ -42,20 +42,19 @@ class Config:
|
|||
str
|
||||
Path to configuration directory.
|
||||
"""
|
||||
# directory_config_home = xdg.BaseDirectory.xdg_config_home
|
||||
directory_config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||
if directory_config_home is None:
|
||||
directory_home = os.environ.get('HOME')
|
||||
if directory_home is None:
|
||||
# config_home = xdg.BaseDirectory.xdg_config_home
|
||||
config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||
if config_home is None:
|
||||
if os.environ.get('HOME') is None:
|
||||
if sys.platform == 'win32':
|
||||
directory_config_home = os.environ.get('APPDATA')
|
||||
if directory_config_home is None:
|
||||
return 'kaikout_config'
|
||||
config_home = os.environ.get('APPDATA')
|
||||
if config_home is None:
|
||||
return os.path.abspath('.')
|
||||
else:
|
||||
return 'kaikout_config'
|
||||
return os.path.abspath('.')
|
||||
else:
|
||||
directory_config_home = os.path.join(directory_home, '.config')
|
||||
return os.path.join(directory_config_home, 'kaikout')
|
||||
config_home = os.path.join(os.environ.get('HOME'), '.config')
|
||||
return os.path.join(config_home, 'kaikout')
|
||||
|
||||
|
||||
def get_values(filename, key=None):
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
bookmarks = []
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
from asyncio import Lock
|
||||
from kaikout.log import Logger
|
||||
from sqlite3 import connect, Error, IntegrityError
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
@ -17,10 +18,429 @@ import tomllib
|
|||
# # with start_action(action_type="search_entries()", query=query):
|
||||
# # with start_action(action_type="check_entry()", link=link):
|
||||
|
||||
CURSORS = {}
|
||||
|
||||
# aiosqlite
|
||||
DBLOCK = Lock()
|
||||
|
||||
logger = Logger(__name__)
|
||||
|
||||
|
||||
class DatabaseToml:
|
||||
class SQLite:
|
||||
|
||||
|
||||
def create_connection(db_file):
|
||||
"""
|
||||
Create a database connection to the SQLite database
|
||||
specified by db_file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
conn : object
|
||||
Connection object or None.
|
||||
"""
|
||||
time_begin = time.time()
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
message_log = '{}'
|
||||
logger.debug(message_log.format(function_name))
|
||||
conn = None
|
||||
try:
|
||||
conn = connect(db_file)
|
||||
conn.execute("PRAGMA foreign_keys = ON")
|
||||
# return conn
|
||||
except Error as e:
|
||||
logger.warning('Error creating a connection to database {}.'.format(db_file))
|
||||
logger.error(e)
|
||||
time_end = time.time()
|
||||
difference = time_end - time_begin
|
||||
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
|
||||
difference))
|
||||
return conn
|
||||
|
||||
|
||||
def create_tables(db_file):
|
||||
"""
|
||||
Create SQLite tables.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {}'
|
||||
.format(function_name, db_file))
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
activity_table_sql = (
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS activity (
|
||||
id INTEGER NOT NULL,
|
||||
stanza_id TEXT,
|
||||
alias TEXT,
|
||||
jid TEXT,
|
||||
body TEXT,
|
||||
thread TEXT,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
"""
|
||||
)
|
||||
filters_table_sql = (
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS filters (
|
||||
id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
"""
|
||||
)
|
||||
outcast_table_sql = (
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS outcast (
|
||||
id INTEGER NOT NULL,
|
||||
alias TEXT,
|
||||
jid TEXT,
|
||||
reason TEXT,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
"""
|
||||
)
|
||||
settings_table_sql = (
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
id INTEGER NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value INTEGER,
|
||||
PRIMARY KEY ("id")
|
||||
);
|
||||
"""
|
||||
)
|
||||
cur = conn.cursor()
|
||||
# cur = get_cursor(db_file)
|
||||
cur.execute(activity_table_sql)
|
||||
cur.execute(filters_table_sql)
|
||||
cur.execute(outcast_table_sql)
|
||||
cur.execute(settings_table_sql)
|
||||
|
||||
|
||||
def get_cursor(db_file):
|
||||
"""
|
||||
Allocate a cursor to connection per database.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
CURSORS[db_file] : object
|
||||
Cursor.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {}'
|
||||
.format(function_name, db_file))
|
||||
if db_file in CURSORS:
|
||||
return CURSORS[db_file]
|
||||
else:
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
CURSORS[db_file] = cur
|
||||
return CURSORS[db_file]
|
||||
|
||||
|
||||
async def import_feeds(db_file, feeds):
|
||||
"""
|
||||
Insert a new feed into the feeds table.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
feeds : list
|
||||
Set of feeds (Title and URL).
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {}'
|
||||
.format(function_name, db_file))
|
||||
async with DBLOCK:
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
for feed in feeds:
|
||||
logger.debug('{}: feed: {}'
|
||||
.format(function_name, feed))
|
||||
url = feed['url']
|
||||
title = feed['title']
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_properties(
|
||||
title, url)
|
||||
VALUES(
|
||||
?, ?)
|
||||
"""
|
||||
)
|
||||
par = (title, url)
|
||||
try:
|
||||
cur.execute(sql, par)
|
||||
except IntegrityError as e:
|
||||
logger.warning("Skipping: " + str(url))
|
||||
logger.error(e)
|
||||
|
||||
|
||||
async def add_metadata(db_file):
|
||||
"""
|
||||
Insert a new feed into the feeds table.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {}'
|
||||
.format(function_name, db_file))
|
||||
async with DBLOCK:
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
sql = (
|
||||
"""
|
||||
SELECT id
|
||||
FROM feeds_properties
|
||||
ORDER BY id ASC
|
||||
"""
|
||||
)
|
||||
ixs = cur.execute(sql).fetchall()
|
||||
for ix in ixs:
|
||||
feed_id = ix[0]
|
||||
# Set feed status
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_state(
|
||||
feed_id)
|
||||
VALUES(
|
||||
?)
|
||||
"""
|
||||
)
|
||||
par = (feed_id,)
|
||||
try:
|
||||
cur.execute(sql, par)
|
||||
except IntegrityError as e:
|
||||
logger.warning(
|
||||
"Skipping feed_id {} for table feeds_state".format(feed_id))
|
||||
logger.error(e)
|
||||
# Set feed preferences.
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_preferences(
|
||||
feed_id)
|
||||
VALUES(
|
||||
?)
|
||||
"""
|
||||
)
|
||||
par = (feed_id,)
|
||||
try:
|
||||
cur.execute(sql, par)
|
||||
except IntegrityError as e:
|
||||
logger.warning(
|
||||
"Skipping feed_id {} for table feeds_preferences".format(feed_id))
|
||||
logger.error(e)
|
||||
|
||||
|
||||
async def insert_feed(db_file, url, title, identifier, entries=None, version=None,
|
||||
encoding=None, language=None, status_code=None,
|
||||
updated=None):
|
||||
"""
|
||||
Insert a new feed into the feeds table.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
url : str
|
||||
URL.
|
||||
title : str
|
||||
Feed title.
|
||||
identifier : str
|
||||
Feed identifier.
|
||||
entries : int, optional
|
||||
Number of entries. The default is None.
|
||||
version : str, optional
|
||||
Type of feed. The default is None.
|
||||
encoding : str, optional
|
||||
Encoding of feed. The default is None.
|
||||
language : str, optional
|
||||
Language code of feed. The default is None.
|
||||
status : str, optional
|
||||
HTTP status code. The default is None.
|
||||
updated : ???, optional
|
||||
Date feed was last updated. The default is None.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {} url: {}'
|
||||
.format(function_name, db_file, url))
|
||||
async with DBLOCK:
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_properties(
|
||||
url, title, identifier, entries, version, encoding, language, updated)
|
||||
VALUES(
|
||||
?, ?, ?, ?, ?, ?, ?, ?)
|
||||
"""
|
||||
)
|
||||
par = (url, title, identifier, entries, version, encoding, language, updated)
|
||||
cur.execute(sql, par)
|
||||
sql = (
|
||||
"""
|
||||
SELECT id
|
||||
FROM feeds_properties
|
||||
WHERE url = :url
|
||||
"""
|
||||
)
|
||||
par = (url,)
|
||||
feed_id = cur.execute(sql, par).fetchone()[0]
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_state(
|
||||
feed_id, status_code, valid)
|
||||
VALUES(
|
||||
?, ?, ?)
|
||||
"""
|
||||
)
|
||||
par = (feed_id, status_code, 1)
|
||||
cur.execute(sql, par)
|
||||
sql = (
|
||||
"""
|
||||
INSERT
|
||||
INTO feeds_preferences(
|
||||
feed_id)
|
||||
VALUES(
|
||||
?)
|
||||
"""
|
||||
)
|
||||
par = (feed_id,)
|
||||
cur.execute(sql, par)
|
||||
|
||||
|
||||
async def remove_feed_by_url(db_file, url):
|
||||
"""
|
||||
Delete a feed by feed URL.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
url : str
|
||||
URL of feed.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {} url: {}'
|
||||
.format(function_name, db_file, url))
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
async with DBLOCK:
|
||||
cur = conn.cursor()
|
||||
sql = (
|
||||
"""
|
||||
DELETE
|
||||
FROM feeds_properties
|
||||
WHERE url = ?
|
||||
"""
|
||||
)
|
||||
par = (url,)
|
||||
cur.execute(sql, par)
|
||||
|
||||
|
||||
async def remove_feed_by_index(db_file, ix):
|
||||
"""
|
||||
Delete a feed by feed ID.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
ix : str
|
||||
Index of feed.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {} ix: {}'
|
||||
.format(function_name, db_file, ix))
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
async with DBLOCK:
|
||||
cur = conn.cursor()
|
||||
# # NOTE Should we move DBLOCK to this line? 2022-12-23
|
||||
# sql = (
|
||||
# "DELETE "
|
||||
# "FROM entries "
|
||||
# "WHERE feed_id = ?"
|
||||
# )
|
||||
# par = (url,)
|
||||
# cur.execute(sql, par) # Error? 2024-01-05
|
||||
# sql = (
|
||||
# "DELETE "
|
||||
# "FROM archive "
|
||||
# "WHERE feed_id = ?"
|
||||
# )
|
||||
# par = (url,)
|
||||
# cur.execute(sql, par)
|
||||
sql = (
|
||||
"""
|
||||
DELETE
|
||||
FROM feeds_properties
|
||||
WHERE id = ?
|
||||
"""
|
||||
)
|
||||
par = (ix,)
|
||||
cur.execute(sql, par)
|
||||
|
||||
|
||||
def get_feeds_by_tag_id(db_file, tag_id):
|
||||
"""
|
||||
Get feeds of given tag.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
tag_id : str
|
||||
Tag ID.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : tuple
|
||||
List of tags.
|
||||
"""
|
||||
function_name = sys._getframe().f_code.co_name
|
||||
logger.debug('{}: db_file: {} tag_id: {}'
|
||||
.format(function_name, db_file, tag_id))
|
||||
with SQLite.create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
sql = (
|
||||
"""
|
||||
SELECT feeds_properties.*
|
||||
FROM feeds_properties
|
||||
INNER JOIN tagged_feeds ON feeds_properties.id = tagged_feeds.feed_id
|
||||
INNER JOIN tags ON tags.id = tagged_feeds.tag_id
|
||||
WHERE tags.id = ?
|
||||
ORDER BY feeds_properties.title;
|
||||
"""
|
||||
)
|
||||
par = (tag_id,)
|
||||
result = cur.execute(sql, par).fetchall()
|
||||
return result
|
||||
|
||||
|
||||
class Toml:
|
||||
|
||||
|
||||
def instantiate(self, room):
|
||||
|
@ -42,16 +462,15 @@ class DatabaseToml:
|
|||
object
|
||||
Coroutine object.
|
||||
"""
|
||||
data_dir = DatabaseToml.get_default_data_directory()
|
||||
data_dir = Toml.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir):
|
||||
os.mkdir(data_dir)
|
||||
data_dir_toml = os.path.join(data_dir, 'toml')
|
||||
if not os.path.isdir(data_dir_toml):
|
||||
os.mkdir(data_dir_toml)
|
||||
filename = os.path.join(data_dir_toml, f'{room}.toml')
|
||||
if not os.path.isdir(data_dir + "/toml"):
|
||||
os.mkdir(data_dir + "/toml")
|
||||
filename = os.path.join(data_dir, "toml", r"{}.toml".format(room))
|
||||
if not os.path.exists(filename):
|
||||
DatabaseToml.create_settings_file(self, filename)
|
||||
DatabaseToml.load_jid_settings(self, room, filename)
|
||||
Toml.create_settings_file(self, filename)
|
||||
Toml.load_jid_settings(self, room, filename)
|
||||
return filename
|
||||
|
||||
|
||||
|
@ -62,13 +481,14 @@ class DatabaseToml:
|
|||
elif sys.platform == 'win32':
|
||||
data_home = os.environ.get('APPDATA')
|
||||
if data_home is None:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(
|
||||
os.path.dirname(__file__) + '/kaikout_data')
|
||||
else:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||
|
||||
|
||||
def get_data_file(data_dir, room):
|
||||
toml_file = os.path.join(data_dir, 'toml', f'{room}.toml')
|
||||
toml_file = os.path.join(data_dir, "toml", r"{}.toml".format(room))
|
||||
return toml_file
|
||||
|
||||
|
||||
|
@ -79,8 +499,8 @@ class DatabaseToml:
|
|||
|
||||
|
||||
def load_jid_settings(self, room, filename):
|
||||
# data_dir = DatabaseToml.get_default_data_directory()
|
||||
# filename = DatabaseToml.get_data_file(data_dir, room)
|
||||
# data_dir = Toml.get_default_data_directory()
|
||||
# filename = Toml.get_data_file(data_dir, room)
|
||||
with open(filename, 'rb') as f: self.settings[room] = tomllib.load(f)
|
||||
|
||||
|
||||
|
|
55
kaikout/erdhe.py
Normal file
55
kaikout/erdhe.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from slixmpp import ClientXMPP
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
import logging
|
||||
|
||||
class WelcomeWhisperer:
|
||||
"""
|
||||
A feature class that sends welcome whispers to users joining an XMPP room.
|
||||
"""
|
||||
def __init__(self, xmpp_client):
|
||||
self.xmpp = xmpp_client
|
||||
self.rooms = {}
|
||||
|
||||
# Register event handlers
|
||||
self.xmpp.add_event_handler("groupchat_presence", self.handle_groupchat_presence)
|
||||
|
||||
def handle_groupchat_presence(self, presence):
|
||||
"""
|
||||
Handle presence stanzas from chat rooms.
|
||||
"""
|
||||
if presence['type'] == 'available':
|
||||
room = presence['from'].bare
|
||||
nick = presence['from'].resource
|
||||
|
||||
# Check if this is a new user joining (not already in our room roster)
|
||||
if room in self.rooms and nick not in self.rooms[room]:
|
||||
self.send_welcome_whisper(room, nick)
|
||||
|
||||
# Update our room roster
|
||||
if room not in self.rooms:
|
||||
self.rooms[room] = set()
|
||||
self.rooms[room].add(nick)
|
||||
|
||||
def send_welcome_whisper(self, room, nick):
|
||||
"""
|
||||
Send a welcome whisper to a user who just joined the room.
|
||||
"""
|
||||
message = f"Welcome to the room {nick}, have a good time in the channel!"
|
||||
try:
|
||||
self.xmpp.send_message(
|
||||
mto=room,
|
||||
mbody=f"/w {nick} {message}",
|
||||
mtype='groupchat'
|
||||
)
|
||||
logging.info(f"Sent welcome whisper to {nick} in {room}")
|
||||
except Exception as e:
|
||||
logging.error(f"Failed to send welcome whisper: {e}")
|
||||
|
||||
def integrate_with_kaikout(xmpp_client):
|
||||
"""
|
||||
Integrate the WelcomeWhisperer feature with an existing Kaikout XmppClient instance.
|
||||
"""
|
||||
welcomer = WelcomeWhisperer(xmpp_client)
|
||||
return welcomer
|
|
@ -4,7 +4,7 @@
|
|||
import csv
|
||||
from email.utils import parseaddr
|
||||
import hashlib
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
#import kaikout.sqlite as sqlite
|
||||
import os
|
||||
|
@ -37,16 +37,16 @@ class Config:
|
|||
str
|
||||
Path to data directory.
|
||||
"""
|
||||
directory_home = os.environ.get('HOME')
|
||||
if directory_home:
|
||||
data_home = os.path.join(directory_home, '.local', 'share')
|
||||
if os.environ.get('HOME'):
|
||||
data_home = os.path.join(os.environ.get('HOME'), '.local', 'share')
|
||||
return os.path.join(data_home, 'kaikout')
|
||||
elif sys.platform == 'win32':
|
||||
data_home = os.environ.get('APPDATA')
|
||||
if data_home is None:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(
|
||||
os.path.dirname(__file__) + '/kaikout_data')
|
||||
else:
|
||||
return 'kaikout_data'
|
||||
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||
|
||||
|
||||
def get_default_config_directory():
|
||||
|
@ -63,20 +63,40 @@ class Config:
|
|||
str
|
||||
Path to configuration directory.
|
||||
"""
|
||||
# directory_config_home = xdg.BaseDirectory.xdg_config_home
|
||||
directory_config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||
if directory_config_home is None:
|
||||
directory_home = os.environ.get('HOME')
|
||||
if directory_home is None:
|
||||
# config_home = xdg.BaseDirectory.xdg_config_home
|
||||
config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||
if config_home is None:
|
||||
if os.environ.get('HOME') is None:
|
||||
if sys.platform == 'win32':
|
||||
directory_config_home = os.environ.get('APPDATA')
|
||||
if directory_config_home is None:
|
||||
return 'kaikout_config'
|
||||
config_home = os.environ.get('APPDATA')
|
||||
if config_home is None:
|
||||
return os.path.abspath('.')
|
||||
else:
|
||||
return 'kaikout_config'
|
||||
return os.path.abspath('.')
|
||||
else:
|
||||
directory_config_home = os.path.join(directory_home, '.config')
|
||||
return os.path.join(directory_config_home, 'kaikout')
|
||||
config_home = os.path.join(
|
||||
os.environ.get('HOME'), '.config'
|
||||
)
|
||||
return os.path.join(config_home, 'kaikout')
|
||||
|
||||
|
||||
def get_setting_value(db_file, key):
|
||||
value = sqlite.get_setting_value(db_file, key)
|
||||
if value:
|
||||
value = value[0]
|
||||
else:
|
||||
value = Config.get_value('settings', 'Settings', key)
|
||||
return value
|
||||
|
||||
|
||||
def get_values(filename, key=None):
|
||||
config_dir = Config.get_default_config_directory()
|
||||
if not os.path.isdir(config_dir): config_dir = '/usr/share/kaikout/'
|
||||
if not os.path.isdir(config_dir): config_dir = os.path.dirname(__file__) + "/assets"
|
||||
config_file = os.path.join(config_dir, filename)
|
||||
with open(config_file, mode="rb") as f: result = tomllib.load(f)
|
||||
values = result[key] if key else result
|
||||
return values
|
||||
|
||||
|
||||
class Documentation:
|
||||
|
@ -116,103 +136,14 @@ class Documentation:
|
|||
class Log:
|
||||
|
||||
|
||||
def jid_exist(filename, fields):
|
||||
"""
|
||||
Ceck whether Alias and Jabber ID exist.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Filename.
|
||||
fields : list
|
||||
jid, alias, timestamp.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None.
|
||||
"""
|
||||
data_dir = Config.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir): return False
|
||||
data_dir_logs = os.path.join(data_dir, 'logs')
|
||||
if not os.path.isdir(data_dir_logs): return False
|
||||
csv_file = os.path.join(data_dir_logs, f'{filename}.csv')
|
||||
if not os.path.exists(csv_file): return False
|
||||
with open(csv_file, 'r') as f:
|
||||
reader = csv.reader(f)
|
||||
for line in reader:
|
||||
if line[0] == fields[0]:
|
||||
return True
|
||||
|
||||
|
||||
def alias_jid_exist(filename, fields):
|
||||
"""
|
||||
Ceck whether Alias and Jabber ID exist.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Filename.
|
||||
fields : list
|
||||
jid, alias, timestamp.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None.
|
||||
"""
|
||||
data_dir = Config.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir): return False
|
||||
data_dir_logs = os.path.join(data_dir, 'logs')
|
||||
if not os.path.isdir(data_dir_logs): return False
|
||||
csv_file = os.path.join(data_dir_logs, f'{filename}.csv')
|
||||
if not os.path.exists(csv_file): return False
|
||||
with open(csv_file, 'r') as f:
|
||||
reader = csv.reader(f)
|
||||
for line in reader:
|
||||
if line[0] == fields[0] and line[1] == fields[1]:
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def csv_jid(filename, fields):
|
||||
"""
|
||||
Log Jabber ID to CSV file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Filename.
|
||||
fields : list
|
||||
jid, alias, timestamp.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None.
|
||||
"""
|
||||
data_dir = Config.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir): os.mkdir(data_dir)
|
||||
data_dir_logs = os.path.join(data_dir, 'logs')
|
||||
if not os.path.isdir(data_dir_logs): os.mkdir(data_dir_logs)
|
||||
csv_file = os.path.join(data_dir_logs, f'{filename}.csv')
|
||||
if not os.path.exists(csv_file):
|
||||
columns = ['jid', 'alias', 'timestamp']
|
||||
with open(csv_file, 'w') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(columns)
|
||||
with open(csv_file, 'a') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(fields)
|
||||
|
||||
|
||||
def csv(filename, fields):
|
||||
"""
|
||||
Log message or presence to CSV file.
|
||||
Log message to CSV file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Filename.
|
||||
fields : list
|
||||
type, timestamp, alias, body, lang, and identifier.
|
||||
message : slixmpp.stanza.message.Message
|
||||
Message object.
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
@ -220,12 +151,11 @@ class Log:
|
|||
"""
|
||||
data_dir = Config.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir): os.mkdir(data_dir)
|
||||
data_dir_logs = os.path.join(data_dir, 'logs')
|
||||
if not os.path.isdir(data_dir_logs): os.mkdir(data_dir_logs)
|
||||
csv_file = os.path.join(data_dir_logs, f'{filename}.csv')
|
||||
if not os.path.isdir(data_dir + "/logs"): os.mkdir(data_dir + "/logs")
|
||||
csv_file = os.path.join(data_dir, "logs", r"{}.csv".format(filename))
|
||||
if not os.path.exists(csv_file):
|
||||
columns = ['type', 'timestamp', 'alias', 'body', 'lang', 'identifier']
|
||||
with open(csv_file, 'w') as f:
|
||||
with open(csv_file, 'a') as f:
|
||||
writer = csv.writer(f)
|
||||
writer.writerow(columns)
|
||||
with open(csv_file, 'a') as f:
|
||||
|
@ -251,8 +181,8 @@ class Log:
|
|||
None.
|
||||
"""
|
||||
alias, content, identifier, timestamp = fields
|
||||
data_dir = DatabaseToml.get_default_data_directory()
|
||||
filename = DatabaseToml.get_data_file(data_dir, room)
|
||||
data_dir = Toml.get_default_data_directory()
|
||||
filename = Toml.get_data_file(data_dir, room)
|
||||
# filename = room + '.toml'
|
||||
entry = {}
|
||||
entry['alias'] = alias
|
||||
|
@ -295,41 +225,44 @@ class BlockList:
|
|||
with open(filename, 'w') as f: f.write(content)
|
||||
return filename
|
||||
|
||||
class String:
|
||||
|
||||
def md5_hash(url):
|
||||
def load_blocklist(self):
|
||||
filename = BlockList.get_filename()
|
||||
with open(filename, 'rb') as f:
|
||||
self.blocklist = tomllib.load(f)
|
||||
|
||||
|
||||
def add_entry_to_blocklist(self, jabber_id, node_id, item_id):
|
||||
"""
|
||||
Hash URL string to MD5 checksum.
|
||||
Update blocklist file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
URL.
|
||||
jabber_id : str
|
||||
Jabber ID.
|
||||
node_id : str
|
||||
Node name.
|
||||
item_id : str
|
||||
Item ID.
|
||||
|
||||
Returns
|
||||
-------
|
||||
url_digest : str
|
||||
Hashed URL as an MD5 checksum.
|
||||
None.
|
||||
"""
|
||||
url_encoded = url.encode()
|
||||
url_hashed = hashlib.md5(url_encoded)
|
||||
url_digest = url_hashed.hexdigest()
|
||||
return url_digest
|
||||
if jabber_id not in self.blocklist['entries']:
|
||||
self.blocklist['entries'][jabber_id] = {}
|
||||
if node_id not in self.blocklist['entries'][jabber_id]:
|
||||
self.blocklist['entries'][jabber_id][node_id] = []
|
||||
self.blocklist['entries'][jabber_id][node_id].append(item_id)
|
||||
data = self.blocklist
|
||||
content = tomli_w.dumps(data)
|
||||
filename = BlockList.get_filename()
|
||||
with open(filename, 'w') as f: f.write(content)
|
||||
|
||||
class Toml:
|
||||
|
||||
def open_file(filename: str) -> dict:
|
||||
with open(filename, mode="rb") as fn:
|
||||
data = tomllib.load(fn)
|
||||
return data
|
||||
|
||||
def save_file(filename: str, data: dict) -> None:
|
||||
with open(filename, 'w') as fn:
|
||||
data_as_string = tomli_w.dumps(data)
|
||||
fn.write(data_as_string)
|
||||
|
||||
class Url:
|
||||
|
||||
|
||||
def check_xmpp_uri(uri):
|
||||
"""
|
||||
Check validity of XMPP URI.
|
||||
|
@ -348,3 +281,26 @@ class Url:
|
|||
if parseaddr(jid)[1] != jid:
|
||||
jid = False
|
||||
return jid
|
||||
|
||||
|
||||
class String:
|
||||
|
||||
|
||||
def md5_hash(url):
|
||||
"""
|
||||
Hash URL string to MD5 checksum.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url : str
|
||||
URL.
|
||||
|
||||
Returns
|
||||
-------
|
||||
url_digest : str
|
||||
Hashed URL as an MD5 checksum.
|
||||
"""
|
||||
url_encoded = url.encode()
|
||||
url_hashed = hashlib.md5(url_encoded)
|
||||
url_digest = url_hashed.hexdigest()
|
||||
return url_digest
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
__version__ = '0.0.8'
|
||||
__version_info__ = (0, 0, 8)
|
||||
__version__ = '0.0.6'
|
||||
__version_info__ = (0, 0, 6)
|
||||
|
|
99
kaikout/xmpp/bookmark.py
Normal file
99
kaikout/xmpp/bookmark.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
|
||||
TODO
|
||||
|
||||
1) Save groupchat name instead of jid in field name.
|
||||
|
||||
"""
|
||||
|
||||
from slixmpp.plugins.xep_0048.stanza import Bookmarks
|
||||
|
||||
|
||||
class XmppBookmark:
|
||||
|
||||
|
||||
async def get_bookmarks(self):
|
||||
result = await self.plugin['xep_0048'].get_bookmarks()
|
||||
conferences = result['private']['bookmarks']['conferences']
|
||||
return conferences
|
||||
|
||||
|
||||
async def get_bookmark_properties(self, jid):
|
||||
result = await self.plugin['xep_0048'].get_bookmarks()
|
||||
groupchats = result['private']['bookmarks']['conferences']
|
||||
for groupchat in groupchats:
|
||||
if jid == groupchat['jid']:
|
||||
properties = {'password': groupchat['password'],
|
||||
'jid': groupchat['jid'],
|
||||
'name': groupchat['name'],
|
||||
'nick': groupchat['nick'],
|
||||
'autojoin': groupchat['autojoin'],
|
||||
'lang': groupchat['lang']}
|
||||
break
|
||||
return properties
|
||||
|
||||
|
||||
async def add(self, jid=None, properties=None):
|
||||
result = await self.plugin['xep_0048'].get_bookmarks()
|
||||
conferences = result['private']['bookmarks']['conferences']
|
||||
groupchats = []
|
||||
if properties:
|
||||
properties['jid'] = properties['room'] + '@' + properties['host']
|
||||
if not properties['alias']: properties['alias'] = self.alias
|
||||
else:
|
||||
properties = {
|
||||
'jid' : jid,
|
||||
'alias' : self.alias,
|
||||
'name' : jid.split('@')[0],
|
||||
'autojoin' : True,
|
||||
'password' : None,
|
||||
}
|
||||
for conference in conferences:
|
||||
if conference['jid'] != properties['jid']:
|
||||
groupchats.extend([conference])
|
||||
# FIXME Ad-hoc bookmark form is stuck
|
||||
# if jid not in groupchats:
|
||||
if properties['jid'] not in groupchats:
|
||||
bookmarks = Bookmarks()
|
||||
for groupchat in groupchats:
|
||||
# if groupchat['jid'] == groupchat['name']:
|
||||
# groupchat['name'] = groupchat['name'].split('@')[0]
|
||||
bookmarks.add_conference(groupchat['jid'],
|
||||
groupchat['nick'],
|
||||
name=groupchat['name'],
|
||||
autojoin=groupchat['autojoin'],
|
||||
password=groupchat['password'])
|
||||
bookmarks.add_conference(properties['jid'],
|
||||
properties['alias'],
|
||||
name=properties['name'],
|
||||
autojoin=properties['autojoin'],
|
||||
password=properties['password'])
|
||||
# await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||
self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||
# bookmarks = Bookmarks()
|
||||
# await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||
# print(await self.plugin['xep_0048'].get_bookmarks())
|
||||
|
||||
# bm = BookmarkStorage()
|
||||
# bm.conferences.append(Conference(muc_jid, autojoin=True, nick=self.alias))
|
||||
# await self['xep_0402'].publish(bm)
|
||||
|
||||
|
||||
async def remove(self, jid):
|
||||
result = await self.plugin['xep_0048'].get_bookmarks()
|
||||
conferences = result['private']['bookmarks']['conferences']
|
||||
groupchats = []
|
||||
for conference in conferences:
|
||||
if not conference['jid'] == jid:
|
||||
groupchats.extend([conference])
|
||||
bookmarks = Bookmarks()
|
||||
for groupchat in groupchats:
|
||||
bookmarks.add_conference(groupchat['jid'],
|
||||
groupchat['nick'],
|
||||
name=groupchat['name'],
|
||||
autojoin=groupchat['autojoin'],
|
||||
password=groupchat['password'])
|
||||
await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
|
@ -2,7 +2,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# from slixmpp import JID
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.utilities import Documentation
|
||||
from kaikout.xmpp.commands import XmppCommands
|
||||
|
@ -52,19 +52,13 @@ class XmppChat:
|
|||
if message_type == 'groupchat':
|
||||
alias = message['mucnick']
|
||||
room = message['mucroom']
|
||||
self_alias = XmppUtilities.get_self_alias(self, jid_bare)
|
||||
|
||||
alias_of_kaikout = XmppUtilities.get_self_alias(self, jid_bare)
|
||||
if (message['mucnick'] == self.alias or
|
||||
not XmppUtilities.is_moderator(self, room, alias) or
|
||||
(not message_body.startswith(self_alias + ' ') and
|
||||
not message_body.startswith(self_alias + ',') and
|
||||
not message_body.startswith(self_alias + ':'))):
|
||||
not message_body.startswith(alias_of_kaikout)):
|
||||
return
|
||||
|
||||
# Adding one to the length because of
|
||||
# assumption that a comma or a dot is added
|
||||
self_alias_length = len(self_alias) + 1
|
||||
command = message_body[self_alias_length:].lstrip()
|
||||
alias_of_kaikout_length = len(alias_of_kaikout) + 1
|
||||
command = message_body[alias_of_kaikout_length:].lstrip()
|
||||
elif message_type in ('chat', 'normal'):
|
||||
command = message_body
|
||||
jid_full = jid.full
|
||||
|
@ -183,7 +177,7 @@ class XmppChat:
|
|||
print(message)
|
||||
return
|
||||
|
||||
db_file = DatabaseToml.instantiate(self, room)
|
||||
db_file = Toml.instantiate(self, room)
|
||||
|
||||
# # Support private message via groupchat
|
||||
# # See https://codeberg.org/poezio/slixmpp/issues/3506
|
||||
|
|
|
@ -4,9 +4,10 @@
|
|||
import asyncio
|
||||
from datetime import datetime
|
||||
from kaikout.about import Documentation
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.utilities import Config, Log, BlockList, Toml
|
||||
from kaikout.utilities import Config, Log, BlockList
|
||||
from kaikout.xmpp.bookmark import XmppBookmark
|
||||
from kaikout.xmpp.chat import XmppChat
|
||||
from kaikout.xmpp.commands import XmppCommands
|
||||
from kaikout.xmpp.groupchat import XmppGroupchat
|
||||
|
@ -15,7 +16,6 @@ from kaikout.xmpp.muc import XmppMuc
|
|||
from kaikout.xmpp.observation import XmppObservation
|
||||
from kaikout.xmpp.pubsub import XmppPubsub
|
||||
from kaikout.xmpp.status import XmppStatus
|
||||
import os
|
||||
import slixmpp
|
||||
import time
|
||||
|
||||
|
@ -39,39 +39,23 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
|
||||
def __init__(self, jid, password, hostname, port, alias):
|
||||
slixmpp.ClientXMPP.__init__(self, jid, password, hostname, port, alias)
|
||||
self.directory_config = Config.get_default_config_directory()
|
||||
self.directory_shared = Config.get_default_data_directory()
|
||||
# A handler for accounts.
|
||||
filename_accounts = os.path.join(self.directory_config, 'accounts.toml')
|
||||
self.data_accounts = Toml.open_file(filename_accounts)
|
||||
self.data_accounts_xmpp = self.data_accounts['xmpp']
|
||||
# A handler for blocklist.
|
||||
self.filename_blocklist = os.path.join(self.directory_shared, 'blocklist.toml')
|
||||
self.blocklist = Toml.open_file(self.filename_blocklist)
|
||||
# A handler for blocklist.
|
||||
filename_rtbl = os.path.join(self.directory_config, 'rtbl.toml')
|
||||
self.data_rtbl = Toml.open_file(filename_rtbl)
|
||||
# A handler for settings.
|
||||
filename_settings = os.path.join(self.directory_config, 'settings.toml')
|
||||
self.data_settings = Toml.open_file(filename_settings)
|
||||
# Handlers for action messages.
|
||||
self.actions = {}
|
||||
self.action_count = 0
|
||||
# A handler for alias.
|
||||
self.alias = alias
|
||||
# A handler for bookmarks.
|
||||
self.filename_bookmarks = os.path.join(self.directory_config, 'bookmarks.toml')
|
||||
self.data_bookmarks = Toml.open_file(self.filename_bookmarks)
|
||||
self.bookmarks = self.data_bookmarks['bookmarks']
|
||||
# A handler for configuration.
|
||||
self.defaults = self.data_settings['defaults']
|
||||
self.defaults = Config.get_values('settings.toml', 'defaults')
|
||||
# Handlers for connectivity.
|
||||
self.connection_attempts = 0
|
||||
self.max_connection_attempts = 10
|
||||
self.task_ping_instance = {}
|
||||
self.reconnect_timeout = self.data_accounts_xmpp['settings']['reconnect_timeout']
|
||||
self.reconnect_timeout = Config.get_values('accounts.toml', 'xmpp')['settings']['reconnect_timeout']
|
||||
# A handler for operators.
|
||||
self.operators = self.data_accounts_xmpp['operators']
|
||||
self.operators = Config.get_values('accounts.toml', 'xmpp')['operators']
|
||||
# A handler for blocklist.
|
||||
#self.blocklist = {}
|
||||
BlockList.load_blocklist(self)
|
||||
# A handler for sessions.
|
||||
self.sessions = {}
|
||||
# A handler for settings.
|
||||
|
@ -138,34 +122,48 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
async def on_groupchat_invite(self, message):
|
||||
jid_full = str(message['from'])
|
||||
room = message['groupchat_invite']['jid']
|
||||
result = await XmppGroupchat.join(self, room)
|
||||
if result != 'ban':
|
||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
message_body = ('/me moderation chat bot. Jabber ID: xmpp:'
|
||||
f'{self.boundjid.bare}?message (groupchat_invite)')
|
||||
result = await XmppMuc.join(self, room)
|
||||
if result == 'ban':
|
||||
message_body = '{} is banned from {}'.format(self.alias, room)
|
||||
jid_bare = message['from'].bare
|
||||
# This might not be necessary because JID might not be of the inviter, but rather of the MUC
|
||||
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||
logger.warning(message_body)
|
||||
print("on_groupchat_invite")
|
||||
print("BAN BAN BAN BAN BAN")
|
||||
print("on_groupchat_invite")
|
||||
print(jid_full)
|
||||
print(jid_full)
|
||||
print(jid_full)
|
||||
print("on_groupchat_invite")
|
||||
print("BAN BAN BAN BAN BAN")
|
||||
print("on_groupchat_invite")
|
||||
else:
|
||||
await XmppBookmark.add(self, room)
|
||||
message_body = (
|
||||
'Greetings! I am {}, the news anchor.\n'
|
||||
'My job is to bring you the latest news from sources you '
|
||||
'provide me with.\n'
|
||||
'You may always reach me via xmpp:{}?message'
|
||||
.format(self.alias, self.boundjid.bare))
|
||||
XmppMessage.send(self, room, message_body, 'groupchat')
|
||||
XmppStatus.send_status_message(self, room)
|
||||
self.add_event_handler("muc::%s::got_online" % room, self.on_muc_got_online)
|
||||
self.add_event_handler("muc::%s::presence" % room, self.on_muc_presence)
|
||||
self.add_event_handler("muc::%s::self-presence" % room, self.on_muc_self_presence)
|
||||
|
||||
|
||||
async def on_groupchat_direct_invite(self, message):
|
||||
room = message['groupchat_invite']['jid']
|
||||
result = await XmppGroupchat.join(self, room)
|
||||
if result != 'ban':
|
||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
message_body = ('/me moderation chat bot. Jabber ID: xmpp:'
|
||||
f'{self.boundjid.bare}?message')
|
||||
result = await XmppMuc.join(self, room)
|
||||
if result == 'ban':
|
||||
message_body = '{} is banned from {}'.format(self.alias, room)
|
||||
jid_bare = message['from'].bare
|
||||
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||
logger.warning(message_body)
|
||||
else:
|
||||
await XmppBookmark.add(self, room)
|
||||
message_body = ('/me moderation chat bot. Jabber ID: xmpp:{}?message'
|
||||
.format(self.boundjid.bare))
|
||||
XmppMessage.send(self, room, message_body, 'groupchat')
|
||||
XmppStatus.send_status_message(self, room)
|
||||
self.add_event_handler("muc::%s::got_online" % room, self.on_muc_got_online)
|
||||
self.add_event_handler("muc::%s::presence" % room, self.on_muc_presence)
|
||||
self.add_event_handler("muc::%s::self-presence" % room, self.on_muc_self_presence)
|
||||
|
||||
|
||||
async def on_message(self, message):
|
||||
|
@ -182,29 +180,24 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
fields = ['message', timestamp_iso, alias, message_body, lang, identifier]
|
||||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||
Log.csv(filename, fields)
|
||||
db_file = DatabaseToml.instantiate(self, room)
|
||||
db_file = Toml.instantiate(self, room)
|
||||
timestamp = time.time()
|
||||
jid_full = XmppMuc.get_full_jid(self, room, alias)
|
||||
if jid_full and '/' in jid_full:
|
||||
jid_bare = jid_full.split('/')[0]
|
||||
XmppCommands.update_last_activity(
|
||||
self, room, jid_bare, db_file, timestamp)
|
||||
# DatabaseToml.load_jid_settings(self, room)
|
||||
# await XmppChat.process_message(self, message)
|
||||
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||
self.settings[room]['enabled'] and
|
||||
alias != self.alias and
|
||||
jid_bare and
|
||||
jid_bare not in self.settings[room]['jid_whitelist']):
|
||||
identifier = message['id']
|
||||
fields = [alias, message_body, identifier, timestamp]
|
||||
Log.toml(self, room, fields, 'message')
|
||||
# Check for message
|
||||
await XmppObservation.observe_message(self, db_file, alias,
|
||||
message_body, room)
|
||||
# Check for inactivity
|
||||
await XmppObservation.observe_inactivity(self, db_file,
|
||||
room)
|
||||
jid_bare = XmppMuc.get_full_jid(self, room, alias).split('/')[0]
|
||||
XmppCommands.update_last_activity(self, room, jid_bare, db_file, timestamp)
|
||||
# Toml.load_jid_settings(self, room)
|
||||
# await XmppChat.process_message(self, message)
|
||||
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||
self.settings[room]['enabled'] and
|
||||
alias != self.alias and
|
||||
jid_bare and
|
||||
jid_bare not in self.settings[room]['jid_whitelist']):
|
||||
identifier = message['id']
|
||||
fields = [alias, message_body, identifier, timestamp]
|
||||
Log.toml(self, room, fields, 'message')
|
||||
# Check for message
|
||||
await XmppObservation.observe_message(self, db_file, alias, message_body, room)
|
||||
# Check for inactivity
|
||||
await XmppObservation.observe_inactivity(self, db_file, room)
|
||||
|
||||
|
||||
async def on_muc_got_online(self, presence):
|
||||
|
@ -218,15 +211,6 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||
Log.csv(filename, fields)
|
||||
jid_bare = presence['muc']['jid'].bare
|
||||
fields = [jid_bare, alias, timestamp_iso]
|
||||
if jid_bare:
|
||||
if not Log.jid_exist(room, fields):
|
||||
message_body = (f'Welcome, {alias}! We hope that you would '
|
||||
'have a good time at this group chat.')
|
||||
XmppMessage.send(self, room, message_body, 'groupchat')
|
||||
Log.csv_jid(room, fields)
|
||||
elif not Log.alias_jid_exist(room, fields):
|
||||
Log.csv_jid(room, fields)
|
||||
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||
self.settings[room]['enabled'] and
|
||||
jid_bare and
|
||||
|
@ -247,9 +231,9 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
status_codes = presence['muc']['status_codes']
|
||||
actor_alias = presence['muc']['item']['actor']['nick']
|
||||
if 301 in status_codes:
|
||||
presence_body = f'User has been banned by {actor_alias}'
|
||||
presence_body = 'User has been banned by {}'.format(actor_alias)
|
||||
elif 307 in status_codes:
|
||||
presence_body = f'User has been kicked by {actor_alias}'
|
||||
presence_body = 'User has been kicked by {}'.format(actor_alias)
|
||||
else:
|
||||
presence_body = presence['status']
|
||||
room = presence['muc']['room']
|
||||
|
@ -258,7 +242,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||
# if identifier and presence_body:
|
||||
Log.csv(filename, fields)
|
||||
db_file = DatabaseToml.instantiate(self, room)
|
||||
db_file = Toml.instantiate(self, room)
|
||||
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||
self.settings[room]['enabled'] and
|
||||
alias != self.alias):
|
||||
|
@ -269,8 +253,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
await XmppObservation.observe_strikes(self, db_file, presence, room)
|
||||
if jid_bare and jid_bare not in self.settings[room]['jid_whitelist']:
|
||||
# Check for status message
|
||||
await XmppObservation.observe_status_message(
|
||||
self, alias, db_file, jid_bare, presence_body, room)
|
||||
await XmppObservation.observe_status_message(self, alias, db_file, jid_bare, presence_body, room)
|
||||
# Check for inactivity
|
||||
await XmppObservation.observe_inactivity(self, db_file, room)
|
||||
|
||||
|
@ -279,16 +262,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
actor = presence['muc']['item']['actor']['nick']
|
||||
alias = presence['muc']['nick']
|
||||
room = presence['muc']['room']
|
||||
if actor and alias == self.alias: XmppStatus.send_status_message(self,
|
||||
room)
|
||||
# TODO Check whether group chat is not anonymous
|
||||
if XmppMuc.is_moderator(self, room, self.alias):
|
||||
timestamp_iso = datetime.now().isoformat()
|
||||
for alias in XmppMuc.get_roster(self, room):
|
||||
jid_bare = XmppMuc.get_full_jid(self, room, alias).split('/')[0]
|
||||
fields = [jid_bare, alias, timestamp_iso]
|
||||
if not Log.alias_jid_exist(room, fields): Log.csv_jid(room,
|
||||
fields)
|
||||
if actor and alias == self.alias: XmppStatus.send_status_message(self, room)
|
||||
|
||||
|
||||
def on_reactions(self, message):
|
||||
|
@ -326,7 +300,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
"""
|
||||
# self.command_list()
|
||||
# await self.get_roster()
|
||||
rtbl_sources = self.data_rtbl['sources']
|
||||
rtbl_sources = Config.get_values('rtbl.toml')['sources']
|
||||
for source in rtbl_sources:
|
||||
jabber_id = source['jabber_id']
|
||||
node_id = source['node_id']
|
||||
|
@ -334,23 +308,28 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
if subscribe['pubsub']['subscription']['subscription'] == 'subscribed':
|
||||
rtbl_list = await XmppPubsub.get_items(self, jabber_id, node_id)
|
||||
rtbl_items = rtbl_list['pubsub']['items']
|
||||
muc_bans_sha256 = self.blocklist['entries']['xmppbl.org']['muc_bans_sha256']
|
||||
for item in rtbl_items:
|
||||
exist = False
|
||||
item_id = item['id']
|
||||
if item_id not in muc_bans_sha256: muc_bans_sha256.append(item_id)
|
||||
# TODO Extract items item_payload.find(namespace + 'title')
|
||||
# NOTE (Pdb)
|
||||
# for i in item['payload'].iter(): i.attrib
|
||||
# {'reason': 'urn:xmpp:reporting:abuse'}
|
||||
self.blocklist['entries']['xmppbl.org']['muc_bans_sha256'] = muc_bans_sha256
|
||||
Toml.save_file(self.filename_blocklist, self.blocklist)
|
||||
del self.filename_blocklist
|
||||
for jid in self.blocklist['entries']:
|
||||
for node in jid:
|
||||
for item in node:
|
||||
if item_id == item:
|
||||
exist = True
|
||||
break
|
||||
if not exist:
|
||||
# TODO Extract items item_payload.find(namespace + 'title')
|
||||
# NOTE (Pdb)
|
||||
# for i in item['payload'].iter(): i.attrib
|
||||
# {'reason': 'urn:xmpp:reporting:abuse'}
|
||||
BlockList.add_entry_to_blocklist(self, jabber_id, node_id, item_id)
|
||||
# subscribe['from'] = xmppbl.org
|
||||
# subscribe['pubsub']['subscription']['node'] = 'muc_bans_sha256'
|
||||
subscriptions = await XmppPubsub.get_node_subscriptions(
|
||||
self, jabber_id, node_id)
|
||||
subscriptions = await XmppPubsub.get_node_subscriptions(self, jabber_id, node_id)
|
||||
await self['xep_0115'].update_caps()
|
||||
rooms = await XmppGroupchat.autojoin(self)
|
||||
bookmarks = await XmppBookmark.get_bookmarks(self)
|
||||
print(bookmarks)
|
||||
rooms = await XmppGroupchat.autojoin(self, bookmarks)
|
||||
# See also get_joined_rooms of slixmpp.plugins.xep_0045
|
||||
for room in rooms:
|
||||
XmppStatus.send_status_message(self, room)
|
||||
|
|
|
@ -5,9 +5,10 @@ import asyncio
|
|||
import kaikout.config as config
|
||||
from kaikout.config import Config
|
||||
from kaikout.log import Logger
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.utilities import Documentation, Toml, Url
|
||||
from kaikout.database import Toml
|
||||
from kaikout.utilities import Documentation, Url
|
||||
from kaikout.version import __version__
|
||||
from kaikout.xmpp.bookmark import XmppBookmark
|
||||
from kaikout.xmpp.muc import XmppMuc
|
||||
from kaikout.xmpp.status import XmppStatus
|
||||
from kaikout.xmpp.utilities import XmppUtilities
|
||||
|
@ -36,7 +37,7 @@ class XmppCommands:
|
|||
async def clear_filter(self, room, db_file, key):
|
||||
value = []
|
||||
self.settings[room][key] = value
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, key, value)
|
||||
Toml.update_jid_settings(self, room, db_file, key, value)
|
||||
message = 'Filter {} has been purged.'.format(key)
|
||||
return message
|
||||
|
||||
|
@ -80,17 +81,18 @@ class XmppCommands:
|
|||
|
||||
|
||||
async def bookmark_add(self, muc_jid):
|
||||
if muc_jid not in self.bookmarks: self.bookmarks.append(muc_jid)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
return f'Groupchat {muc_jid} has been added to bookmarks.'
|
||||
await XmppBookmark.add(self, jid=muc_jid)
|
||||
message = ('Groupchat {} has been added to bookmarks.'
|
||||
.format(muc_jid))
|
||||
return message
|
||||
|
||||
|
||||
async def bookmark_del(self, muc_jid):
|
||||
if muc_jid in self.bookmarks: self.bookmarks.remove(muc_jid)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
return f'Groupchat {muc_jid} has been removed from bookmarks.'
|
||||
|
||||
|
||||
await XmppBookmark.remove(self, muc_jid)
|
||||
message = ('Groupchat {} has been removed from bookmarks.'
|
||||
.format(muc_jid))
|
||||
return message
|
||||
|
||||
async def invite_jid_to_muc(self, jid_bare):
|
||||
muc_jid = 'slixfeed@chat.woodpeckersnest.space'
|
||||
if await XmppUtilities.get_chat_type(self, jid_bare) == 'chat':
|
||||
|
@ -120,13 +122,12 @@ class XmppCommands:
|
|||
if muc_jid:
|
||||
# TODO probe JID and confirm it's a groupchat
|
||||
result = await XmppMuc.join(self, muc_jid)
|
||||
# await XmppBookmark.add(self, jid=muc_jid)
|
||||
if result == 'ban':
|
||||
message = '{} is banned from {}'.format(self.alias, muc_jid)
|
||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
||||
else:
|
||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
||||
await XmppBookmark.add(self, muc_jid)
|
||||
message = 'Joined groupchat {}'.format(muc_jid)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
else:
|
||||
message = '> {}\nGroupchat JID appears to be invalid.'.format(muc_jid)
|
||||
else:
|
||||
|
@ -136,8 +137,7 @@ class XmppCommands:
|
|||
|
||||
async def muc_leave(self, room):
|
||||
XmppMuc.leave(self, room)
|
||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
await XmppBookmark.remove(self, room)
|
||||
|
||||
|
||||
async def outcast(self, room, alias, reason):
|
||||
|
@ -163,11 +163,14 @@ class XmppCommands:
|
|||
|
||||
|
||||
async def print_bookmarks(self):
|
||||
conferences = self.bookmarks
|
||||
conferences = await XmppBookmark.get_bookmarks(self)
|
||||
message = '\nList of groupchats:\n\n```\n'
|
||||
for conference in conferences:
|
||||
message += f'{conference}\n'
|
||||
message += (f'```\nTotal of {len(conferences)} groupchats.\n')
|
||||
message += ('Name: {}\n'
|
||||
'Room: {}\n'
|
||||
'\n'
|
||||
.format(conference['name'], conference['jid']))
|
||||
message += ('```\nTotal of {} groupchats.\n'.format(len(conferences)))
|
||||
return message
|
||||
|
||||
|
||||
|
@ -324,7 +327,7 @@ class XmppCommands:
|
|||
if jid_full:
|
||||
jid_bare = jid_full.split('/')[0]
|
||||
scores[jid_bare] = scores[jid_bare] + 1 if jid_bare in scores else 1
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'scores', scores)
|
||||
Toml.update_jid_settings(self, room, db_file, 'scores', scores)
|
||||
time.sleep(5)
|
||||
del self.actions[room][task_number]
|
||||
XmppStatus.send_status_message(self, room)
|
||||
|
@ -352,7 +355,7 @@ class XmppCommands:
|
|||
"""
|
||||
scores = self.settings[room]['score_ban'] if 'score_ban' in self.settings[room] else {}
|
||||
scores[jid_bare] = scores[jid_bare] + 1 if jid_bare in scores else 1
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'score_ban', scores)
|
||||
Toml.update_jid_settings(self, room, db_file, 'score_ban', scores)
|
||||
# result = scores[jid_bare]
|
||||
# return result
|
||||
|
||||
|
@ -377,7 +380,7 @@ class XmppCommands:
|
|||
"""
|
||||
scores = self.settings[room]['score_kick'] if 'score_kick' in self.settings[room] else {}
|
||||
scores[jid_bare] = scores[jid_bare] + 1 if jid_bare in scores else 1
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'score_kick', scores)
|
||||
Toml.update_jid_settings(self, room, db_file, 'score_kick', scores)
|
||||
# result = scores[jid_bare]
|
||||
# return result
|
||||
|
||||
|
@ -404,7 +407,7 @@ class XmppCommands:
|
|||
"""
|
||||
activity = self.settings[room]['last_activity'] if 'last_activity' in self.settings[room] else {}
|
||||
activity[jid_bare] = timestamp
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'last_activity', activity)
|
||||
Toml.update_jid_settings(self, room, db_file, 'last_activity', activity)
|
||||
|
||||
|
||||
def remove_last_activity(self, room, jid_bare, db_file):
|
||||
|
@ -427,7 +430,7 @@ class XmppCommands:
|
|||
"""
|
||||
activity = self.settings[room]['last_activity'] if 'last_activity' in self.settings[room] else {}
|
||||
del activity[jid_bare]
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'last_activity', activity)
|
||||
Toml.update_jid_settings(self, room, db_file, 'last_activity', activity)
|
||||
|
||||
|
||||
def raise_score_inactivity(self, room, alias, db_file):
|
||||
|
@ -459,7 +462,7 @@ class XmppCommands:
|
|||
if jid_full:
|
||||
jid_bare = jid_full.split('/')[0]
|
||||
scores_inactivity[jid_bare] = scores_inactivity[jid_bare] + 1 if jid_bare in scores_inactivity else 1
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, 'scores_inactivity', scores_inactivity)
|
||||
Toml.update_jid_settings(self, room, db_file, 'scores_inactivity', scores_inactivity)
|
||||
time.sleep(5)
|
||||
del self.actions[room][task_number]
|
||||
XmppStatus.send_status_message(self, room)
|
||||
|
@ -471,16 +474,16 @@ class XmppCommands:
|
|||
if key:
|
||||
value = self.defaults[key]
|
||||
self.settings[room][key] = value
|
||||
# data_dir = DatabaseToml.get_default_data_directory()
|
||||
# db_file = DatabaseToml.get_data_file(data_dir, jid_bare)
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, key, value)
|
||||
# data_dir = Toml.get_default_data_directory()
|
||||
# db_file = Toml.get_data_file(data_dir, jid_bare)
|
||||
Toml.update_jid_settings(self, room, db_file, key, value)
|
||||
message = ('Setting {} has been restored to default value.'
|
||||
.format(key))
|
||||
else:
|
||||
self.settings = self.defaults
|
||||
data_dir = DatabaseToml.get_default_data_directory()
|
||||
db_file = DatabaseToml.get_data_file(data_dir, room)
|
||||
DatabaseToml.create_settings_file(self, db_file)
|
||||
data_dir = Toml.get_default_data_directory()
|
||||
db_file = Toml.get_data_file(data_dir, room)
|
||||
Toml.create_settings_file(self, db_file)
|
||||
message = 'Default settings have been restored.'
|
||||
return message
|
||||
|
||||
|
@ -521,7 +524,7 @@ class XmppCommands:
|
|||
string_trim = string.strip()
|
||||
string_list.remove(string_trim)
|
||||
processed_strings.append(string_trim)
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, filter, string_list)
|
||||
Toml.update_jid_settings(self, room, db_file, filter, string_list)
|
||||
processed_strings.sort()
|
||||
if processed_strings:
|
||||
message = 'Strings "{}" have been {} list "{}".'.format(
|
||||
|
@ -548,4 +551,4 @@ class XmppCommands:
|
|||
|
||||
|
||||
def update_setting_value(self, room, db_file, key, value):
|
||||
DatabaseToml.update_jid_settings(self, room, db_file, key, value)
|
||||
Toml.update_jid_settings(self, room, db_file, key, value)
|
||||
|
|
|
@ -1,52 +1,58 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from kaikout.xmpp.message import XmppMessage
|
||||
"""
|
||||
|
||||
TODO
|
||||
|
||||
1) Send message to inviter that bot has joined to groupchat.
|
||||
|
||||
2) If groupchat requires captcha, send the consequent message.
|
||||
|
||||
3) If groupchat error is received, send that error message to inviter.
|
||||
|
||||
FIXME
|
||||
|
||||
1) Save name of groupchat instead of jid as name
|
||||
|
||||
"""
|
||||
from kaikout.xmpp.bookmark import XmppBookmark
|
||||
from kaikout.xmpp.muc import XmppMuc
|
||||
from kaikout.xmpp.status import XmppStatus
|
||||
from kaikout.utilities import Toml
|
||||
from kaikout.log import Logger, Message
|
||||
import random
|
||||
|
||||
logger = Logger(__name__)
|
||||
|
||||
|
||||
class XmppGroupchat:
|
||||
|
||||
async def join(self, room):
|
||||
result = await XmppMuc.join(self, room)
|
||||
if result == 'ban':
|
||||
message_body = '{} is banned from {}'.format(self.alias, room)
|
||||
jid_bare = message['from'].bare
|
||||
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||
logger.warning(message_body)
|
||||
elif result == 'conflict':
|
||||
while result == 'conflict':
|
||||
number = str(random.randrange(1000, 5000))
|
||||
print(f'Conflict. Atempting to join to {room} as {self.alias} #{number}')
|
||||
result = await XmppMuc.join(self, room, f'{self.alias} #{number}')
|
||||
else:
|
||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
return result
|
||||
|
||||
async def autojoin(self):
|
||||
mucs_joined = []
|
||||
for room in self.bookmarks:
|
||||
alias = self.alias
|
||||
print(f'Joining to MUC {room} ...')
|
||||
#Message.printer(f'Joining to MUC {room} ...')
|
||||
result = await XmppMuc.join(self, room)
|
||||
if result == 'ban':
|
||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
||||
logger.warning(f'{alias} is banned from {room}')
|
||||
logger.warning(f'Groupchat {room} has been removed from bookmarks')
|
||||
elif result == 'conflict':
|
||||
while result == 'conflict':
|
||||
number = str(random.randrange(1000, 5000))
|
||||
print(f'Conflict. Atempting to join to {room} as {self.alias} #{number}')
|
||||
result = await XmppMuc.join(self, room, f'{alias} #{number}')
|
||||
else:
|
||||
mucs_joined.append(room)
|
||||
return mucs_joined
|
||||
async def autojoin(self, bookmarks):
|
||||
mucs_join_success = []
|
||||
for bookmark in bookmarks:
|
||||
if bookmark["jid"] and bookmark["autojoin"]:
|
||||
if not bookmark["nick"]:
|
||||
bookmark["nick"] = self.alias
|
||||
logger.error('Alias (i.e. Nicknname) is missing for '
|
||||
'bookmark {}'.format(bookmark['name']))
|
||||
alias = bookmark["nick"]
|
||||
room = bookmark["jid"]
|
||||
Message.printer('Joining to MUC {} ...'.format(room))
|
||||
result = await XmppMuc.join(self, room, alias)
|
||||
if result == 'ban':
|
||||
await XmppBookmark.remove(self, room)
|
||||
logger.warning('{} is banned from {}'.format(self.alias, room))
|
||||
logger.warning('Groupchat {} has been removed from bookmarks'
|
||||
.format(room))
|
||||
else:
|
||||
mucs_join_success.append(room)
|
||||
logger.info('Autojoin groupchat\n'
|
||||
'Name : {}\n'
|
||||
'JID : {}\n'
|
||||
'Alias : {}\n'
|
||||
.format(bookmark["name"],
|
||||
bookmark["jid"],
|
||||
bookmark["nick"]))
|
||||
elif not bookmark["jid"]:
|
||||
logger.error('JID is missing for bookmark {}'
|
||||
.format(bookmark['name']))
|
||||
return mucs_join_success
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.xmpp.commands import XmppCommands
|
||||
|
||||
|
@ -17,8 +17,8 @@ class XmppModeration:
|
|||
if jid_bare not in self.settings[room]['last_activity']:
|
||||
# self.settings[room]['last_activity'][jid_bare] = timestamp
|
||||
# last_activity_for_jid = self.settings[room]['last_activity'][jid_bare]
|
||||
db_file = DatabaseToml.instantiate(self, room)
|
||||
# DatabaseToml.update_jid_settings(self, room, db_file, 'last_activity', last_activity_for_jid)
|
||||
db_file = Toml.instantiate(self, room)
|
||||
# Toml.update_jid_settings(self, room, db_file, 'last_activity', last_activity_for_jid)
|
||||
XmppCommands.update_last_activity(self, room, jid_bare, db_file, timestamp)
|
||||
else:
|
||||
jid_last_activity = self.settings[room]['last_activity'][jid_bare]
|
||||
|
|
|
@ -16,7 +16,6 @@ FIXME
|
|||
1) Save name of groupchat instead of jid as name
|
||||
|
||||
"""
|
||||
from asyncio import TimeoutError
|
||||
from slixmpp.exceptions import IqError, IqTimeout, PresenceError
|
||||
from kaikout.log import Logger
|
||||
|
||||
|
@ -93,18 +92,40 @@ class XmppMuc:
|
|||
def is_moderator(self, room, alias):
|
||||
"""Check if given JID is a moderator"""
|
||||
role = self.plugin['xep_0045'].get_jid_property(room, alias, 'role')
|
||||
result = True if role == 'moderator' else False
|
||||
if role == 'moderator':
|
||||
result = True
|
||||
else:
|
||||
result = False
|
||||
return result
|
||||
|
||||
|
||||
async def join(self, jid_bare, alias=None, password=None):
|
||||
logger.info('Joining groupchat\nJID : {}\n'.format(jid_bare))
|
||||
#jid_from = str(self.boundjid) if self.is_component else None
|
||||
async def join(self, jid, alias=None, password=None):
|
||||
# token = await initdb(
|
||||
# muc_jid,
|
||||
# sqlite.get_setting_value,
|
||||
# "token"
|
||||
# )
|
||||
# if token != "accepted":
|
||||
# token = randrange(10000, 99999)
|
||||
# await initdb(
|
||||
# muc_jid,
|
||||
# sqlite.update_setting_value,
|
||||
# ["token", token]
|
||||
# )
|
||||
# self.send_message(
|
||||
# mto=inviter,
|
||||
# mfrom=self.boundjid.bare,
|
||||
# mbody=(
|
||||
# "Send activation token {} to groupchat xmpp:{}?join."
|
||||
# ).format(token, muc_jid)
|
||||
# )
|
||||
logger.info('Joining groupchat\nJID : {}\n'.format(jid))
|
||||
jid_from = str(self.boundjid) if self.is_component else None
|
||||
if not alias: alias = self.alias
|
||||
try:
|
||||
await self.plugin['xep_0045'].join_muc_wait(jid_bare,
|
||||
await self.plugin['xep_0045'].join_muc_wait(jid,
|
||||
alias,
|
||||
#presence_options = {"pfrom" : jid_from},
|
||||
presence_options = {"pfrom" : jid_from},
|
||||
password=password,
|
||||
maxchars=0,
|
||||
maxstanzas=0,
|
||||
|
@ -115,35 +136,22 @@ class XmppMuc:
|
|||
except IqError as e:
|
||||
logger.error('Error XmppIQ')
|
||||
logger.error(str(e))
|
||||
logger.error(jid_bare)
|
||||
logger.error(jid)
|
||||
result = 'error'
|
||||
except IqTimeout as e:
|
||||
logger.error('Timeout XmppIQ')
|
||||
logger.error(str(e))
|
||||
logger.error(jid_bare)
|
||||
result = 'timeout'
|
||||
except TimeoutError as e:
|
||||
logger.error('Timeout AsyncIO')
|
||||
logger.error(str(e))
|
||||
logger.error(jid_bare)
|
||||
logger.error(jid)
|
||||
result = 'timeout'
|
||||
except PresenceError as e:
|
||||
logger.error('Error Presence')
|
||||
logger.error(str(e))
|
||||
if (e.condition == 'forbidden' and
|
||||
e.presence['error']['code'] == '403'):
|
||||
logger.warning('{} is banned from {}'.format(self.alias, jid_bare))
|
||||
logger.warning('{} is banned from {}'.format(self.alias, jid))
|
||||
result = 'ban'
|
||||
elif e.condition == 'conflict':
|
||||
logger.warning(e.presence['error']['text'])
|
||||
result = 'conflict'
|
||||
else:
|
||||
result = 'error'
|
||||
except Exception as e:
|
||||
logger.error('Unknown error')
|
||||
logger.error(str(e))
|
||||
logger.error(jid_bare)
|
||||
result = 'unknown'
|
||||
return result
|
||||
|
||||
|
||||
|
@ -175,11 +183,6 @@ class XmppMuc:
|
|||
logger.error('Could not set affiliation at room: {}'.format(room))
|
||||
logger.error(str(e))
|
||||
logger.error(room)
|
||||
except Exception as e:
|
||||
logger.error('Unknown error')
|
||||
logger.error('Could not set affiliation at room: {}'.format(room))
|
||||
logger.error(str(e))
|
||||
logger.error(room)
|
||||
|
||||
|
||||
async def set_role(self, room, alias, role, reason=None):
|
||||
|
@ -192,8 +195,3 @@ class XmppMuc:
|
|||
logger.error('Could not set role of alias: {}'.format(alias))
|
||||
logger.error(str(e))
|
||||
logger.error(room)
|
||||
except Exception as e:
|
||||
logger.error('Unknown error')
|
||||
logger.error('Could not set role of alias: {}'.format(alias))
|
||||
logger.error(str(e))
|
||||
logger.error(room)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import asyncio
|
||||
from hashlib import sha256
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.xmpp.commands import XmppCommands
|
||||
from kaikout.xmpp.message import XmppMessage
|
||||
|
@ -70,7 +70,7 @@ class XmppObservation:
|
|||
'You are expected to be expelled from '
|
||||
'groupchat {} within {} hour time.'
|
||||
.format(room, int(span) or 'an'))
|
||||
DatabaseToml.update_jid_settings(
|
||||
Toml.update_jid_settings(
|
||||
self, room, db_file, 'inactivity_notice', noticed_jids)
|
||||
if message_to_participant:
|
||||
XmppMessage.send(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from kaikout.database import DatabaseToml
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.xmpp.presence import XmppPresence
|
||||
from kaikout.xmpp.utilities import XmppUtilities
|
||||
|
@ -27,8 +27,8 @@ class XmppStatus:
|
|||
if not status_mode and not status_text:
|
||||
if XmppUtilities.is_moderator(self, room, self.alias):
|
||||
if room not in self.settings:
|
||||
DatabaseToml.instantiate(self, room)
|
||||
# DatabaseToml.load_jid_settings(self, room)
|
||||
Toml.instantiate(self, room)
|
||||
# Toml.load_jid_settings(self, room)
|
||||
if self.settings[room]['enabled']:
|
||||
jid_task = self.actions[room] if room in self.actions else None
|
||||
if jid_task and len(jid_task):
|
||||
|
|
Loading…
Reference in a new issue