forked from sch/Slixfeed
7f0c4f4274
Improve handling of errors.
1476 lines
82 KiB
Python
1476 lines
82 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
|
|
TODO
|
|
|
|
1) Deprecate "add" (see above) and make it interactive.
|
|
Slixfeed: Do you still want to add this URL to subscription list?
|
|
See: case _ if message_lowercase.startswith("add"):
|
|
|
|
2) If subscription is inadequate (see XmppPresence.request), send a message that says so.
|
|
|
|
elif not self.client_roster[jid]["to"]:
|
|
breakpoint()
|
|
message.reply("Share online status to activate bot.").send()
|
|
return
|
|
|
|
3) Set timeout for moderator interaction.
|
|
If moderator interaction has been made, and moderator approves the bot, then
|
|
the bot will add the given groupchat to bookmarks; otherwise, the bot will
|
|
send a message that it was not approved and therefore leaves the groupchat.
|
|
|
|
"""
|
|
|
|
import asyncio
|
|
from feedparser import parse
|
|
import logging
|
|
import os
|
|
import slixfeed.action as action
|
|
import slixfeed.config as config
|
|
import slixfeed.crawl as crawl
|
|
from slixfeed.config import Config
|
|
import slixfeed.dt as dt
|
|
import slixfeed.fetch as fetch
|
|
import slixfeed.sqlite as sqlite
|
|
import slixfeed.task as task
|
|
import slixfeed.url as uri
|
|
from slixfeed.version import __version__
|
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
|
from slixfeed.xmpp.muc import XmppGroupchat
|
|
from slixfeed.xmpp.message import XmppMessage
|
|
from slixfeed.xmpp.presence import XmppPresence
|
|
from slixfeed.xmpp.upload import XmppUpload
|
|
from slixfeed.xmpp.privilege import is_moderator, is_operator, is_access
|
|
from slixfeed.xmpp.utility import get_chat_type
|
|
import time
|
|
|
|
from random import randrange
|
|
|
|
try:
|
|
import tomllib
|
|
except:
|
|
import tomli as tomllib
|
|
|
|
|
|
# for task in main_task:
|
|
# task.cancel()
|
|
|
|
# Deprecated in favour of event "presence_available"
|
|
# if not main_task:
|
|
# await select_file()
|
|
|
|
class Chat:
|
|
|
|
async def process_message(self, message):
|
|
"""
|
|
Process incoming message stanzas. Be aware that this also
|
|
includes MUC messages and error messages. It is usually
|
|
a good practice to check the messages's type before
|
|
processing or sending replies.
|
|
|
|
Parameters
|
|
----------
|
|
message : str
|
|
The received message stanza. See the documentation
|
|
for stanza objects and the Message stanza to see
|
|
how it may be used.
|
|
"""
|
|
if message['type'] in ('chat', 'groupchat', 'normal'):
|
|
jid_bare = message['from'].bare
|
|
jid_file = jid_bare
|
|
message_text = ' '.join(message['body'].split())
|
|
command_time_start = time.time()
|
|
|
|
# if (message['type'] == 'groupchat' and
|
|
# message['muc']['nick'] == self.alias):
|
|
# return
|
|
|
|
# FIXME Code repetition. See below.
|
|
# TODO Check alias by nickname associated with conference
|
|
if message['type'] == 'groupchat':
|
|
if (message['muc']['nick'] == self.alias):
|
|
return
|
|
jid_full = str(message['from'])
|
|
if not is_moderator(self, jid_bare, jid_full):
|
|
return
|
|
|
|
# NOTE This is an exceptional case in which we treat
|
|
# type groupchat the same as type chat in a way that
|
|
# doesn't require an exclamation mark for actionable
|
|
# command.
|
|
if (message_text.lower().startswith('http') and
|
|
message_text.lower().endswith('.opml')):
|
|
url = message_text
|
|
key_list = ['status']
|
|
task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
status_type = 'dnd'
|
|
status_message = '📥️ Procesing request to import feeds...'
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
result = await fetch.http(url)
|
|
count = await action.import_opml(db_file, result)
|
|
if count:
|
|
response = 'Successfully imported {} feeds.'.format(count)
|
|
else:
|
|
response = 'OPML file was not imported.'
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
XmppMessage.send_reply(self, message, response)
|
|
return
|
|
|
|
|
|
if message['type'] == 'groupchat':
|
|
# nick = message['from'][message['from'].index('/')+1:]
|
|
# nick = str(message['from'])
|
|
# nick = nick[nick.index('/')+1:]
|
|
if (message['muc']['nick'] == self.alias or
|
|
not message['body'].startswith('!')):
|
|
return
|
|
# token = await initdb(
|
|
# jid_bare,
|
|
# sqlite.get_setting_value,
|
|
# 'token'
|
|
# )
|
|
# if token == 'accepted':
|
|
# operator = await initdb(
|
|
# jid_bare,
|
|
# sqlite.get_setting_value,
|
|
# 'masters'
|
|
# )
|
|
# if operator:
|
|
# if nick not in operator:
|
|
# return
|
|
# approved = False
|
|
jid_full = str(message['from'])
|
|
if not is_moderator(self, jid_bare, jid_full):
|
|
return
|
|
# if role == 'moderator':
|
|
# approved = True
|
|
# TODO Implement a list of temporary operators
|
|
# Once an operator is appointed, the control would last
|
|
# untile the participant has been disconnected from MUC
|
|
# An operator is a function to appoint non moderators.
|
|
# Changing nickname is fine and consist of no problem.
|
|
# if not approved:
|
|
# operator = await initdb(
|
|
# jid_bare,
|
|
# sqlite.get_setting_value,
|
|
# 'masters'
|
|
# )
|
|
# if operator:
|
|
# if nick in operator:
|
|
# approved = True
|
|
# if not approved:
|
|
# return
|
|
|
|
# # Begin processing new JID
|
|
# # Deprecated in favour of event 'presence_available'
|
|
# db_dir = config.get_default_data_directory()
|
|
# os.chdir(db_dir)
|
|
# if jid + '.db' not in os.listdir():
|
|
# await task_jid(jid)
|
|
|
|
# await compose.message(self, jid_bare, message)
|
|
|
|
if message['type'] == 'groupchat':
|
|
message_text = message_text[1:]
|
|
message_lowercase = message_text.lower()
|
|
|
|
logging.debug([str(message['from']), ':', message_text])
|
|
|
|
# Support private message via groupchat
|
|
# See https://codeberg.org/poezio/slixmpp/issues/3506
|
|
if message['type'] == 'chat' and message.get_plugin('muc', check=True):
|
|
# jid_bare = message['from'].bare
|
|
jid_full = str(message['from'])
|
|
if (jid_bare == jid_full[:jid_full.index('/')]):
|
|
jid = str(message['from'])
|
|
jid_file = jid_full.replace('/', '_')
|
|
|
|
response = None
|
|
match message_lowercase:
|
|
# case 'breakpoint':
|
|
# if is_operator(self, jid_bare):
|
|
# breakpoint()
|
|
# print('task_manager[jid]')
|
|
# print(task_manager[jid])
|
|
# await self.get_roster()
|
|
# print('roster 1')
|
|
# print(self.client_roster)
|
|
# print('roster 2')
|
|
# print(self.client_roster.keys())
|
|
# print('jid')
|
|
# print(jid)
|
|
# else:
|
|
# response = (
|
|
# 'This action is restricted. '
|
|
# 'Type: breakpoint.'
|
|
# )
|
|
# XmppMessage.send_reply(self, message, response)
|
|
case 'help':
|
|
command_list = ' '.join(action.manual('commands.toml'))
|
|
response = ('Available command keys:\n'
|
|
'```\n{}\n```\n'
|
|
'Usage: `help <key>`'
|
|
.format(command_list))
|
|
print(response)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'help all':
|
|
command_list = action.manual('commands.toml', section='all')
|
|
response = ('Complete list of commands:\n'
|
|
'```\n{}\n```'
|
|
.format(command_list))
|
|
print(response)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('help'):
|
|
command = message_text[5:].lower()
|
|
command = command.split(' ')
|
|
if len(command) == 2:
|
|
command_root = command[0]
|
|
command_name = command[1]
|
|
command_list = action.manual('commands.toml',
|
|
section=command_root,
|
|
command=command_name)
|
|
if command_list:
|
|
command_list = ''.join(command_list)
|
|
response = (command_list)
|
|
else:
|
|
response = ('KeyError for {} {}'
|
|
.format(command_root, command_name))
|
|
elif len(command) == 1:
|
|
command = command[0]
|
|
command_list = action.manual('commands.toml', command)
|
|
if command_list:
|
|
command_list = ' '.join(command_list)
|
|
response = ('Available command `{}` keys:\n'
|
|
'```\n{}\n```\n'
|
|
'Usage: `help {} <command>`'
|
|
.format(command, command_list, command))
|
|
else:
|
|
response = 'KeyError for {}'.format(command)
|
|
else:
|
|
response = ('Invalid. Enter command key '
|
|
'or command key & name')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'info':
|
|
config_dir = config.get_default_config_directory()
|
|
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
|
entries = tomllib.load(information)
|
|
response = ('Available command options:\n'
|
|
'```\n{}\n```\n'
|
|
'Usage: `info <option>`'
|
|
.format(', '.join(entries)))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('info'):
|
|
entry = message_text[5:].lower()
|
|
config_dir = config.get_default_config_directory()
|
|
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
|
entries = tomllib.load(information)
|
|
if entry in entries:
|
|
# command_list = '\n'.join(command_list)
|
|
response = (entries[entry]['info'])
|
|
else:
|
|
response = ('KeyError for {}'
|
|
.format(entry))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase in ['greetings', 'hallo', 'hello',
|
|
'hey', 'hi', 'hola', 'holla',
|
|
'hollo']:
|
|
response = ('Greeting! My name is {}.\n'
|
|
'I am an RSS News Bot.\n'
|
|
'Send "help" for further instructions.\n'
|
|
.format(self.alias))
|
|
XmppMessage.send_reply(self, message, response)
|
|
|
|
# case _ if message_lowercase.startswith('activate'):
|
|
# if message['type'] == 'groupchat':
|
|
# acode = message[9:]
|
|
# token = await initdb(
|
|
# jid_bare,
|
|
# sqlite.get_setting_value,
|
|
# 'token'
|
|
# )
|
|
# if int(acode) == token:
|
|
# await initdb(
|
|
# jid_bare,
|
|
# sqlite.update_setting_value,
|
|
# ['masters', nick]
|
|
# )
|
|
# await initdb(
|
|
# jid_bare,
|
|
# sqlite.update_setting_value,
|
|
# ['token', 'accepted']
|
|
# )
|
|
# response = '{}, your are in command.'.format(nick)
|
|
# else:
|
|
# response = 'Activation code is not valid.'
|
|
# else:
|
|
# response = 'This command is valid for groupchat only.'
|
|
case _ if message_lowercase.startswith('add '):
|
|
# Add given feed without validity check.
|
|
message_text = message_text[4:]
|
|
url = message_text.split(' ')[0]
|
|
title = ' '.join(message_text.split(' ')[1:])
|
|
if url.startswith('http'):
|
|
if not title:
|
|
title = uri.get_hostname(url)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
counter = 0
|
|
hostname = uri.get_hostname(url)
|
|
hostname = hostname.replace('.','-')
|
|
identifier = hostname + ':' + str(counter)
|
|
while True:
|
|
if sqlite.check_identifier_exist(db_file, identifier):
|
|
counter += 1
|
|
identifier = hostname + ':' + str(counter)
|
|
else:
|
|
break
|
|
exist = sqlite.get_feed_id_and_name(db_file, url)
|
|
if not exist:
|
|
await sqlite.insert_feed(db_file, url, title,
|
|
identifier)
|
|
feed_id = sqlite.get_feed_id(db_file, url)
|
|
feed_id = feed_id[0]
|
|
result = await fetch.http(url)
|
|
if not result['error']:
|
|
document = result['content']
|
|
feed = parse(document)
|
|
feed_valid = 0 if feed.bozo else 1
|
|
await sqlite.update_feed_validity(db_file, feed_id, feed_valid)
|
|
if feed.has_key('updated_parsed'):
|
|
feed_updated = feed.updated_parsed
|
|
try:
|
|
feed_updated = dt.convert_struct_time_to_iso8601(feed_updated)
|
|
except:
|
|
feed_updated = None
|
|
else:
|
|
feed_updated = None
|
|
feed_properties = action.get_properties_of_feed(
|
|
db_file, feed_id, feed)
|
|
await sqlite.update_feed_properties(db_file, feed_id,
|
|
feed_properties)
|
|
feed_id = sqlite.get_feed_id(db_file, url)
|
|
feed_id = feed_id[0]
|
|
new_entries = action.get_properties_of_entries(
|
|
jid_bare, db_file, url, feed_id, feed)
|
|
if new_entries:
|
|
await sqlite.add_entries_and_update_feed_state(
|
|
db_file, feed_id, new_entries)
|
|
|
|
# Function "scan" of module "actions" no longer exists.
|
|
# If you choose to add this download functionality and
|
|
# the look into function "check_updates" of module "task".
|
|
# await action.scan(self, jid_bare, db_file, url)
|
|
# if jid_bare not in self.settings:
|
|
# Config.add_settings_jid(self.settings, jid_bare,
|
|
# db_file)
|
|
# old = Config.get_setting_value(self.settings, jid_bare,
|
|
# 'old')
|
|
# if old:
|
|
# # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
# # await send_status(jid)
|
|
# key_list = ['status']
|
|
# await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
# else:
|
|
# feed_id = sqlite.get_feed_id(db_file, url)
|
|
# feed_id = feed_id[0]
|
|
# await sqlite.mark_feed_as_read(db_file, feed_id)
|
|
|
|
response = ('> {}\n'
|
|
'News source has been '
|
|
'added to subscription list.'
|
|
.format(url))
|
|
else:
|
|
ix = exist[0]
|
|
name = exist[1]
|
|
response = ('> {}\n'
|
|
'News source "{}" is already '
|
|
'listed in the subscription list at '
|
|
'index {}'
|
|
.format(url, name, ix))
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing URL.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('allow +'):
|
|
key = message_text[:5].lower()
|
|
val = message_text[7:]
|
|
if val:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
keywords = sqlite.get_filter_value(db_file, key)
|
|
if keywords: keywords = str(keywords[0])
|
|
val = await config.add_to_list(val, keywords)
|
|
if sqlite.is_filter_key(db_file, key):
|
|
await sqlite.update_filter_value(db_file,
|
|
[key, val])
|
|
else:
|
|
await sqlite.set_filter_value(db_file, [key, val])
|
|
response = ('Approved keywords\n'
|
|
'```\n{}\n```'
|
|
.format(val))
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing keywords.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('allow -'):
|
|
key = message_text[:5].lower()
|
|
val = message_text[7:]
|
|
if val:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
keywords = sqlite.get_filter_value(db_file, key)
|
|
if keywords: keywords = str(keywords[0])
|
|
val = await config.remove_from_list(val, keywords)
|
|
if sqlite.is_filter_key(db_file, key):
|
|
await sqlite.update_filter_value(db_file,
|
|
[key, val])
|
|
else:
|
|
await sqlite.set_filter_value(db_file, [key, val])
|
|
response = ('Approved keywords\n'
|
|
'```\n{}\n```'
|
|
.format(val))
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing keywords.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('archive '):
|
|
key = message_text[:7].lower()
|
|
val = message_text[8:]
|
|
if val:
|
|
try:
|
|
val_new = int(val)
|
|
if val_new > 500:
|
|
response = 'Value may not be greater than 500.'
|
|
else:
|
|
val_old = Config.get_setting_value(
|
|
self.settings, jid_bare, key)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(
|
|
self.settings, jid_bare, db_file, key, val_new)
|
|
response = ('Maximum archived items has '
|
|
'been set to {} (was: {}).'
|
|
.format(val_new, val_old))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Enter a numeric value only.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing value.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('bookmark +'):
|
|
if is_operator(self, jid_bare):
|
|
muc_jid = message_text[11:]
|
|
await XmppBookmark.add(self, jid=muc_jid)
|
|
response = ('Groupchat {} has been added to bookmarks.'
|
|
.format(muc_jid))
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: adding bookmarks.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('bookmark -'):
|
|
if is_operator(self, jid_bare):
|
|
muc_jid = message_text[11:]
|
|
await XmppBookmark.remove(self, muc_jid)
|
|
response = ('Groupchat {} has been removed from bookmarks.'
|
|
.format(muc_jid))
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: removing bookmarks.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('default '):
|
|
key = message_text[8:]
|
|
self.settings[jid_bare][key] = None
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await sqlite.delete_setting(db_file, key)
|
|
response = ('Setting {} has been restored to default value.'
|
|
.format(key))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'defaults':
|
|
del self.settings[jid_bare]
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await sqlite.delete_settings(db_file)
|
|
response = 'Default settings have been restored.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('clear '):
|
|
key = message_text[6:]
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await sqlite.delete_filter(db_file, key)
|
|
response = 'Filter {} has been purged.'.format(key)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'bookmarks':
|
|
if is_operator(self, jid_bare):
|
|
conferences = await XmppBookmark.get_bookmarks(self)
|
|
response = action.list_bookmarks(self, conferences)
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: viewing bookmarks.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('deny +'):
|
|
key = message_text[:4].lower()
|
|
val = message_text[6:]
|
|
if val:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
keywords = sqlite.get_filter_value(db_file, key)
|
|
if keywords: keywords = str(keywords[0])
|
|
val = await config.add_to_list(val, keywords)
|
|
if sqlite.is_filter_key(db_file, key):
|
|
await sqlite.update_filter_value(db_file,
|
|
[key, val])
|
|
else:
|
|
await sqlite.set_filter_value(db_file, [key, val])
|
|
response = ('Rejected keywords\n'
|
|
'```\n{}\n```'
|
|
.format(val))
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing keywords.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('deny -'):
|
|
key = message_text[:4].lower()
|
|
val = message_text[6:]
|
|
if val:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
keywords = sqlite.get_filter_value(db_file, key)
|
|
if keywords: keywords = str(keywords[0])
|
|
val = await config.remove_from_list(val, keywords)
|
|
if sqlite.is_filter_key(db_file, key):
|
|
await sqlite.update_filter_value(db_file,
|
|
[key, val])
|
|
else:
|
|
await sqlite.set_filter_value(db_file, [key, val])
|
|
response = ('Rejected keywords\n'
|
|
'```\n{}\n```'
|
|
.format(val))
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing keywords.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('export '):
|
|
ext = message_text[7:]
|
|
if ext in ('md', 'opml'): # html xbel
|
|
status_type = 'dnd'
|
|
status_message = ('📤️ Procesing request to '
|
|
'export feeds into {}...'
|
|
.format(ext.upper()))
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
filename = action.export_feeds(self, jid_bare, jid_file, ext)
|
|
url = await XmppUpload.start(self, jid_bare, filename)
|
|
# response = (
|
|
# 'Feeds exported successfully to {}.\n{}'
|
|
# ).format(ex, url)
|
|
# XmppMessage.send_oob_reply_message(message, url, response)
|
|
chat_type = await get_chat_type(self, jid_bare)
|
|
XmppMessage.send_oob(self, jid_bare, url, chat_type)
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
else:
|
|
response = ('Unsupported filetype.\n'
|
|
'Try: md or opml')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if (message_lowercase.startswith('gemini:') or
|
|
message_lowercase.startswith('gopher:')):
|
|
response = 'Gemini and Gopher are not supported yet.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if (message_lowercase.startswith('http')) and(
|
|
message_lowercase.endswith('.opml')):
|
|
url = message_text
|
|
key_list = ['status']
|
|
task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
status_type = 'dnd'
|
|
status_message = '📥️ Procesing request to import feeds...'
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
result = await fetch.http(url)
|
|
count = await action.import_opml(db_file, result)
|
|
if count:
|
|
response = ('Successfully imported {} feeds.'
|
|
.format(count))
|
|
else:
|
|
response = 'OPML file was not imported.'
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('pubsub list '):
|
|
jid = message_text[12:]
|
|
from slixfeed.xmpp.publish import XmppPubsub
|
|
iq = await XmppPubsub.get_nodes(self, jid)
|
|
response = 'List of nodes for {}:\n```\n'.format(jid)
|
|
for item in iq['disco_items']:
|
|
item_id = item['node']
|
|
item_name = item['name']
|
|
response += 'Name: {}\nNode: {}\n\n'.format(item_name, item_id)
|
|
response += '```'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('pubsub send '):
|
|
if is_operator(self, jid_bare):
|
|
info = message_text[12:]
|
|
info = info.split(' ')
|
|
jid = info[0]
|
|
# num = int(info[1])
|
|
if jid:
|
|
# if num:
|
|
# report = await action.xmpp_pubsub_send_unread_items(
|
|
# self, jid, num)
|
|
# else:
|
|
# report = await action.xmpp_pubsub_send_unread_items(
|
|
# self, jid)
|
|
report = await action.xmpp_pubsub_send_unread_items(
|
|
self, jid)
|
|
response = ''
|
|
for url in report:
|
|
if report[url]:
|
|
response += url + ' : ' + str(report[url]) + '\n'
|
|
else:
|
|
response = 'PubSub JID is missing. Enter PubSub JID.'
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: sending news to PubSub.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
# TODO Handle node error
|
|
# sqlite3.IntegrityError: UNIQUE constraint failed: feeds_pubsub.node
|
|
# ERROR:slixmpp.basexmpp:UNIQUE constraint failed: feeds_pubsub.node
|
|
case _ if message_lowercase.startswith('pubsub '):
|
|
if is_operator(self, jid_bare):
|
|
info = message_text[7:].split(' ')
|
|
if len(info) > 1:
|
|
jid = info[0]
|
|
if '/' not in jid:
|
|
url = info[1]
|
|
db_file = config.get_pathname_to_database(jid)
|
|
if len(info) > 2:
|
|
identifier = info[2]
|
|
else:
|
|
counter = 0
|
|
hostname = uri.get_hostname(url)
|
|
hostname = hostname.replace('.','-')
|
|
identifier = hostname + ':' + str(counter)
|
|
while True:
|
|
if sqlite.check_identifier_exist(
|
|
db_file, identifier):
|
|
counter += 1
|
|
identifier = hostname + ':' + str(counter)
|
|
else:
|
|
break
|
|
# task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
status_type = 'dnd'
|
|
status_message = ('📫️ Processing request to fetch data from {}'
|
|
.format(url))
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
if url.startswith('feed:/') or url.startswith('itpc:/') or url.startswith('rss:/'):
|
|
url = uri.feed_to_http(url)
|
|
url = (await uri.replace_hostname(url, 'feed')) or url
|
|
result = await action.add_feed(self, jid_bare,
|
|
db_file, url,
|
|
identifier)
|
|
if isinstance(result, list):
|
|
results = result
|
|
response = ("Syndication feeds found for {}\n\n```\n"
|
|
.format(url))
|
|
for result in results:
|
|
response += ("Title : {}\n"
|
|
"Link : {}\n"
|
|
"\n"
|
|
.format(result['name'], result['link']))
|
|
response += ('```\nTotal of {} feeds.'
|
|
.format(len(results)))
|
|
elif result['exist']:
|
|
response = ('> {}\nNews source "{}" is already '
|
|
'listed in the subscription list at '
|
|
'index {}'
|
|
.format(result['link'],
|
|
result['name'],
|
|
result['index']))
|
|
elif result['identifier']:
|
|
response = ('> {}\nIdentifier "{}" is already '
|
|
'allocated to index {}'
|
|
.format(result['link'],
|
|
result['identifier'],
|
|
result['index']))
|
|
elif result['error']:
|
|
response = ('> {}\nFailed to find subscriptions. '
|
|
'Reason: {} (status code: {})'
|
|
.format(url, result['message'],
|
|
result['code']))
|
|
else:
|
|
response = ('> {}\nNews source "{}" has been '
|
|
'added to subscription list.'
|
|
.format(result['link'], result['name']))
|
|
# task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
print(self.pending_tasks)
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
# except:
|
|
# response = (
|
|
# '> {}\nNews source is in the process '
|
|
# 'of being added to the subscription '
|
|
# 'list.'.format(url)
|
|
# )
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'JID may not include "/".')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing argument. '
|
|
'Enter PubSub JID and subscription URL '
|
|
'(and optionally: Identifier Name).')
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: publishing to node.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if (message_lowercase.startswith('http') or
|
|
message_lowercase.startswith('feed:/') or
|
|
message_lowercase.startswith('itpc:/') or
|
|
message_lowercase.startswith('rss:/')):
|
|
url = message_text
|
|
# task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
status_type = 'dnd'
|
|
status_message = ('📫️ Processing request to fetch data from {}'
|
|
.format(url))
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
if url.startswith('feed:/') or url.startswith('rss:/'):
|
|
url = uri.feed_to_http(url)
|
|
url = (await uri.replace_hostname(url, 'feed')) or url
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
counter = 0
|
|
hostname = uri.get_hostname(url)
|
|
hostname = hostname.replace('.','-')
|
|
identifier = hostname + ':' + str(counter)
|
|
while True:
|
|
if sqlite.check_identifier_exist(db_file, identifier):
|
|
counter += 1
|
|
identifier = hostname + ':' + str(counter)
|
|
else:
|
|
break
|
|
# try:
|
|
result = await action.add_feed(self, jid_bare, db_file, url,
|
|
identifier)
|
|
if isinstance(result, list):
|
|
results = result
|
|
response = ("Syndication feeds found for {}\n\n```\n"
|
|
.format(url))
|
|
for result in results:
|
|
response += ("Title : {}\n"
|
|
"Link : {}\n"
|
|
"\n"
|
|
.format(result['name'], result['link']))
|
|
response += ('```\nTotal of {} feeds.'
|
|
.format(len(results)))
|
|
elif result['exist']:
|
|
response = ('> {}\nNews source "{}" is already '
|
|
'listed in the subscription list at '
|
|
'index {}'.format(result['link'],
|
|
result['name'],
|
|
result['index']))
|
|
elif result['error']:
|
|
response = ('> {}\nFailed to find subscriptions. '
|
|
'Reason: {} (status code: {})'
|
|
.format(url, result['message'],
|
|
result['code']))
|
|
else:
|
|
response = ('> {}\nNews source "{}" has been '
|
|
'added to subscription list.'
|
|
.format(result['link'], result['name']))
|
|
# task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
print(self.pending_tasks)
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
# except:
|
|
# response = (
|
|
# '> {}\nNews source is in the process '
|
|
# 'of being added to the subscription '
|
|
# 'list.'.format(url)
|
|
# )
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('feeds'):
|
|
query = message_text[6:]
|
|
if query:
|
|
if len(query) > 3:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
result = sqlite.search_feeds(db_file, query)
|
|
response = action.list_feeds_by_query(query, result)
|
|
else:
|
|
response = 'Enter at least 4 characters to search'
|
|
else:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
result = sqlite.get_feeds(db_file)
|
|
response = action.list_feeds(result)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'goodbye':
|
|
if message['type'] == 'groupchat':
|
|
XmppGroupchat.leave(self, jid_bare)
|
|
await XmppBookmark.remove(self, jid_bare)
|
|
else:
|
|
response = 'This command is valid in groupchat only.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('interval '):
|
|
key = message_text[:8].lower()
|
|
val = message_text[9:]
|
|
if val:
|
|
try:
|
|
val_new = int(val)
|
|
val_old = Config.get_setting_value(self.settings, jid_bare, key)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(
|
|
self.settings, jid_bare, db_file, key, val_new)
|
|
# NOTE Perhaps this should be replaced by functions
|
|
# clean and start
|
|
task.refresh_task(self, jid_bare,
|
|
task.task_message, key, val_new)
|
|
response = ('Updates will be sent every {} minutes '
|
|
'(was: {}).'.format(val_new, val_old))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Enter a numeric value only.')
|
|
else:
|
|
response = 'Missing value.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('join'):
|
|
muc_jid = uri.check_xmpp_uri(message_text[5:])
|
|
if muc_jid:
|
|
# TODO probe JID and confirm it's a groupchat
|
|
result = await XmppGroupchat.join(self, muc_jid)
|
|
# await XmppBookmark.add(self, jid=muc_jid)
|
|
if result == 'ban':
|
|
response = ('{} is banned from {}'
|
|
.format(self.alias, muc_jid))
|
|
else:
|
|
await XmppBookmark.add(self, muc_jid)
|
|
response = ('Joined groupchat {}'
|
|
.format(message_text))
|
|
else:
|
|
response = ('> {}\n'
|
|
'XMPP URI is not valid.'
|
|
.format(message_text))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('length '):
|
|
key = message_text[:6].lower()
|
|
val = message_text[7:]
|
|
if val:
|
|
try:
|
|
val_new = int(val)
|
|
val_old = Config.get_setting_value(
|
|
self.settings, jid_bare, key)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(
|
|
self.settings, jid_bare, db_file, key, val_new)
|
|
if val_new == 0: # if not val:
|
|
response = ('Summary length limit is disabled '
|
|
'(was: {}).'.format(val_old))
|
|
else:
|
|
response = ('Summary maximum length is set to '
|
|
'{} characters (was: {}).'
|
|
.format(val_new, val_old))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Enter a numeric value only.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing value.')
|
|
# case _ if message_lowercase.startswith('mastership'):
|
|
# key = message_text[:7]
|
|
# val = message_text[11:]
|
|
# if val:
|
|
# names = await initdb(
|
|
# jid_bare,
|
|
# sqlite.get_setting_value,
|
|
# key
|
|
# )
|
|
# val = await config.add_to_list(
|
|
# val,
|
|
# names
|
|
# )
|
|
# await initdb(
|
|
# jid_bare,
|
|
# sqlite.update_setting_valuevv,
|
|
# [key, val]
|
|
# )
|
|
# response = (
|
|
# 'Operators\n'
|
|
# '```\n{}\n```'
|
|
# ).format(val)
|
|
# else:
|
|
# response = 'Missing value.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'media off':
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
key = 'media'
|
|
val = 0
|
|
await Config.set_setting_value(
|
|
self.settings, jid_bare, db_file, key, val)
|
|
response = 'Media is disabled.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'media on':
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
key = 'media'
|
|
val = 1
|
|
await Config.set_setting_value(self.settings, jid_bare,
|
|
db_file, key, val)
|
|
response = 'Media is enabled.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'new':
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
key = 'old'
|
|
val = 0
|
|
await Config.set_setting_value(self.settings, jid_bare,
|
|
db_file, key, val)
|
|
response = 'Only new items of newly added feeds be delivered.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('node delete '):
|
|
if is_operator(self, jid_bare):
|
|
info = message_text[12:]
|
|
info = info.split(' ')
|
|
if len(info) > 2:
|
|
jid = info[0]
|
|
nid = info[1]
|
|
if jid:
|
|
from slixfeed.xmpp.publish import XmppPubsub
|
|
XmppPubsub.delete_node(self, jid, nid)
|
|
response = 'Deleted node: ' + nid
|
|
else:
|
|
response = 'PubSub JID is missing. Enter PubSub JID.'
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing argument. '
|
|
'Enter JID and Node name.')
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: sending news to PubSub.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('node purge '):
|
|
if is_operator(self, jid_bare):
|
|
info = message_text[11:]
|
|
info = info.split(' ')
|
|
if len(info) > 1:
|
|
jid = info[0]
|
|
nid = info[1]
|
|
if jid:
|
|
from slixfeed.xmpp.publish import XmppPubsub
|
|
XmppPubsub.purge_node(self, jid, nid)
|
|
response = 'Purged node: ' + nid
|
|
else:
|
|
response = 'PubSub JID is missing. Enter PubSub JID.'
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing argument. '
|
|
'Enter JID and Node name.')
|
|
else:
|
|
response = ('This action is restricted. '
|
|
'Type: sending news to PubSub.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('next'):
|
|
num = message_text[5:]
|
|
if num:
|
|
await action.xmpp_chat_send_unread_items(self,
|
|
jid_bare, num)
|
|
else:
|
|
await action.xmpp_chat_send_unread_items(self, jid_bare)
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
case 'old':
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
key = 'old'
|
|
val = 1
|
|
await Config.set_setting_value(self.settings, jid_bare,
|
|
db_file, key, val)
|
|
response = 'All items of newly added feeds be delivered.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'options':
|
|
response = 'Options:\n```'
|
|
for key in self.settings[jid_bare]:
|
|
val = Config.get_setting_value(self.settings, jid_bare, key)
|
|
# val = Config.get_setting_value(self.settings, jid_bare, key)
|
|
steps = 11 - len(key)
|
|
pulse = ''
|
|
for step in range(steps):
|
|
pulse += ' '
|
|
response += '\n' + key + pulse + ': ' + str(val)
|
|
print(response)
|
|
response += '\n```'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('quantum '):
|
|
key = message_text[:7].lower()
|
|
val = message_text[8:]
|
|
if val:
|
|
try:
|
|
val_new = int(val)
|
|
val_old = Config.get_setting_value(self.settings,
|
|
jid_bare, key)
|
|
# response = (
|
|
# 'Every update will contain {} news items.'
|
|
# ).format(response)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(self.settings, jid_bare,
|
|
db_file, key, val_new)
|
|
response = ('Next update will contain {} news items '
|
|
'(was: {}).'.format(val_new, val_old))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Enter a numeric value only.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing value.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'random':
|
|
# TODO /questions/2279706/select-random-row-from-a-sqlite-table
|
|
# NOTE sqlitehandler.get_entry_unread
|
|
response = 'Updates will be sent by random order.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('read '):
|
|
data = message_text[5:]
|
|
data = data.split()
|
|
url = data[0]
|
|
if url:
|
|
key_list = ['status']
|
|
task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
status_type = 'dnd'
|
|
status_message = ('📫️ Processing request to fetch data '
|
|
'from {}'.format(url))
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
if url.startswith('feed:/') or url.startswith('rss:/'):
|
|
url = uri.feed_to_http(url)
|
|
url = (await uri.replace_hostname(url, 'feed')) or url
|
|
match len(data):
|
|
case 1:
|
|
if url.startswith('http'):
|
|
while True:
|
|
result = await fetch.http(url)
|
|
status = result['status_code']
|
|
if not result['error']:
|
|
document = result['content']
|
|
feed = parse(document)
|
|
# if is_feed(url, feed):
|
|
if action.is_feed(feed):
|
|
response = action.view_feed(url, feed)
|
|
break
|
|
else:
|
|
result = await crawl.probe_page(url, document)
|
|
if isinstance(result, list):
|
|
results = result
|
|
response = ("Syndication feeds found for {}\n\n```\n"
|
|
.format(url))
|
|
for result in results:
|
|
response += ("Title : {}\n"
|
|
"Link : {}\n"
|
|
"\n"
|
|
.format(result['name'], result['link']))
|
|
response += ('```\nTotal of {} feeds.'
|
|
.format(len(results)))
|
|
break
|
|
else:
|
|
url = result['link']
|
|
else:
|
|
response = ('> {}\nFailed to load URL. Reason: {}'
|
|
.format(url, status))
|
|
break
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing URL.')
|
|
case 2:
|
|
num = data[1]
|
|
if url.startswith('http'):
|
|
while True:
|
|
result = await fetch.http(url)
|
|
if not result['error']:
|
|
document = result['content']
|
|
status = result['status_code']
|
|
feed = parse(document)
|
|
# if is_feed(url, feed):
|
|
if action.is_feed(feed):
|
|
response = action.view_entry(url, feed, num)
|
|
break
|
|
else:
|
|
result = await crawl.probe_page(url, document)
|
|
if isinstance(result, list):
|
|
results = result
|
|
response = ("Syndication feeds found for {}\n\n```\n"
|
|
.format(url))
|
|
for result in results:
|
|
response += ("Title : {}\n"
|
|
"Link : {}\n"
|
|
"\n"
|
|
.format(result['name'], result['link']))
|
|
response += ('```\nTotal of {} feeds.'
|
|
.format(len(results)))
|
|
break
|
|
else:
|
|
url = result['link']
|
|
else:
|
|
response = ('> {}\nFailed to load URL. Reason: {}'
|
|
.format(url, status))
|
|
break
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing URL.')
|
|
case _:
|
|
response = ('Enter command as follows:\n'
|
|
'`read <url>` or `read <url> <number>`\n'
|
|
'URL must not contain white space.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing URL.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
case _ if message_lowercase.startswith('recent '):
|
|
num = message_text[7:]
|
|
if num:
|
|
try:
|
|
num = int(num)
|
|
if num < 1 or num > 50:
|
|
response = 'Value must be ranged from 1 to 50.'
|
|
else:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
result = sqlite.get_last_entries(db_file, num)
|
|
response = action.list_last_entries(result, num)
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Enter a numeric value only.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing value.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('remove '):
|
|
ix_url = message_text[7:]
|
|
ix_url = ix_url.split(' ')
|
|
if ix_url:
|
|
for i in ix_url:
|
|
if i:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
try:
|
|
ix = int(i)
|
|
url = sqlite.get_feed_url(db_file, ix)
|
|
if url:
|
|
url = url[0]
|
|
name = sqlite.get_feed_title(db_file, ix)
|
|
name = name[0]
|
|
await sqlite.remove_feed_by_index(db_file, ix)
|
|
response = ('> {}\n'
|
|
'News source "{}" has been '
|
|
'removed from subscription list.'
|
|
.format(url, name))
|
|
else:
|
|
response = ('No news source with index {}.'
|
|
.format(ix))
|
|
except:
|
|
url = i
|
|
feed_id = sqlite.get_feed_id(db_file, url)
|
|
if feed_id:
|
|
feed_id = feed_id[0]
|
|
await sqlite.remove_feed_by_url(db_file, url)
|
|
response = ('> {}\n'
|
|
'News source has been removed '
|
|
'from subscription list.'
|
|
.format(url))
|
|
else:
|
|
response = ('> {}\n'
|
|
# 'No action has been made.'
|
|
'News source does not exist. '
|
|
.format(url))
|
|
# refresh_task(self, jid_bare, send_status, 'status', 20)
|
|
# task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
XmppMessage.send_reply(self, message, response)
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing argument. '
|
|
'Enter subscription URL or index number.')
|
|
case _ if message_lowercase.startswith('reset'):
|
|
# TODO Reset also by ID
|
|
ix_url = message_text[6:]
|
|
key_list = ['status']
|
|
task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
status_type = 'dnd'
|
|
status_message = '📫️ Marking entries as read...'
|
|
# pending_tasks_num = len(self.pending_tasks[jid_bare])
|
|
pending_tasks_num = randrange(10000, 99999)
|
|
self.pending_tasks[jid_bare][pending_tasks_num] = status_message
|
|
# self.pending_tasks_counter += 1
|
|
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
if ix_url:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
try:
|
|
ix = int(ix_url)
|
|
url = sqlite.get_feed_url(db_file, ix)
|
|
if url:
|
|
url = url[0]
|
|
name = sqlite.get_feed_title(db_file, ix)
|
|
name = name[0]
|
|
await sqlite.mark_feed_as_read(db_file, ix)
|
|
response = ('> {}\n'
|
|
'All entries of source "{}" have been '
|
|
'marked as read.'
|
|
.format(url, name))
|
|
else:
|
|
response = ('No news source with index {}.'
|
|
.format(ix))
|
|
except:
|
|
url = ix_url
|
|
feed_id = sqlite.get_feed_id(db_file, url)
|
|
if feed_id:
|
|
feed_id = feed_id[0]
|
|
name = sqlite.get_feed_title(db_file, feed_id)
|
|
name = name[0]
|
|
await sqlite.mark_feed_as_read(db_file, feed_id)
|
|
response = ('> {}\n'
|
|
'All entries of source "{}" have been '
|
|
'marked as read.'
|
|
.format(url, name))
|
|
else:
|
|
response = ('> {}\n'
|
|
# 'No action has been made.'
|
|
'News source does not exist. '
|
|
.format(url))
|
|
else:
|
|
await sqlite.mark_all_as_read(db_file)
|
|
response = 'All entries have been marked as read.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
del self.pending_tasks[jid_bare][pending_tasks_num]
|
|
# del self.pending_tasks[jid_bare][self.pending_tasks_counter]
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
case _ if message_lowercase.startswith('search '):
|
|
query = message_text[7:]
|
|
if query:
|
|
if len(query) > 1:
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
results = await sqlite.search_entries(db_file, query)
|
|
response = action.list_search_results(query, results)
|
|
else:
|
|
response = 'Enter at least 2 characters to search'
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing search query.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'start':
|
|
key = 'enabled'
|
|
val = 1
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(self.settings, jid_bare,
|
|
db_file, key, val)
|
|
status_type = 'available'
|
|
status_message = '📫️ Welcome back!'
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
await asyncio.sleep(5)
|
|
key_list = ['check', 'status', 'interval']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
response = 'Updates are enabled.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'stats':
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
response = await action.list_statistics(db_file)
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('disable '):
|
|
feed_id = message_text[8:]
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
try:
|
|
await sqlite.set_enabled_status(db_file, feed_id, 0)
|
|
await sqlite.mark_feed_as_read(db_file, feed_id)
|
|
name = sqlite.get_feed_title(db_file, feed_id)[0]
|
|
addr = sqlite.get_feed_url(db_file, feed_id)[0]
|
|
response = ('> {}\n'
|
|
'Updates are now disabled for news source "{}"'
|
|
.format(addr, name))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'No news source with index {}.'
|
|
.format(feed_id))
|
|
XmppMessage.send_reply(self, message, response)
|
|
key_list = ['status']
|
|
await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
case _ if message_lowercase.startswith('rename '):
|
|
message_text = message_text[7:]
|
|
feed_id = message_text.split(' ')[0]
|
|
name = ' '.join(message_text.split(' ')[1:])
|
|
if name:
|
|
try:
|
|
feed_id = int(feed_id)
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
name_old = sqlite.get_feed_title(db_file, feed_id)
|
|
if name_old:
|
|
name_old = name_old[0]
|
|
if name == name_old:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Input name is identical to the '
|
|
'existing name.')
|
|
else:
|
|
await sqlite.set_feed_title(db_file, feed_id,
|
|
name)
|
|
response = ('> {}'
|
|
'\n'
|
|
'Subscription #{} has been '
|
|
'renamed to "{}".'.format(
|
|
name_old,feed_id, name))
|
|
else:
|
|
response = ('Subscription with Id {} does not '
|
|
'exist.'.format(feed_id))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Subscription Id must be a numeric value.')
|
|
else:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'Missing argument. '
|
|
'Enter subscription Id and name.')
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('enable '):
|
|
feed_id = message_text[7:]
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
try:
|
|
await sqlite.set_enabled_status(db_file, feed_id, 1)
|
|
name = sqlite.get_feed_title(db_file, feed_id)[0]
|
|
addr = sqlite.get_feed_url(db_file, feed_id)[0]
|
|
response = ('> {}\n'
|
|
'Updates are now enabled for news source "{}"'
|
|
.format(addr, name))
|
|
except:
|
|
response = ('No action has been taken.'
|
|
'\n'
|
|
'No news source with index {}.'.format(ix))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'stop':
|
|
key = 'enabled'
|
|
val = 0
|
|
db_file = config.get_pathname_to_database(jid_file)
|
|
await Config.set_setting_value(
|
|
self.settings, jid_bare, db_file, key, val)
|
|
key_list = ['interval', 'status']
|
|
task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
|
|
status_type = 'xa'
|
|
status_message = '📪️ Send "Start" to receive Jabber updates'
|
|
XmppPresence.send(self, jid_bare, status_message,
|
|
status_type=status_type)
|
|
response = 'Updates are disabled.'
|
|
XmppMessage.send_reply(self, message, response)
|
|
case 'support':
|
|
muc_jid = 'slixfeed@chat.woodpeckersnest.space'
|
|
response = 'Join xmpp:{}?join'.format(muc_jid)
|
|
XmppMessage.send_reply(self, message, response)
|
|
if await get_chat_type(self, jid_bare) == 'chat':
|
|
self.plugin['xep_0045'].invite(muc_jid, jid_bare)
|
|
case 'version':
|
|
response = __version__
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _ if message_lowercase.startswith('xmpp:'):
|
|
muc_jid = uri.check_xmpp_uri(message_text)
|
|
if muc_jid:
|
|
# TODO probe JID and confirm it's a groupchat
|
|
XmppGroupchat.join(self, muc_jid)
|
|
# await XmppBookmark.add(self, jid=muc_jid)
|
|
response = ('Joined groupchat {}'
|
|
.format(message_text))
|
|
else:
|
|
response = ('> {}\n'
|
|
'XMPP URI is not valid.'
|
|
.format(message_text))
|
|
XmppMessage.send_reply(self, message, response)
|
|
case _:
|
|
response = ('Unknown command. '
|
|
'Press "help" for list of commands')
|
|
XmppMessage.send_reply(self, message, response)
|
|
# TODO Use message correction here
|
|
# NOTE This might not be a good idea if
|
|
# commands are sent one close to the next
|
|
# if response: message.reply(response).send()
|
|
|
|
command_time_finish = time.time()
|
|
command_time_total = command_time_finish - command_time_start
|
|
command_time_total = round(command_time_total, 3)
|
|
response = 'Finished. Total time: {}s'.format(command_time_total)
|
|
XmppMessage.send_reply(self, message, response)
|
|
|
|
if not response: response = 'EMPTY MESSAGE - ACTION ONLY'
|
|
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 + '/logs/'):
|
|
os.mkdir(data_dir + '/logs/')
|
|
action.log_to_markdown(
|
|
dt.current_time(), os.path.join(data_dir, 'logs', jid_file),
|
|
jid_bare, message_text)
|
|
action.log_to_markdown(
|
|
dt.current_time(), os.path.join(data_dir, 'logs', jid_file),
|
|
jid_bare, response)
|
|
|
|
print(
|
|
'Message : {}\n'
|
|
'JID : {}\n'
|
|
'File : {}\n'
|
|
'{}\n'
|
|
.format(message_text, jid_bare, jid_file, response)
|
|
)
|