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
|
$ 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.
|
It is advised to use a dedicated extra account for KaikOut.
|
||||||
|
|
||||||
## Recommended Clients
|
## Recommended Clients
|
||||||
|
|
|
@ -6,37 +6,18 @@
|
||||||
# See the file LICENSE for copying permission.
|
# See the file LICENSE for copying permission.
|
||||||
|
|
||||||
# from kaikout.about import Documentation
|
# 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.chat import XmppChat
|
||||||
from kaikout.xmpp.client import XmppClient
|
from kaikout.xmpp.client import XmppClient
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
from erdhe import integrate_with_kaikout # Add this import
|
||||||
import logging
|
import logging
|
||||||
import os
|
# import os
|
||||||
import shutil
|
|
||||||
# import slixmpp
|
# import slixmpp
|
||||||
# import sys
|
# import sys
|
||||||
|
|
||||||
def main():
|
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.
|
# Setup the command line arguments.
|
||||||
parser = ArgumentParser(description=XmppClient.__doc__)
|
parser = ArgumentParser(description=XmppClient.__doc__)
|
||||||
|
|
||||||
|
@ -48,52 +29,39 @@ def main():
|
||||||
action="store_const", dest="loglevel",
|
action="store_const", dest="loglevel",
|
||||||
const=logging.DEBUG, default=logging.INFO)
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Setup logging.
|
# Setup logging.
|
||||||
logging.basicConfig(level=args.loglevel,
|
logging.basicConfig(level=args.loglevel,
|
||||||
format='%(levelname)-8s %(message)s')
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
# Configure settings file
|
account_xmpp = Config.get_values('accounts.toml', 'xmpp')
|
||||||
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)
|
|
||||||
|
|
||||||
data_settings = Toml.open_file(file_settings)
|
if args.jid is None and not account_xmpp['client']['jid']:
|
||||||
|
args.jid = input("Username: ")
|
||||||
# Configure account
|
if args.password is None and not account_xmpp['client']['password']:
|
||||||
data_settings_account = data_settings['xmpp']['client']
|
args.password = getpass("Password: ")
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
# Try configuration file
|
# Try configuration file
|
||||||
jid = data_settings_account['jid']
|
if 'client' in account_xmpp:
|
||||||
password = data_settings_account['password']
|
jid = account_xmpp['client']['jid']
|
||||||
alias = data_settings_account['alias']
|
password = account_xmpp['client']['password']
|
||||||
# TODO
|
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
|
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
|
port = account_xmpp['client']['port'] if 'port' in account_xmpp['client'] else None
|
||||||
hostname = port = None
|
XmppClient(jid, password, hostname, port, alias)
|
||||||
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__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
|
@ -26,8 +26,8 @@ BDAY = "20 June 2024"
|
||||||
#DESC = ""
|
#DESC = ""
|
||||||
|
|
||||||
[xmpp.client]
|
[xmpp.client]
|
||||||
alias = ""
|
alias = "KaikOut"
|
||||||
jid = ""
|
jid = "/KaikOut"
|
||||||
password = ""
|
password = ""
|
||||||
|
|
||||||
[tox]
|
[tox]
|
|
@ -1,2 +0,0 @@
|
||||||
[entries."xmppbl.org"]
|
|
||||||
muc_bans_sha256 = []
|
|
|
@ -16,16 +16,16 @@ class Config:
|
||||||
|
|
||||||
|
|
||||||
def get_default_data_directory():
|
def get_default_data_directory():
|
||||||
directory_home = os.environ.get('HOME')
|
if os.environ.get('HOME'):
|
||||||
if directory_home:
|
data_home = os.path.join(os.environ.get('HOME'), '.local', 'share')
|
||||||
data_home = os.path.join(directory_home, '.local', 'share')
|
|
||||||
return os.path.join(data_home, 'kaikout')
|
return os.path.join(data_home, 'kaikout')
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
data_home = os.environ.get('APPDATA')
|
data_home = os.environ.get('APPDATA')
|
||||||
if data_home is None:
|
if data_home is None:
|
||||||
return 'kaikout_data'
|
return os.path.join(
|
||||||
|
os.path.dirname(__file__) + '/kaikout_data')
|
||||||
else:
|
else:
|
||||||
return 'kaikout_data'
|
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||||
|
|
||||||
|
|
||||||
def get_default_config_directory():
|
def get_default_config_directory():
|
||||||
|
@ -42,20 +42,19 @@ class Config:
|
||||||
str
|
str
|
||||||
Path to configuration directory.
|
Path to configuration directory.
|
||||||
"""
|
"""
|
||||||
# directory_config_home = xdg.BaseDirectory.xdg_config_home
|
# config_home = xdg.BaseDirectory.xdg_config_home
|
||||||
directory_config_home = os.environ.get('XDG_CONFIG_HOME')
|
config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||||
if directory_config_home is None:
|
if config_home is None:
|
||||||
directory_home = os.environ.get('HOME')
|
if os.environ.get('HOME') is None:
|
||||||
if directory_home is None:
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
directory_config_home = os.environ.get('APPDATA')
|
config_home = os.environ.get('APPDATA')
|
||||||
if directory_config_home is None:
|
if config_home is None:
|
||||||
return 'kaikout_config'
|
return os.path.abspath('.')
|
||||||
else:
|
else:
|
||||||
return 'kaikout_config'
|
return os.path.abspath('.')
|
||||||
else:
|
else:
|
||||||
directory_config_home = os.path.join(directory_home, '.config')
|
config_home = os.path.join(os.environ.get('HOME'), '.config')
|
||||||
return os.path.join(directory_config_home, 'kaikout')
|
return os.path.join(config_home, 'kaikout')
|
||||||
|
|
||||||
|
|
||||||
def get_values(filename, key=None):
|
def get_values(filename, key=None):
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
bookmarks = []
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
from asyncio import Lock
|
from asyncio import Lock
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
|
from sqlite3 import connect, Error, IntegrityError
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
@ -17,10 +18,429 @@ import tomllib
|
||||||
# # with start_action(action_type="search_entries()", query=query):
|
# # with start_action(action_type="search_entries()", query=query):
|
||||||
# # with start_action(action_type="check_entry()", link=link):
|
# # with start_action(action_type="check_entry()", link=link):
|
||||||
|
|
||||||
|
CURSORS = {}
|
||||||
|
|
||||||
|
# aiosqlite
|
||||||
|
DBLOCK = Lock()
|
||||||
|
|
||||||
logger = Logger(__name__)
|
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):
|
def instantiate(self, room):
|
||||||
|
@ -42,16 +462,15 @@ class DatabaseToml:
|
||||||
object
|
object
|
||||||
Coroutine object.
|
Coroutine object.
|
||||||
"""
|
"""
|
||||||
data_dir = DatabaseToml.get_default_data_directory()
|
data_dir = Toml.get_default_data_directory()
|
||||||
if not os.path.isdir(data_dir):
|
if not os.path.isdir(data_dir):
|
||||||
os.mkdir(data_dir)
|
os.mkdir(data_dir)
|
||||||
data_dir_toml = os.path.join(data_dir, 'toml')
|
if not os.path.isdir(data_dir + "/toml"):
|
||||||
if not os.path.isdir(data_dir_toml):
|
os.mkdir(data_dir + "/toml")
|
||||||
os.mkdir(data_dir_toml)
|
filename = os.path.join(data_dir, "toml", r"{}.toml".format(room))
|
||||||
filename = os.path.join(data_dir_toml, f'{room}.toml')
|
|
||||||
if not os.path.exists(filename):
|
if not os.path.exists(filename):
|
||||||
DatabaseToml.create_settings_file(self, filename)
|
Toml.create_settings_file(self, filename)
|
||||||
DatabaseToml.load_jid_settings(self, room, filename)
|
Toml.load_jid_settings(self, room, filename)
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,13 +481,14 @@ class DatabaseToml:
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
data_home = os.environ.get('APPDATA')
|
data_home = os.environ.get('APPDATA')
|
||||||
if data_home is None:
|
if data_home is None:
|
||||||
return 'kaikout_data'
|
return os.path.join(
|
||||||
|
os.path.dirname(__file__) + '/kaikout_data')
|
||||||
else:
|
else:
|
||||||
return 'kaikout_data'
|
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||||
|
|
||||||
|
|
||||||
def get_data_file(data_dir, room):
|
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
|
return toml_file
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,8 +499,8 @@ class DatabaseToml:
|
||||||
|
|
||||||
|
|
||||||
def load_jid_settings(self, room, filename):
|
def load_jid_settings(self, room, filename):
|
||||||
# data_dir = DatabaseToml.get_default_data_directory()
|
# data_dir = Toml.get_default_data_directory()
|
||||||
# filename = DatabaseToml.get_data_file(data_dir, room)
|
# filename = Toml.get_data_file(data_dir, room)
|
||||||
with open(filename, 'rb') as f: self.settings[room] = tomllib.load(f)
|
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
|
import csv
|
||||||
from email.utils import parseaddr
|
from email.utils import parseaddr
|
||||||
import hashlib
|
import hashlib
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
#import kaikout.sqlite as sqlite
|
#import kaikout.sqlite as sqlite
|
||||||
import os
|
import os
|
||||||
|
@ -37,16 +37,16 @@ class Config:
|
||||||
str
|
str
|
||||||
Path to data directory.
|
Path to data directory.
|
||||||
"""
|
"""
|
||||||
directory_home = os.environ.get('HOME')
|
if os.environ.get('HOME'):
|
||||||
if directory_home:
|
data_home = os.path.join(os.environ.get('HOME'), '.local', 'share')
|
||||||
data_home = os.path.join(directory_home, '.local', 'share')
|
|
||||||
return os.path.join(data_home, 'kaikout')
|
return os.path.join(data_home, 'kaikout')
|
||||||
elif sys.platform == 'win32':
|
elif sys.platform == 'win32':
|
||||||
data_home = os.environ.get('APPDATA')
|
data_home = os.environ.get('APPDATA')
|
||||||
if data_home is None:
|
if data_home is None:
|
||||||
return 'kaikout_data'
|
return os.path.join(
|
||||||
|
os.path.dirname(__file__) + '/kaikout_data')
|
||||||
else:
|
else:
|
||||||
return 'kaikout_data'
|
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
|
||||||
|
|
||||||
|
|
||||||
def get_default_config_directory():
|
def get_default_config_directory():
|
||||||
|
@ -63,20 +63,40 @@ class Config:
|
||||||
str
|
str
|
||||||
Path to configuration directory.
|
Path to configuration directory.
|
||||||
"""
|
"""
|
||||||
# directory_config_home = xdg.BaseDirectory.xdg_config_home
|
# config_home = xdg.BaseDirectory.xdg_config_home
|
||||||
directory_config_home = os.environ.get('XDG_CONFIG_HOME')
|
config_home = os.environ.get('XDG_CONFIG_HOME')
|
||||||
if directory_config_home is None:
|
if config_home is None:
|
||||||
directory_home = os.environ.get('HOME')
|
if os.environ.get('HOME') is None:
|
||||||
if directory_home is None:
|
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
directory_config_home = os.environ.get('APPDATA')
|
config_home = os.environ.get('APPDATA')
|
||||||
if directory_config_home is None:
|
if config_home is None:
|
||||||
return 'kaikout_config'
|
return os.path.abspath('.')
|
||||||
else:
|
else:
|
||||||
return 'kaikout_config'
|
return os.path.abspath('.')
|
||||||
else:
|
else:
|
||||||
directory_config_home = os.path.join(directory_home, '.config')
|
config_home = os.path.join(
|
||||||
return os.path.join(directory_config_home, 'kaikout')
|
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:
|
class Documentation:
|
||||||
|
@ -116,103 +136,14 @@ class Documentation:
|
||||||
class Log:
|
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):
|
def csv(filename, fields):
|
||||||
"""
|
"""
|
||||||
Log message or presence to CSV file.
|
Log message to CSV file.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
filename : str
|
message : slixmpp.stanza.message.Message
|
||||||
Filename.
|
Message object.
|
||||||
fields : list
|
|
||||||
type, timestamp, alias, body, lang, and identifier.
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
@ -220,12 +151,11 @@ class Log:
|
||||||
"""
|
"""
|
||||||
data_dir = Config.get_default_data_directory()
|
data_dir = Config.get_default_data_directory()
|
||||||
if not os.path.isdir(data_dir): os.mkdir(data_dir)
|
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")
|
||||||
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))
|
||||||
csv_file = os.path.join(data_dir_logs, f'{filename}.csv')
|
|
||||||
if not os.path.exists(csv_file):
|
if not os.path.exists(csv_file):
|
||||||
columns = ['type', 'timestamp', 'alias', 'body', 'lang', 'identifier']
|
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 = csv.writer(f)
|
||||||
writer.writerow(columns)
|
writer.writerow(columns)
|
||||||
with open(csv_file, 'a') as f:
|
with open(csv_file, 'a') as f:
|
||||||
|
@ -251,8 +181,8 @@ class Log:
|
||||||
None.
|
None.
|
||||||
"""
|
"""
|
||||||
alias, content, identifier, timestamp = fields
|
alias, content, identifier, timestamp = fields
|
||||||
data_dir = DatabaseToml.get_default_data_directory()
|
data_dir = Toml.get_default_data_directory()
|
||||||
filename = DatabaseToml.get_data_file(data_dir, room)
|
filename = Toml.get_data_file(data_dir, room)
|
||||||
# filename = room + '.toml'
|
# filename = room + '.toml'
|
||||||
entry = {}
|
entry = {}
|
||||||
entry['alias'] = alias
|
entry['alias'] = alias
|
||||||
|
@ -295,41 +225,44 @@ class BlockList:
|
||||||
with open(filename, 'w') as f: f.write(content)
|
with open(filename, 'w') as f: f.write(content)
|
||||||
return filename
|
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
|
Parameters
|
||||||
----------
|
----------
|
||||||
url : str
|
jabber_id : str
|
||||||
URL.
|
Jabber ID.
|
||||||
|
node_id : str
|
||||||
|
Node name.
|
||||||
|
item_id : str
|
||||||
|
Item ID.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
url_digest : str
|
None.
|
||||||
Hashed URL as an MD5 checksum.
|
|
||||||
"""
|
"""
|
||||||
url_encoded = url.encode()
|
if jabber_id not in self.blocklist['entries']:
|
||||||
url_hashed = hashlib.md5(url_encoded)
|
self.blocklist['entries'][jabber_id] = {}
|
||||||
url_digest = url_hashed.hexdigest()
|
if node_id not in self.blocklist['entries'][jabber_id]:
|
||||||
return url_digest
|
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:
|
class Url:
|
||||||
|
|
||||||
|
|
||||||
def check_xmpp_uri(uri):
|
def check_xmpp_uri(uri):
|
||||||
"""
|
"""
|
||||||
Check validity of XMPP URI.
|
Check validity of XMPP URI.
|
||||||
|
@ -348,3 +281,26 @@ class Url:
|
||||||
if parseaddr(jid)[1] != jid:
|
if parseaddr(jid)[1] != jid:
|
||||||
jid = False
|
jid = False
|
||||||
return jid
|
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__ = '0.0.6'
|
||||||
__version_info__ = (0, 0, 8)
|
__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 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
# from slixmpp import JID
|
# from slixmpp import JID
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
from kaikout.utilities import Documentation
|
from kaikout.utilities import Documentation
|
||||||
from kaikout.xmpp.commands import XmppCommands
|
from kaikout.xmpp.commands import XmppCommands
|
||||||
|
@ -52,19 +52,13 @@ class XmppChat:
|
||||||
if message_type == 'groupchat':
|
if message_type == 'groupchat':
|
||||||
alias = message['mucnick']
|
alias = message['mucnick']
|
||||||
room = message['mucroom']
|
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
|
if (message['mucnick'] == self.alias or
|
||||||
not XmppUtilities.is_moderator(self, room, alias) or
|
not XmppUtilities.is_moderator(self, room, alias) or
|
||||||
(not message_body.startswith(self_alias + ' ') and
|
not message_body.startswith(alias_of_kaikout)):
|
||||||
not message_body.startswith(self_alias + ',') and
|
|
||||||
not message_body.startswith(self_alias + ':'))):
|
|
||||||
return
|
return
|
||||||
|
alias_of_kaikout_length = len(alias_of_kaikout) + 1
|
||||||
# Adding one to the length because of
|
command = message_body[alias_of_kaikout_length:].lstrip()
|
||||||
# assumption that a comma or a dot is added
|
|
||||||
self_alias_length = len(self_alias) + 1
|
|
||||||
command = message_body[self_alias_length:].lstrip()
|
|
||||||
elif message_type in ('chat', 'normal'):
|
elif message_type in ('chat', 'normal'):
|
||||||
command = message_body
|
command = message_body
|
||||||
jid_full = jid.full
|
jid_full = jid.full
|
||||||
|
@ -183,7 +177,7 @@ class XmppChat:
|
||||||
print(message)
|
print(message)
|
||||||
return
|
return
|
||||||
|
|
||||||
db_file = DatabaseToml.instantiate(self, room)
|
db_file = Toml.instantiate(self, room)
|
||||||
|
|
||||||
# # Support private message via groupchat
|
# # Support private message via groupchat
|
||||||
# # See https://codeberg.org/poezio/slixmpp/issues/3506
|
# # See https://codeberg.org/poezio/slixmpp/issues/3506
|
||||||
|
|
|
@ -4,9 +4,10 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from kaikout.about import Documentation
|
from kaikout.about import Documentation
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
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.chat import XmppChat
|
||||||
from kaikout.xmpp.commands import XmppCommands
|
from kaikout.xmpp.commands import XmppCommands
|
||||||
from kaikout.xmpp.groupchat import XmppGroupchat
|
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.observation import XmppObservation
|
||||||
from kaikout.xmpp.pubsub import XmppPubsub
|
from kaikout.xmpp.pubsub import XmppPubsub
|
||||||
from kaikout.xmpp.status import XmppStatus
|
from kaikout.xmpp.status import XmppStatus
|
||||||
import os
|
|
||||||
import slixmpp
|
import slixmpp
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -39,39 +39,23 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
def __init__(self, jid, password, hostname, port, alias):
|
def __init__(self, jid, password, hostname, port, alias):
|
||||||
slixmpp.ClientXMPP.__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.
|
# Handlers for action messages.
|
||||||
self.actions = {}
|
self.actions = {}
|
||||||
self.action_count = 0
|
self.action_count = 0
|
||||||
# A handler for alias.
|
# A handler for alias.
|
||||||
self.alias = 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.
|
# A handler for configuration.
|
||||||
self.defaults = self.data_settings['defaults']
|
self.defaults = Config.get_values('settings.toml', 'defaults')
|
||||||
# Handlers for connectivity.
|
# Handlers for connectivity.
|
||||||
self.connection_attempts = 0
|
self.connection_attempts = 0
|
||||||
self.max_connection_attempts = 10
|
self.max_connection_attempts = 10
|
||||||
self.task_ping_instance = {}
|
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.
|
# 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.
|
# A handler for sessions.
|
||||||
self.sessions = {}
|
self.sessions = {}
|
||||||
# A handler for settings.
|
# A handler for settings.
|
||||||
|
@ -138,34 +122,48 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
async def on_groupchat_invite(self, message):
|
async def on_groupchat_invite(self, message):
|
||||||
jid_full = str(message['from'])
|
jid_full = str(message['from'])
|
||||||
room = message['groupchat_invite']['jid']
|
room = message['groupchat_invite']['jid']
|
||||||
result = await XmppGroupchat.join(self, room)
|
result = await XmppMuc.join(self, room)
|
||||||
if result != 'ban':
|
if result == 'ban':
|
||||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
message_body = '{} is banned from {}'.format(self.alias, room)
|
||||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
jid_bare = message['from'].bare
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
# This might not be necessary because JID might not be of the inviter, but rather of the MUC
|
||||||
message_body = ('/me moderation chat bot. Jabber ID: xmpp:'
|
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||||
f'{self.boundjid.bare}?message (groupchat_invite)')
|
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')
|
XmppMessage.send(self, room, message_body, 'groupchat')
|
||||||
XmppStatus.send_status_message(self, room)
|
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):
|
async def on_groupchat_direct_invite(self, message):
|
||||||
room = message['groupchat_invite']['jid']
|
room = message['groupchat_invite']['jid']
|
||||||
result = await XmppGroupchat.join(self, room)
|
result = await XmppMuc.join(self, room)
|
||||||
if result != 'ban':
|
if result == 'ban':
|
||||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
message_body = '{} is banned from {}'.format(self.alias, room)
|
||||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
jid_bare = message['from'].bare
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||||
message_body = ('/me moderation chat bot. Jabber ID: xmpp:'
|
logger.warning(message_body)
|
||||||
f'{self.boundjid.bare}?message')
|
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')
|
XmppMessage.send(self, room, message_body, 'groupchat')
|
||||||
XmppStatus.send_status_message(self, room)
|
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):
|
async def on_message(self, message):
|
||||||
|
@ -182,29 +180,24 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
fields = ['message', timestamp_iso, alias, message_body, lang, identifier]
|
fields = ['message', timestamp_iso, alias, message_body, lang, identifier]
|
||||||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||||
Log.csv(filename, fields)
|
Log.csv(filename, fields)
|
||||||
db_file = DatabaseToml.instantiate(self, room)
|
db_file = Toml.instantiate(self, room)
|
||||||
timestamp = time.time()
|
timestamp = time.time()
|
||||||
jid_full = XmppMuc.get_full_jid(self, room, alias)
|
jid_bare = XmppMuc.get_full_jid(self, room, alias).split('/')[0]
|
||||||
if jid_full and '/' in jid_full:
|
XmppCommands.update_last_activity(self, room, jid_bare, db_file, timestamp)
|
||||||
jid_bare = jid_full.split('/')[0]
|
# Toml.load_jid_settings(self, room)
|
||||||
XmppCommands.update_last_activity(
|
# await XmppChat.process_message(self, message)
|
||||||
self, room, jid_bare, db_file, timestamp)
|
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||||
# DatabaseToml.load_jid_settings(self, room)
|
self.settings[room]['enabled'] and
|
||||||
# await XmppChat.process_message(self, message)
|
alias != self.alias and
|
||||||
if (XmppMuc.is_moderator(self, room, self.alias) and
|
jid_bare and
|
||||||
self.settings[room]['enabled'] and
|
jid_bare not in self.settings[room]['jid_whitelist']):
|
||||||
alias != self.alias and
|
identifier = message['id']
|
||||||
jid_bare and
|
fields = [alias, message_body, identifier, timestamp]
|
||||||
jid_bare not in self.settings[room]['jid_whitelist']):
|
Log.toml(self, room, fields, 'message')
|
||||||
identifier = message['id']
|
# Check for message
|
||||||
fields = [alias, message_body, identifier, timestamp]
|
await XmppObservation.observe_message(self, db_file, alias, message_body, room)
|
||||||
Log.toml(self, room, fields, 'message')
|
# Check for inactivity
|
||||||
# Check for message
|
await XmppObservation.observe_inactivity(self, db_file, room)
|
||||||
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):
|
async def on_muc_got_online(self, presence):
|
||||||
|
@ -218,15 +211,6 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||||
Log.csv(filename, fields)
|
Log.csv(filename, fields)
|
||||||
jid_bare = presence['muc']['jid'].bare
|
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
|
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||||
self.settings[room]['enabled'] and
|
self.settings[room]['enabled'] and
|
||||||
jid_bare and
|
jid_bare and
|
||||||
|
@ -247,9 +231,9 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
status_codes = presence['muc']['status_codes']
|
status_codes = presence['muc']['status_codes']
|
||||||
actor_alias = presence['muc']['item']['actor']['nick']
|
actor_alias = presence['muc']['item']['actor']['nick']
|
||||||
if 301 in status_codes:
|
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:
|
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:
|
else:
|
||||||
presence_body = presence['status']
|
presence_body = presence['status']
|
||||||
room = presence['muc']['room']
|
room = presence['muc']['room']
|
||||||
|
@ -258,7 +242,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
filename = datetime.today().strftime('%Y-%m-%d') + '_' + room
|
||||||
# if identifier and presence_body:
|
# if identifier and presence_body:
|
||||||
Log.csv(filename, fields)
|
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
|
if (XmppMuc.is_moderator(self, room, self.alias) and
|
||||||
self.settings[room]['enabled'] and
|
self.settings[room]['enabled'] and
|
||||||
alias != self.alias):
|
alias != self.alias):
|
||||||
|
@ -269,8 +253,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
await XmppObservation.observe_strikes(self, db_file, presence, room)
|
await XmppObservation.observe_strikes(self, db_file, presence, room)
|
||||||
if jid_bare and jid_bare not in self.settings[room]['jid_whitelist']:
|
if jid_bare and jid_bare not in self.settings[room]['jid_whitelist']:
|
||||||
# Check for status message
|
# Check for status message
|
||||||
await XmppObservation.observe_status_message(
|
await XmppObservation.observe_status_message(self, alias, db_file, jid_bare, presence_body, room)
|
||||||
self, alias, db_file, jid_bare, presence_body, room)
|
|
||||||
# Check for inactivity
|
# Check for inactivity
|
||||||
await XmppObservation.observe_inactivity(self, db_file, room)
|
await XmppObservation.observe_inactivity(self, db_file, room)
|
||||||
|
|
||||||
|
@ -279,16 +262,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
actor = presence['muc']['item']['actor']['nick']
|
actor = presence['muc']['item']['actor']['nick']
|
||||||
alias = presence['muc']['nick']
|
alias = presence['muc']['nick']
|
||||||
room = presence['muc']['room']
|
room = presence['muc']['room']
|
||||||
if actor and alias == self.alias: XmppStatus.send_status_message(self,
|
if actor and alias == self.alias: XmppStatus.send_status_message(self, room)
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
def on_reactions(self, message):
|
def on_reactions(self, message):
|
||||||
|
@ -326,7 +300,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
"""
|
"""
|
||||||
# self.command_list()
|
# self.command_list()
|
||||||
# await self.get_roster()
|
# await self.get_roster()
|
||||||
rtbl_sources = self.data_rtbl['sources']
|
rtbl_sources = Config.get_values('rtbl.toml')['sources']
|
||||||
for source in rtbl_sources:
|
for source in rtbl_sources:
|
||||||
jabber_id = source['jabber_id']
|
jabber_id = source['jabber_id']
|
||||||
node_id = source['node_id']
|
node_id = source['node_id']
|
||||||
|
@ -334,23 +308,28 @@ class XmppClient(slixmpp.ClientXMPP):
|
||||||
if subscribe['pubsub']['subscription']['subscription'] == 'subscribed':
|
if subscribe['pubsub']['subscription']['subscription'] == 'subscribed':
|
||||||
rtbl_list = await XmppPubsub.get_items(self, jabber_id, node_id)
|
rtbl_list = await XmppPubsub.get_items(self, jabber_id, node_id)
|
||||||
rtbl_items = rtbl_list['pubsub']['items']
|
rtbl_items = rtbl_list['pubsub']['items']
|
||||||
muc_bans_sha256 = self.blocklist['entries']['xmppbl.org']['muc_bans_sha256']
|
|
||||||
for item in rtbl_items:
|
for item in rtbl_items:
|
||||||
|
exist = False
|
||||||
item_id = item['id']
|
item_id = item['id']
|
||||||
if item_id not in muc_bans_sha256: muc_bans_sha256.append(item_id)
|
for jid in self.blocklist['entries']:
|
||||||
# TODO Extract items item_payload.find(namespace + 'title')
|
for node in jid:
|
||||||
# NOTE (Pdb)
|
for item in node:
|
||||||
# for i in item['payload'].iter(): i.attrib
|
if item_id == item:
|
||||||
# {'reason': 'urn:xmpp:reporting:abuse'}
|
exist = True
|
||||||
self.blocklist['entries']['xmppbl.org']['muc_bans_sha256'] = muc_bans_sha256
|
break
|
||||||
Toml.save_file(self.filename_blocklist, self.blocklist)
|
if not exist:
|
||||||
del self.filename_blocklist
|
# 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['from'] = xmppbl.org
|
||||||
# subscribe['pubsub']['subscription']['node'] = 'muc_bans_sha256'
|
# subscribe['pubsub']['subscription']['node'] = 'muc_bans_sha256'
|
||||||
subscriptions = await XmppPubsub.get_node_subscriptions(
|
subscriptions = await XmppPubsub.get_node_subscriptions(self, jabber_id, node_id)
|
||||||
self, jabber_id, node_id)
|
|
||||||
await self['xep_0115'].update_caps()
|
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
|
# See also get_joined_rooms of slixmpp.plugins.xep_0045
|
||||||
for room in rooms:
|
for room in rooms:
|
||||||
XmppStatus.send_status_message(self, room)
|
XmppStatus.send_status_message(self, room)
|
||||||
|
|
|
@ -5,9 +5,10 @@ import asyncio
|
||||||
import kaikout.config as config
|
import kaikout.config as config
|
||||||
from kaikout.config import Config
|
from kaikout.config import Config
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.utilities import Documentation, Toml, Url
|
from kaikout.utilities import Documentation, Url
|
||||||
from kaikout.version import __version__
|
from kaikout.version import __version__
|
||||||
|
from kaikout.xmpp.bookmark import XmppBookmark
|
||||||
from kaikout.xmpp.muc import XmppMuc
|
from kaikout.xmpp.muc import XmppMuc
|
||||||
from kaikout.xmpp.status import XmppStatus
|
from kaikout.xmpp.status import XmppStatus
|
||||||
from kaikout.xmpp.utilities import XmppUtilities
|
from kaikout.xmpp.utilities import XmppUtilities
|
||||||
|
@ -36,7 +37,7 @@ class XmppCommands:
|
||||||
async def clear_filter(self, room, db_file, key):
|
async def clear_filter(self, room, db_file, key):
|
||||||
value = []
|
value = []
|
||||||
self.settings[room][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)
|
message = 'Filter {} has been purged.'.format(key)
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
@ -80,16 +81,17 @@ class XmppCommands:
|
||||||
|
|
||||||
|
|
||||||
async def bookmark_add(self, muc_jid):
|
async def bookmark_add(self, muc_jid):
|
||||||
if muc_jid not in self.bookmarks: self.bookmarks.append(muc_jid)
|
await XmppBookmark.add(self, jid=muc_jid)
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
message = ('Groupchat {} has been added to bookmarks.'
|
||||||
return f'Groupchat {muc_jid} has been added to bookmarks.'
|
.format(muc_jid))
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
async def bookmark_del(self, muc_jid):
|
async def bookmark_del(self, muc_jid):
|
||||||
if muc_jid in self.bookmarks: self.bookmarks.remove(muc_jid)
|
await XmppBookmark.remove(self, muc_jid)
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
message = ('Groupchat {} has been removed from bookmarks.'
|
||||||
return f'Groupchat {muc_jid} has been removed from bookmarks.'
|
.format(muc_jid))
|
||||||
|
return message
|
||||||
|
|
||||||
async def invite_jid_to_muc(self, jid_bare):
|
async def invite_jid_to_muc(self, jid_bare):
|
||||||
muc_jid = 'slixfeed@chat.woodpeckersnest.space'
|
muc_jid = 'slixfeed@chat.woodpeckersnest.space'
|
||||||
|
@ -120,13 +122,12 @@ class XmppCommands:
|
||||||
if muc_jid:
|
if muc_jid:
|
||||||
# TODO probe JID and confirm it's a groupchat
|
# TODO probe JID and confirm it's a groupchat
|
||||||
result = await XmppMuc.join(self, muc_jid)
|
result = await XmppMuc.join(self, muc_jid)
|
||||||
|
# await XmppBookmark.add(self, jid=muc_jid)
|
||||||
if result == 'ban':
|
if result == 'ban':
|
||||||
message = '{} is banned from {}'.format(self.alias, muc_jid)
|
message = '{} is banned from {}'.format(self.alias, muc_jid)
|
||||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
|
||||||
else:
|
else:
|
||||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
await XmppBookmark.add(self, muc_jid)
|
||||||
message = 'Joined groupchat {}'.format(muc_jid)
|
message = 'Joined groupchat {}'.format(muc_jid)
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
|
||||||
else:
|
else:
|
||||||
message = '> {}\nGroupchat JID appears to be invalid.'.format(muc_jid)
|
message = '> {}\nGroupchat JID appears to be invalid.'.format(muc_jid)
|
||||||
else:
|
else:
|
||||||
|
@ -136,8 +137,7 @@ class XmppCommands:
|
||||||
|
|
||||||
async def muc_leave(self, room):
|
async def muc_leave(self, room):
|
||||||
XmppMuc.leave(self, room)
|
XmppMuc.leave(self, room)
|
||||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
await XmppBookmark.remove(self, room)
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
|
||||||
|
|
||||||
|
|
||||||
async def outcast(self, room, alias, reason):
|
async def outcast(self, room, alias, reason):
|
||||||
|
@ -163,11 +163,14 @@ class XmppCommands:
|
||||||
|
|
||||||
|
|
||||||
async def print_bookmarks(self):
|
async def print_bookmarks(self):
|
||||||
conferences = self.bookmarks
|
conferences = await XmppBookmark.get_bookmarks(self)
|
||||||
message = '\nList of groupchats:\n\n```\n'
|
message = '\nList of groupchats:\n\n```\n'
|
||||||
for conference in conferences:
|
for conference in conferences:
|
||||||
message += f'{conference}\n'
|
message += ('Name: {}\n'
|
||||||
message += (f'```\nTotal of {len(conferences)} groupchats.\n')
|
'Room: {}\n'
|
||||||
|
'\n'
|
||||||
|
.format(conference['name'], conference['jid']))
|
||||||
|
message += ('```\nTotal of {} groupchats.\n'.format(len(conferences)))
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
@ -324,7 +327,7 @@ class XmppCommands:
|
||||||
if jid_full:
|
if jid_full:
|
||||||
jid_bare = jid_full.split('/')[0]
|
jid_bare = jid_full.split('/')[0]
|
||||||
scores[jid_bare] = scores[jid_bare] + 1 if jid_bare in scores else 1
|
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)
|
time.sleep(5)
|
||||||
del self.actions[room][task_number]
|
del self.actions[room][task_number]
|
||||||
XmppStatus.send_status_message(self, room)
|
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 = 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
|
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]
|
# result = scores[jid_bare]
|
||||||
# return result
|
# return result
|
||||||
|
|
||||||
|
@ -377,7 +380,7 @@ class XmppCommands:
|
||||||
"""
|
"""
|
||||||
scores = self.settings[room]['score_kick'] if 'score_kick' in self.settings[room] else {}
|
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
|
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]
|
# result = scores[jid_bare]
|
||||||
# return result
|
# return result
|
||||||
|
|
||||||
|
@ -404,7 +407,7 @@ class XmppCommands:
|
||||||
"""
|
"""
|
||||||
activity = self.settings[room]['last_activity'] if 'last_activity' in self.settings[room] else {}
|
activity = self.settings[room]['last_activity'] if 'last_activity' in self.settings[room] else {}
|
||||||
activity[jid_bare] = timestamp
|
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):
|
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 {}
|
activity = self.settings[room]['last_activity'] if 'last_activity' in self.settings[room] else {}
|
||||||
del activity[jid_bare]
|
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):
|
def raise_score_inactivity(self, room, alias, db_file):
|
||||||
|
@ -459,7 +462,7 @@ class XmppCommands:
|
||||||
if jid_full:
|
if jid_full:
|
||||||
jid_bare = jid_full.split('/')[0]
|
jid_bare = jid_full.split('/')[0]
|
||||||
scores_inactivity[jid_bare] = scores_inactivity[jid_bare] + 1 if jid_bare in scores_inactivity else 1
|
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)
|
time.sleep(5)
|
||||||
del self.actions[room][task_number]
|
del self.actions[room][task_number]
|
||||||
XmppStatus.send_status_message(self, room)
|
XmppStatus.send_status_message(self, room)
|
||||||
|
@ -471,16 +474,16 @@ class XmppCommands:
|
||||||
if key:
|
if key:
|
||||||
value = self.defaults[key]
|
value = self.defaults[key]
|
||||||
self.settings[room][key] = value
|
self.settings[room][key] = value
|
||||||
# data_dir = DatabaseToml.get_default_data_directory()
|
# data_dir = Toml.get_default_data_directory()
|
||||||
# db_file = DatabaseToml.get_data_file(data_dir, jid_bare)
|
# db_file = Toml.get_data_file(data_dir, jid_bare)
|
||||||
DatabaseToml.update_jid_settings(self, room, db_file, key, value)
|
Toml.update_jid_settings(self, room, db_file, key, value)
|
||||||
message = ('Setting {} has been restored to default value.'
|
message = ('Setting {} has been restored to default value.'
|
||||||
.format(key))
|
.format(key))
|
||||||
else:
|
else:
|
||||||
self.settings = self.defaults
|
self.settings = self.defaults
|
||||||
data_dir = DatabaseToml.get_default_data_directory()
|
data_dir = Toml.get_default_data_directory()
|
||||||
db_file = DatabaseToml.get_data_file(data_dir, room)
|
db_file = Toml.get_data_file(data_dir, room)
|
||||||
DatabaseToml.create_settings_file(self, db_file)
|
Toml.create_settings_file(self, db_file)
|
||||||
message = 'Default settings have been restored.'
|
message = 'Default settings have been restored.'
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
@ -521,7 +524,7 @@ class XmppCommands:
|
||||||
string_trim = string.strip()
|
string_trim = string.strip()
|
||||||
string_list.remove(string_trim)
|
string_list.remove(string_trim)
|
||||||
processed_strings.append(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()
|
processed_strings.sort()
|
||||||
if processed_strings:
|
if processed_strings:
|
||||||
message = 'Strings "{}" have been {} list "{}".'.format(
|
message = 'Strings "{}" have been {} list "{}".'.format(
|
||||||
|
@ -548,4 +551,4 @@ class XmppCommands:
|
||||||
|
|
||||||
|
|
||||||
def update_setting_value(self, room, db_file, key, value):
|
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
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- 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.muc import XmppMuc
|
||||||
from kaikout.xmpp.status import XmppStatus
|
from kaikout.xmpp.status import XmppStatus
|
||||||
from kaikout.utilities import Toml
|
|
||||||
from kaikout.log import Logger, Message
|
from kaikout.log import Logger, Message
|
||||||
import random
|
|
||||||
|
|
||||||
logger = Logger(__name__)
|
logger = Logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class XmppGroupchat:
|
class XmppGroupchat:
|
||||||
|
|
||||||
async def join(self, room):
|
async def autojoin(self, bookmarks):
|
||||||
result = await XmppMuc.join(self, room)
|
mucs_join_success = []
|
||||||
if result == 'ban':
|
for bookmark in bookmarks:
|
||||||
message_body = '{} is banned from {}'.format(self.alias, room)
|
if bookmark["jid"] and bookmark["autojoin"]:
|
||||||
jid_bare = message['from'].bare
|
if not bookmark["nick"]:
|
||||||
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
bookmark["nick"] = self.alias
|
||||||
logger.warning(message_body)
|
logger.error('Alias (i.e. Nicknname) is missing for '
|
||||||
elif result == 'conflict':
|
'bookmark {}'.format(bookmark['name']))
|
||||||
while result == 'conflict':
|
alias = bookmark["nick"]
|
||||||
number = str(random.randrange(1000, 5000))
|
room = bookmark["jid"]
|
||||||
print(f'Conflict. Atempting to join to {room} as {self.alias} #{number}')
|
Message.printer('Joining to MUC {} ...'.format(room))
|
||||||
result = await XmppMuc.join(self, room, f'{self.alias} #{number}')
|
result = await XmppMuc.join(self, room, alias)
|
||||||
else:
|
if result == 'ban':
|
||||||
#self.bookmarks.append({'jid' : room, 'lang' : '', 'pass' : ''})
|
await XmppBookmark.remove(self, room)
|
||||||
if room not in self.bookmarks: self.bookmarks.append(room)
|
logger.warning('{} is banned from {}'.format(self.alias, room))
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
logger.warning('Groupchat {} has been removed from bookmarks'
|
||||||
return result
|
.format(room))
|
||||||
|
else:
|
||||||
async def autojoin(self):
|
mucs_join_success.append(room)
|
||||||
mucs_joined = []
|
logger.info('Autojoin groupchat\n'
|
||||||
for room in self.bookmarks:
|
'Name : {}\n'
|
||||||
alias = self.alias
|
'JID : {}\n'
|
||||||
print(f'Joining to MUC {room} ...')
|
'Alias : {}\n'
|
||||||
#Message.printer(f'Joining to MUC {room} ...')
|
.format(bookmark["name"],
|
||||||
result = await XmppMuc.join(self, room)
|
bookmark["jid"],
|
||||||
if result == 'ban':
|
bookmark["nick"]))
|
||||||
if room in self.bookmarks: self.bookmarks.remove(room)
|
elif not bookmark["jid"]:
|
||||||
Toml.save_file(self.filename_bookmarks, self.data_bookmarks)
|
logger.error('JID is missing for bookmark {}'
|
||||||
logger.warning(f'{alias} is banned from {room}')
|
.format(bookmark['name']))
|
||||||
logger.warning(f'Groupchat {room} has been removed from bookmarks')
|
return mucs_join_success
|
||||||
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
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
from kaikout.xmpp.commands import XmppCommands
|
from kaikout.xmpp.commands import XmppCommands
|
||||||
|
|
||||||
|
@ -17,8 +17,8 @@ class XmppModeration:
|
||||||
if jid_bare not in self.settings[room]['last_activity']:
|
if jid_bare not in self.settings[room]['last_activity']:
|
||||||
# self.settings[room]['last_activity'][jid_bare] = timestamp
|
# self.settings[room]['last_activity'][jid_bare] = timestamp
|
||||||
# last_activity_for_jid = self.settings[room]['last_activity'][jid_bare]
|
# last_activity_for_jid = self.settings[room]['last_activity'][jid_bare]
|
||||||
db_file = DatabaseToml.instantiate(self, room)
|
db_file = Toml.instantiate(self, room)
|
||||||
# DatabaseToml.update_jid_settings(self, room, db_file, 'last_activity', last_activity_for_jid)
|
# 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)
|
XmppCommands.update_last_activity(self, room, jid_bare, db_file, timestamp)
|
||||||
else:
|
else:
|
||||||
jid_last_activity = self.settings[room]['last_activity'][jid_bare]
|
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
|
1) Save name of groupchat instead of jid as name
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from asyncio import TimeoutError
|
|
||||||
from slixmpp.exceptions import IqError, IqTimeout, PresenceError
|
from slixmpp.exceptions import IqError, IqTimeout, PresenceError
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
|
|
||||||
|
@ -93,18 +92,40 @@ class XmppMuc:
|
||||||
def is_moderator(self, room, alias):
|
def is_moderator(self, room, alias):
|
||||||
"""Check if given JID is a moderator"""
|
"""Check if given JID is a moderator"""
|
||||||
role = self.plugin['xep_0045'].get_jid_property(room, alias, 'role')
|
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
|
return result
|
||||||
|
|
||||||
|
|
||||||
async def join(self, jid_bare, alias=None, password=None):
|
async def join(self, jid, alias=None, password=None):
|
||||||
logger.info('Joining groupchat\nJID : {}\n'.format(jid_bare))
|
# token = await initdb(
|
||||||
#jid_from = str(self.boundjid) if self.is_component else None
|
# 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
|
if not alias: alias = self.alias
|
||||||
try:
|
try:
|
||||||
await self.plugin['xep_0045'].join_muc_wait(jid_bare,
|
await self.plugin['xep_0045'].join_muc_wait(jid,
|
||||||
alias,
|
alias,
|
||||||
#presence_options = {"pfrom" : jid_from},
|
presence_options = {"pfrom" : jid_from},
|
||||||
password=password,
|
password=password,
|
||||||
maxchars=0,
|
maxchars=0,
|
||||||
maxstanzas=0,
|
maxstanzas=0,
|
||||||
|
@ -115,35 +136,22 @@ class XmppMuc:
|
||||||
except IqError as e:
|
except IqError as e:
|
||||||
logger.error('Error XmppIQ')
|
logger.error('Error XmppIQ')
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
logger.error(jid_bare)
|
logger.error(jid)
|
||||||
result = 'error'
|
result = 'error'
|
||||||
except IqTimeout as e:
|
except IqTimeout as e:
|
||||||
logger.error('Timeout XmppIQ')
|
logger.error('Timeout XmppIQ')
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
logger.error(jid_bare)
|
logger.error(jid)
|
||||||
result = 'timeout'
|
|
||||||
except TimeoutError as e:
|
|
||||||
logger.error('Timeout AsyncIO')
|
|
||||||
logger.error(str(e))
|
|
||||||
logger.error(jid_bare)
|
|
||||||
result = 'timeout'
|
result = 'timeout'
|
||||||
except PresenceError as e:
|
except PresenceError as e:
|
||||||
logger.error('Error Presence')
|
logger.error('Error Presence')
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
if (e.condition == 'forbidden' and
|
if (e.condition == 'forbidden' and
|
||||||
e.presence['error']['code'] == '403'):
|
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'
|
result = 'ban'
|
||||||
elif e.condition == 'conflict':
|
|
||||||
logger.warning(e.presence['error']['text'])
|
|
||||||
result = 'conflict'
|
|
||||||
else:
|
else:
|
||||||
result = 'error'
|
result = 'error'
|
||||||
except Exception as e:
|
|
||||||
logger.error('Unknown error')
|
|
||||||
logger.error(str(e))
|
|
||||||
logger.error(jid_bare)
|
|
||||||
result = 'unknown'
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@ -175,11 +183,6 @@ class XmppMuc:
|
||||||
logger.error('Could not set affiliation at room: {}'.format(room))
|
logger.error('Could not set affiliation at room: {}'.format(room))
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
logger.error(room)
|
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):
|
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('Could not set role of alias: {}'.format(alias))
|
||||||
logger.error(str(e))
|
logger.error(str(e))
|
||||||
logger.error(room)
|
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
|
import asyncio
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
from kaikout.xmpp.commands import XmppCommands
|
from kaikout.xmpp.commands import XmppCommands
|
||||||
from kaikout.xmpp.message import XmppMessage
|
from kaikout.xmpp.message import XmppMessage
|
||||||
|
@ -70,7 +70,7 @@ class XmppObservation:
|
||||||
'You are expected to be expelled from '
|
'You are expected to be expelled from '
|
||||||
'groupchat {} within {} hour time.'
|
'groupchat {} within {} hour time.'
|
||||||
.format(room, int(span) or 'an'))
|
.format(room, int(span) or 'an'))
|
||||||
DatabaseToml.update_jid_settings(
|
Toml.update_jid_settings(
|
||||||
self, room, db_file, 'inactivity_notice', noticed_jids)
|
self, room, db_file, 'inactivity_notice', noticed_jids)
|
||||||
if message_to_participant:
|
if message_to_participant:
|
||||||
XmppMessage.send(
|
XmppMessage.send(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from kaikout.database import DatabaseToml
|
from kaikout.database import Toml
|
||||||
from kaikout.log import Logger
|
from kaikout.log import Logger
|
||||||
from kaikout.xmpp.presence import XmppPresence
|
from kaikout.xmpp.presence import XmppPresence
|
||||||
from kaikout.xmpp.utilities import XmppUtilities
|
from kaikout.xmpp.utilities import XmppUtilities
|
||||||
|
@ -27,8 +27,8 @@ class XmppStatus:
|
||||||
if not status_mode and not status_text:
|
if not status_mode and not status_text:
|
||||||
if XmppUtilities.is_moderator(self, room, self.alias):
|
if XmppUtilities.is_moderator(self, room, self.alias):
|
||||||
if room not in self.settings:
|
if room not in self.settings:
|
||||||
DatabaseToml.instantiate(self, room)
|
Toml.instantiate(self, room)
|
||||||
# DatabaseToml.load_jid_settings(self, room)
|
# Toml.load_jid_settings(self, room)
|
||||||
if self.settings[room]['enabled']:
|
if self.settings[room]['enabled']:
|
||||||
jid_task = self.actions[room] if room in self.actions else None
|
jid_task = self.actions[room] if room in self.actions else None
|
||||||
if jid_task and len(jid_task):
|
if jid_task and len(jid_task):
|
||||||
|
|
Loading…
Reference in a new issue