Improve PubSub support (WIP).

Improve MUC handling.
Add command "send" to add feeds to other JIDs.
Ad-Hoc: Add functionality to specify JId to commit actions on upon.
Add subscription preview upon adding a subscription.
Add project Jabber RSS Transport to bots list.
Add projects Psi and Psi+ to clients list.
This commit is contained in:
Schimon Jehudah 2024-03-26 16:23:22 +00:00
parent 35beab7802
commit 5507b16161
13 changed files with 1767 additions and 1134 deletions

View file

@ -49,8 +49,10 @@ from slixfeed.url import (
) )
import slixfeed.task as task import slixfeed.task as task
from slixfeed.xmpp.bookmark import XmppBookmark from slixfeed.xmpp.bookmark import XmppBookmark
from slixfeed.xmpp.iq import XmppIQ
from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.presence import XmppPresence
from slixfeed.xmpp.publish import XmppPubsub
from slixfeed.xmpp.upload import XmppUpload from slixfeed.xmpp.upload import XmppUpload
from slixfeed.xmpp.utility import get_chat_type from slixfeed.xmpp.utility import get_chat_type
import sys import sys
@ -134,7 +136,7 @@ if (await get_chat_type(self, jid_bare) == 'chat' and
""" """
async def xmpp_send_status(self, jid): async def xmpp_send_status_message(self, jid):
""" """
Send status message. Send status message.
@ -190,7 +192,50 @@ async def xmpp_send_status(self, jid):
# ) # )
async def xmpp_send_update(self, jid, num=None): async def xmpp_send_pubsub(self, jid_bare):
function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_bare: {}'.format(function_name, jid_bare))
jid_file = jid_bare.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
if enabled:
subscriptions = sqlite.get_active_feeds_url(db_file)
for url in subscriptions:
url = url[0]
feed_id = sqlite.get_feed_id(db_file, url)
feed_id = feed_id[0]
feed_title = sqlite.get_feed_title(db_file, feed_id)
feed_title = feed_title[0]
feed_summary = None
node = sqlite.get_node_name(db_file, feed_id)
node = node[0]
xep = None
iq_create_node = XmppPubsub.create_node(
self, jid_bare, node, xep, feed_title, feed_summary)
await XmppIQ.send(self, iq_create_node)
entries = sqlite.get_unread_entries_of_feed(db_file, feed_id)
feed_properties = sqlite.get_feed_properties(db_file, feed_id)
feed_version = feed_properties[2]
for entry in entries:
feed_entry = {'author' : None,
'authors' : None,
'category' : None,
'content' : None,
'description' : entry[3],
'href' : entry[2],
'links' : entry[4],
'tags' : None,
'title' : entry[1],
'type' : None,
'updated' : entry[7]}
iq_create_entry = XmppPubsub.create_entry(
self, jid_bare, node, feed_entry, feed_version)
await XmppIQ.send(self, iq_create_entry)
ix = entry[0]
await sqlite.mark_as_read(db_file, ix)
async def xmpp_send_message(self, jid, num=None):
""" """
Send news items as messages. Send news items as messages.
@ -272,7 +317,7 @@ async def xmpp_send_update(self, jid, num=None):
# TODO Do not refresh task before # TODO Do not refresh task before
# verifying that it was completed. # verifying that it was completed.
# await start_tasks_xmpp(self, jid, ['status']) # await start_tasks_xmpp_chat(self, jid, ['status'])
# await refresh_task(self, jid, send_update, 'interval') # await refresh_task(self, jid, send_update, 'interval')
# interval = await initdb( # interval = await initdb(
@ -767,13 +812,15 @@ async def import_opml(db_file, result):
return difference return difference
async def add_feed(self, jid_bare, db_file, url): async def add_feed(self, jid_bare, db_file, url, node):
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} url: {}' logger.debug('{}: db_file: {} url: {}'
.format(function_name, db_file, url)) .format(function_name, db_file, url))
while True: while True:
exist = sqlite.get_feed_id_and_name(db_file, url) exist_feed = sqlite.get_feed_id_and_name(db_file, url)
if not exist: if not exist_feed:
exist_node = sqlite.check_node_exist(db_file, node)
if not exist_node:
result = await fetch.http(url) result = await fetch.http(url)
message = result['message'] message = result['message']
status_code = result['status_code'] status_code = result['status_code']
@ -804,8 +851,7 @@ async def add_feed(self, jid_bare, db_file, url):
updated = '' updated = ''
version = feed["version"] version = feed["version"]
entries = len(feed["entries"]) entries = len(feed["entries"])
await sqlite.insert_feed(db_file, url, await sqlite.insert_feed(db_file, url, title, node,
title=title,
entries=entries, entries=entries,
version=version, version=version,
encoding=encoding, encoding=encoding,
@ -823,7 +869,9 @@ async def add_feed(self, jid_bare, db_file, url):
'name' : title, 'name' : title,
'code' : status_code, 'code' : status_code,
'error' : False, 'error' : False,
'exist' : False} 'message': message,
'exist' : False,
'node' : None}
break break
# NOTE This elif statement be unnecessary # NOTE This elif statement be unnecessary
# when feedparser be supporting json feed. # when feedparser be supporting json feed.
@ -851,8 +899,7 @@ async def add_feed(self, jid_bare, db_file, url):
updated = '' updated = ''
version = 'json' + feed["version"].split('/').pop() version = 'json' + feed["version"].split('/').pop()
entries = len(feed["items"]) entries = len(feed["items"])
await sqlite.insert_feed(db_file, url, await sqlite.insert_feed(db_file, url, title, node,
title=title,
entries=entries, entries=entries,
version=version, version=version,
encoding=encoding, encoding=encoding,
@ -870,7 +917,9 @@ async def add_feed(self, jid_bare, db_file, url):
'name' : title, 'name' : title,
'code' : status_code, 'code' : status_code,
'error' : False, 'error' : False,
'exist' : False} 'message': message,
'exist' : False,
'node' : None}
break break
else: else:
# NOTE Do not be tempted to return a compact dictionary. # NOTE Do not be tempted to return a compact dictionary.
@ -885,7 +934,8 @@ async def add_feed(self, jid_bare, db_file, url):
'code' : status_code, 'code' : status_code,
'error' : True, 'error' : True,
'message': message, 'message': message,
'exist' : False} 'exist' : False,
'node' : None}
break break
elif isinstance(result, list): elif isinstance(result, list):
# Get out of the loop and deliver a list of dicts. # Get out of the loop and deliver a list of dicts.
@ -901,11 +951,25 @@ async def add_feed(self, jid_bare, db_file, url):
'code' : status_code, 'code' : status_code,
'error' : True, 'error' : True,
'message': message, 'message': message,
'exist' : False} 'exist' : False,
'node' : None}
break break
else: else:
ix = exist[0] ix = exist_node[1]
name = exist[1] node = exist_node[2]
message = 'Node is already allocated.'
result_final = {'link' : url,
'index' : ix,
'name' : None,
'code' : None,
'error' : False,
'message': message,
'exist' : False,
'node' : node}
break
else:
ix = exist_feed[0]
name = exist_feed[1]
message = 'URL already exist.' message = 'URL already exist.'
result_final = {'link' : url, result_final = {'link' : url,
'index' : ix, 'index' : ix,
@ -913,7 +977,8 @@ async def add_feed(self, jid_bare, db_file, url):
'code' : None, 'code' : None,
'error' : False, 'error' : False,
'message': message, 'message': message,
'exist' : True} 'exist' : True,
'node' : None}
break break
return result_final return result_final

View file

@ -174,6 +174,16 @@ newsfeeds.
interface = "Groupchat" interface = "Groupchat"
url = "https://salsa.debian.org/mdosch/feed-to-muc" url = "https://salsa.debian.org/mdosch/feed-to-muc"
[[friends]]
name = "Jabber RSS Transport"
info = ["""
Jabber RSS Transport is one of the possibilities to read news in Jabber \
via RSS, which allows you not to use a separate program, but to receive \
them directly in your favorite Jabber client.
"""]
interface = "Chat"
url = "https://jabberworld.info/Jabber_RSS_Transport"
[[friends]] [[friends]]
name = "JabRSS by Christof" name = "JabRSS by Christof"
info = [""" info = ["""
@ -648,15 +658,15 @@ name = "Poezio"
info = "XMPP client for console" info = "XMPP client for console"
url = "https://poez.io" url = "https://poez.io"
# [[clients]] [[clients]]
# name = "Psi" name = "Psi"
# info = "XMPP client for desktop" info = "XMPP client for desktop"
# url = "https://psi-im.org" url = "https://psi-im.org"
# [[clients]] [[clients]]
# name = "Psi+" name = "Psi+"
# info = "XMPP client for desktop" info = "XMPP client for desktop"
# url = "https://psi-plus.com" url = "https://psi-plus.com"
# [[clients]] # [[clients]]
# name = "Swift" # name = "Swift"

View file

@ -58,6 +58,18 @@ name = "Berlin XMPP Meetup"
link = "https://mov.im/?feed/pubsub.movim.eu/berlin-xmpp-meetup" link = "https://mov.im/?feed/pubsub.movim.eu/berlin-xmpp-meetup"
tags = ["event", "germany", "xmpp"] tags = ["event", "germany", "xmpp"]
[[feeds]]
lang = "de-de"
name = "blog | hasecke"
link = "https://www.hasecke.eu/index.xml"
tags = ["linux", "p2p", "software", "technology"]
[[feeds]]
lang = "de-de"
name = "heise online News"
link = "https://www.heise.de/rss/heise-atom.xml"
tags = ["computer", "industry", "electronics", "technology"]
[[feeds]] [[feeds]]
lang = "de-de" lang = "de-de"
name = "CCC Event Blog" name = "CCC Event Blog"
@ -214,6 +226,12 @@ name = "La Quadrature du Net"
link = "https://www.laquadrature.net/en/feed/" link = "https://www.laquadrature.net/en/feed/"
tags = ["news", "politics", "privacy", "surveillance"] tags = ["news", "politics", "privacy", "surveillance"]
[[feeds]]
lang = "en-gb"
name = "op-co.de blog"
link = "https://op-co.de/blog/index.rss"
tags = ["code", "germany", "jabber", "mastodon", "telecommunication", "xmpp"]
[[feeds]] [[feeds]]
lang = "en-gb" lang = "en-gb"
name = "Pimux XMPP News" name = "Pimux XMPP News"
@ -408,9 +426,9 @@ tags = ["health"]
[[feeds]] [[feeds]]
lang = "en-us" lang = "en-us"
name = "Monal IM" name = "modernity"
link = "https://monal-im.org/index.xml" link = "https://modernity.news/feed/"
tags = ["iphone", "xmpp"] tags = ["culture", "news", "politics", "usa"]
[[feeds]] [[feeds]]
lang = "en-us" lang = "en-us"
@ -418,6 +436,12 @@ name = "Mom on a Mission"
link = "https://www.mom-on-a-mission.blog/all-posts?format=rss" link = "https://www.mom-on-a-mission.blog/all-posts?format=rss"
tags = ["family", "farming", "food", "gardening", "survival"] tags = ["family", "farming", "food", "gardening", "survival"]
[[feeds]]
lang = "en-us"
name = "Monal IM"
link = "https://monal-im.org/index.xml"
tags = ["iphone", "xmpp"]
[[feeds]] [[feeds]]
lang = "en-us" lang = "en-us"
name = "NLnet News" name = "NLnet News"
@ -778,18 +802,6 @@ name = "שיחה מקומית"
link = "https://www.mekomit.co.il/feed/" link = "https://www.mekomit.co.il/feed/"
tags = ["news", "politics"] tags = ["news", "politics"]
[[feeds]]
lang = "it-it"
name = "Diggita / Prima Pagina"
link = "https://diggita.com/rss.php"
tags = ["computer", "culture", "food", "technology"]
[[feeds]]
lang = "it-it"
name = "Feddit.it"
link = "https://feddit.it/feeds/local.xml?sort=Active"
tags = ["fediverse", "forum"]
[[feeds]] [[feeds]]
lang = "it-it" lang = "it-it"
name = "A sysadmin's (mis)adventures" name = "A sysadmin's (mis)adventures"
@ -802,12 +814,30 @@ name = "Avvocato a Roma"
link = "https://www.studiosabatino.it/feed/" link = "https://www.studiosabatino.it/feed/"
tags = ["law"] tags = ["law"]
[[feeds]]
lang = "it-it"
name = "Diggita / Prima Pagina"
link = "https://diggita.com/rss.php"
tags = ["computer", "culture", "food", "technology"]
[[feeds]] [[feeds]]
lang = "it-it" lang = "it-it"
name = "Disroot Blog" name = "Disroot Blog"
link = "https://disroot.org/it/blog.atom" link = "https://disroot.org/it/blog.atom"
tags = ["decentralization", "privacy"] tags = ["decentralization", "privacy"]
[[feeds]]
lang = "it-it"
name = "Feddit.it"
link = "https://feddit.it/feeds/local.xml?sort=Active"
tags = ["fediverse", "forum"]
[[feeds]]
lang = "it-it"
name = "Italian XMPP Happy Hour - Podcast"
link = "https://podcast.xmpp-it.net/api/v1/channels/xmpphappyhour/rss"
tags = ["decentralization", "privacy", "technology", "telecommunication", "xmpp"]
[[feeds]] [[feeds]]
lang = "it-it" lang = "it-it"
name = "LinuxTrent" name = "LinuxTrent"

View file

@ -167,6 +167,19 @@ def create_tables(db_file):
); );
""" """
) )
feeds_pubsub_table_sql = (
"""
CREATE TABLE IF NOT EXISTS feeds_pubsub (
id INTEGER NOT NULL,
feed_id INTEGER NOT NULL UNIQUE,
node TEXT NOT NULL UNIQUE,
FOREIGN KEY ("feed_id") REFERENCES "feeds" ("id")
ON UPDATE CASCADE
ON DELETE CASCADE,
PRIMARY KEY (id)
);
"""
)
feeds_rules_table_sql = ( feeds_rules_table_sql = (
""" """
CREATE TABLE IF NOT EXISTS feeds_rules ( CREATE TABLE IF NOT EXISTS feeds_rules (
@ -287,6 +300,7 @@ def create_tables(db_file):
cur.execute(feeds_table_sql) cur.execute(feeds_table_sql)
cur.execute(feeds_state_table_sql) cur.execute(feeds_state_table_sql)
cur.execute(feeds_properties_table_sql) cur.execute(feeds_properties_table_sql)
cur.execute(feeds_pubsub_table_sql)
cur.execute(feeds_rules_table_sql) cur.execute(feeds_rules_table_sql)
cur.execute(feeds_tags_table_sql) cur.execute(feeds_tags_table_sql)
cur.execute(filters_table_sql) cur.execute(filters_table_sql)
@ -390,6 +404,7 @@ async def add_metadata(db_file):
feed_id = ix[0] feed_id = ix[0]
insert_feed_status(cur, feed_id) insert_feed_status(cur, feed_id)
insert_feed_properties(cur, feed_id) insert_feed_properties(cur, feed_id)
insert_feed_pubsub(cur, feed_id)
def insert_feed_status(cur, feed_id): def insert_feed_status(cur, feed_id):
@ -452,7 +467,37 @@ def insert_feed_properties(cur, feed_id):
logger.error(e) logger.error(e)
async def insert_feed(db_file, url, title=None, entries=None, version=None, def insert_feed_pubsub(cur, feed_id):
"""
Set feed pubsub.
Parameters
----------
cur : object
Cursor object.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: feed_id: {}'
.format(function_name, feed_id))
sql = (
"""
INSERT
INTO feeds_pubsub(
feed_id)
VALUES(
?)
"""
)
par = (feed_id,)
try:
cur.execute(sql, par)
except IntegrityError as e:
logger.warning(
"Skipping feed_id {} for table feeds_pubsub".format(feed_id))
logger.error(e)
async def insert_feed(db_file, url, title, node, entries=None, version=None,
encoding=None, language=None, status_code=None, encoding=None, language=None, status_code=None,
updated=None): updated=None):
""" """
@ -464,8 +509,10 @@ async def insert_feed(db_file, url, title=None, entries=None, version=None,
Path to database file. Path to database file.
url : str url : str
URL. URL.
title : str, optional title : str
Feed title. The default is None. Feed title.
node : str
Feed Node.
entries : int, optional entries : int, optional
Number of entries. The default is None. Number of entries. The default is None.
version : str, optional version : str, optional
@ -533,6 +580,19 @@ async def insert_feed(db_file, url, title=None, entries=None, version=None,
feed_id, entries, version, encoding, language feed_id, entries, version, encoding, language
) )
cur.execute(sql, par) cur.execute(sql, par)
sql = (
"""
INSERT
INTO feeds_pubsub(
feed_id, node)
VALUES(
?, ?)
"""
)
par = (
feed_id, node
)
cur.execute(sql, par)
async def insert_feed_(db_file, url, title=None, entries=None, version=None, async def insert_feed_(db_file, url, title=None, entries=None, version=None,
@ -699,7 +759,8 @@ def get_feeds_by_tag_id(db_file, tag_id):
FROM feeds FROM feeds
INNER JOIN feeds_tags ON feeds.id = feeds_tags.feed_id INNER JOIN feeds_tags ON feeds.id = feeds_tags.feed_id
INNER JOIN tags ON tags.id = feeds_tags.tag_id INNER JOIN tags ON tags.id = feeds_tags.tag_id
WHERE tags.id = ?; WHERE tags.id = ?
ORDER BY feeds.name;
""" """
) )
par = (tag_id,) par = (tag_id,)
@ -734,7 +795,8 @@ def get_tags_by_feed_id(db_file, feed_id):
FROM tags FROM tags
INNER JOIN feeds_tags ON tags.id = feeds_tags.tag_id INNER JOIN feeds_tags ON tags.id = feeds_tags.tag_id
INNER JOIN feeds ON feeds.id = feeds_tags.feed_id INNER JOIN feeds ON feeds.id = feeds_tags.feed_id
WHERE feeds.id = ?; WHERE feeds.id = ?
ORDER BY tags.tag;
""" """
) )
par = (feed_id,) par = (feed_id,)
@ -777,6 +839,109 @@ async def set_feed_id_and_tag_id(db_file, feed_id, tag_id):
cur.execute(sql, par) cur.execute(sql, par)
def get_feed_properties(db_file, feed_id):
"""
Get properties of given feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed ID.
Returns
-------
node : str
Node name.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} feed_id: {}'
.format(function_name, db_file, feed_id))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT *
FROM feeds_properties
WHERE feed_id = ?
"""
)
par = (feed_id,)
name = cur.execute(sql, par).fetchone()
return name
def get_node_name(db_file, feed_id):
"""
Get name of given node.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed ID.
Returns
-------
node : str
Node name.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} feed_id: {}'
.format(function_name, db_file, feed_id))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT node
FROM feeds_pubsub
WHERE feed_id = ?
"""
)
par = (feed_id,)
name = cur.execute(sql, par).fetchone()
return name
def check_node_exist(db_file, node_name):
"""
Check whether node exist.
Parameters
----------
db_file : str
Path to database file.
node_name : str
Node name.
Returns
-------
id : str
ID.
feed_id : str
Feed ID.
node : str
Node name.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} node_name: {}'
.format(function_name, db_file, node_name))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT id, feed_id, node
FROM feeds_pubsub
WHERE node = ?
"""
)
par = (node_name,)
name = cur.execute(sql, par).fetchone()
return name
def get_tag_id(db_file, tag_name): def get_tag_id(db_file, tag_name):
""" """
Get ID of given tag. Check whether tag exist. Get ID of given tag. Check whether tag exist.
@ -1327,6 +1492,62 @@ async def mark_entry_as_read(cur, ix):
cur.execute(sql, par) cur.execute(sql, par)
def get_status_information_of_feed(db_file, feed_id):
"""
Get status information of given feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed Id.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} feed_id: {}'
.format(function_name, db_file, feed_id))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT *
FROM feeds_state
WHERE feed_id = ?
"""
)
par = (feed_id,)
count = cur.execute(sql, par).fetchone()
return count
def get_unread_entries_of_feed(db_file, feed_id):
"""
Get entries of given feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Feed Id.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {} feed_id: {}'
.format(function_name, db_file, feed_id))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT *
FROM entries
WHERE read = 0 AND feed_id = ?
"""
)
par = (feed_id,)
count = cur.execute(sql, par).fetchall()
return count
def get_number_of_unread_entries_by_feed(db_file, feed_id): def get_number_of_unread_entries_by_feed(db_file, feed_id):
""" """
Count entries of given feed. Count entries of given feed.
@ -2157,6 +2378,37 @@ def get_feeds_by_enabled_state(db_file, enabled_state):
return result return result
def get_feeds_and_enabled_state(db_file):
"""
Select table feeds and join column enabled.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
result : tuple
List of URLs.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {}'
.format(function_name, db_file))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT feeds.*, feeds_state.enabled
FROM feeds
INNER JOIN feeds_state ON feeds.id = feeds_state.feed_id
ORDER BY feeds.name ASC
"""
)
result = cur.execute(sql).fetchall()
return result
def get_active_feeds_url(db_file): def get_active_feeds_url(db_file):
""" """
Query table feeds for active URLs. Query table feeds for active URLs.
@ -2211,6 +2463,7 @@ def get_tags(db_file):
""" """
SELECT tag, id SELECT tag, id
FROM tags FROM tags
ORDER BY tag
""" """
) )
result = cur.execute(sql).fetchall() result = cur.execute(sql).fetchall()
@ -2245,6 +2498,7 @@ def get_feeds(db_file):
""" """
SELECT id, name, url SELECT id, name, url
FROM feeds FROM feeds
ORDER BY name
""" """
) )
result = cur.execute(sql).fetchall() result = cur.execute(sql).fetchall()

View file

@ -3,6 +3,19 @@
""" """
IMPORTANT CONSIDERATION
This file appears to be redundant and may be replaced by a dict handler that
would match task keyword to functions.
Or use it as a class Task
tasks_xmpp_chat = {"check" : check_updates,
"status" : task_status_message,
"interval" : task_message}
tasks_xmpp_pubsub = {"check" : check_updates,
"pubsub" : task_pubsub}
TODO TODO
1) Deprecate "add" (see above) and make it interactive. 1) Deprecate "add" (see above) and make it interactive.
@ -86,6 +99,17 @@ loop = asyncio.get_event_loop()
# task_ping = asyncio.create_task(ping(self, jid=None)) # task_ping = asyncio.create_task(ping(self, jid=None))
class Task:
def start(self, jid_full, tasks=None):
asyncio.create_task()
def cancel(self, jid_full, tasks=None):
pass
def task_ping(self): def task_ping(self):
# global task_ping_instance # global task_ping_instance
try: try:
@ -109,7 +133,49 @@ await taskhandler.start_tasks(
) )
""" """
async def start_tasks_xmpp(self, jid_bare, tasks=None): async def start_tasks_xmpp_pubsub(self, jid_bare, tasks=None):
try:
self.task_manager[jid_bare]
except KeyError as e:
self.task_manager[jid_bare] = {}
logging.debug('KeyError:', str(e))
logging.info('Creating new task manager for JID {}'.format(jid_bare))
if not tasks:
tasks = ['check', 'publish']
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid_bare))
for task in tasks:
# if self.task_manager[jid][task]:
try:
self.task_manager[jid_bare][task].cancel()
except:
logging.info('No task {} for JID {} (start_tasks_xmpp_chat)'
.format(task, jid_bare))
logging.info('Starting tasks {} for JID {}'.format(tasks, jid_bare))
for task in tasks:
# print("task:", task)
# print("tasks:")
# print(tasks)
# breakpoint()
match task:
case 'publish':
self.task_manager[jid_bare]['publish'] = asyncio.create_task(
task_publish(self, jid_bare))
case 'check':
self.task_manager[jid_bare]['check'] = asyncio.create_task(
check_updates(self, jid_bare))
async def task_publish(self, jid_bare):
jid_file = jid_bare.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
if jid_bare not in self.settings:
Config.add_settings_jid(self.settings, jid_bare, db_file)
while True:
await action.xmpp_send_pubsub(self, jid_bare)
await asyncio.sleep(60 * 180)
async def start_tasks_xmpp_chat(self, jid_bare, tasks=None):
""" """
NOTE NOTE
@ -133,7 +199,7 @@ async def start_tasks_xmpp(self, jid_bare, tasks=None):
try: try:
self.task_manager[jid_bare][task].cancel() self.task_manager[jid_bare][task].cancel()
except: except:
logging.info('No task {} for JID {} (start_tasks_xmpp)' logging.info('No task {} for JID {} (start_tasks_xmpp_chat)'
.format(task, jid_bare)) .format(task, jid_bare))
logging.info('Starting tasks {} for JID {}'.format(tasks, jid_bare)) logging.info('Starting tasks {} for JID {}'.format(tasks, jid_bare))
for task in tasks: for task in tasks:
@ -147,10 +213,10 @@ async def start_tasks_xmpp(self, jid_bare, tasks=None):
check_updates(self, jid_bare)) check_updates(self, jid_bare))
case 'status': case 'status':
self.task_manager[jid_bare]['status'] = asyncio.create_task( self.task_manager[jid_bare]['status'] = asyncio.create_task(
task_status(self, jid_bare)) task_status_message(self, jid_bare))
case 'interval': case 'interval':
self.task_manager[jid_bare]['interval'] = asyncio.create_task( self.task_manager[jid_bare]['interval'] = asyncio.create_task(
task_send(self, jid_bare)) task_message(self, jid_bare))
# for task in self.task_manager[jid].values(): # for task in self.task_manager[jid].values():
# print("task_manager[jid].values()") # print("task_manager[jid].values()")
# print(self.task_manager[jid].values()) # print(self.task_manager[jid].values())
@ -162,12 +228,12 @@ async def start_tasks_xmpp(self, jid_bare, tasks=None):
# await task # await task
async def task_status(self, jid): async def task_status_message(self, jid):
await action.xmpp_send_status(self, jid) await action.xmpp_send_status_message(self, jid)
refresh_task(self, jid, task_status, 'status', '90') refresh_task(self, jid, task_status_message, 'status', '90')
async def task_send(self, jid_bare): async def task_message(self, jid_bare):
jid_file = jid_bare.replace('/', '_') jid_file = jid_bare.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if jid_bare not in self.settings: if jid_bare not in self.settings:
@ -195,12 +261,12 @@ async def task_send(self, jid_bare):
await sqlite.update_last_update_time(db_file) await sqlite.update_last_update_time(db_file)
else: else:
await sqlite.set_last_update_time(db_file) await sqlite.set_last_update_time(db_file)
await action.xmpp_send_update(self, jid_bare) await action.xmpp_send_message(self, jid_bare)
refresh_task(self, jid_bare, task_send, 'interval') refresh_task(self, jid_bare, task_message, 'interval')
await start_tasks_xmpp(self, jid_bare, ['status']) await start_tasks_xmpp_chat(self, jid_bare, ['status'])
def clean_tasks_xmpp(self, jid, tasks=None): def clean_tasks_xmpp_chat(self, jid, tasks=None):
if not tasks: if not tasks:
tasks = ['interval', 'status', 'check'] tasks = ['interval', 'status', 'check']
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid)) logging.info('Stopping tasks {} for JID {}'.format(tasks, jid))

View file

@ -45,7 +45,9 @@ from urllib.parse import (
def get_hostname(url): def get_hostname(url):
parted_url = urlsplit(url) parted_url = urlsplit(url)
return parted_url.netloc hostname = parted_url.netloc
if hostname.startswith('www.'): hostname = hostname.replace('www.', '')
return hostname
def replace_hostname(url, url_type): def replace_hostname(url, url_type):

View file

@ -1,2 +1,2 @@
__version__ = '0.1.47' __version__ = '0.1.48'
__version_info__ = (0, 1, 47) __version_info__ = (0, 1, 48)

File diff suppressed because it is too large Load diff

View file

@ -2189,14 +2189,14 @@ class XmppCommand:
status_type=status_type) status_type=status_type)
await asyncio.sleep(5) await asyncio.sleep(5)
key_list = ['check', 'status', 'interval'] key_list = ['check', 'status', 'interval']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
if (key == 'enabled' and if (key == 'enabled' and
val == 0 and val == 0 and
str(is_enabled) == 1): str(is_enabled) == 1):
logger.info('Slixfeed has been disabled for {}'.format(jid_bare)) logger.info('Slixfeed has been disabled for {}'.format(jid_bare))
key_list = ['interval', 'status'] key_list = ['interval', 'status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'xa' status_type = 'xa'
status_message = '📪️ Send "Start" to receive updates' status_message = '📪️ Send "Start" to receive updates'
XmppPresence.send(self, jid_bare, status_message, XmppPresence.send(self, jid_bare, status_message,
@ -2212,10 +2212,10 @@ class XmppCommand:
# XmppPresence.send(self, jid, status_message, # XmppPresence.send(self, jid, status_message,
# status_type=status_type) # status_type=status_type)
# await asyncio.sleep(5) # await asyncio.sleep(5)
# await task.start_tasks_xmpp(self, jid, ['check', 'status', # await task.start_tasks_xmpp_chat(self, jid, ['check', 'status',
# 'interval']) # 'interval'])
# else: # else:
# task.clean_tasks_xmpp(self, jid, ['interval', 'status']) # task.clean_tasks_xmpp_chat(self, jid, ['interval', 'status'])
# status_type = 'xa' # status_type = 'xa'
# status_message = '📪️ Send "Start" to receive Jabber updates' # status_message = '📪️ Send "Start" to receive Jabber updates'
# XmppPresence.send(self, jid, status_message, # XmppPresence.send(self, jid, status_message,

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,8 @@ class XmppGroupchat:
self.join(self, inviter, jid) self.join(self, inviter, jid)
def autojoin(self, bookmarks): async def autojoin(self, bookmarks):
jid_from = str(self.boundjid) if self.is_component else None
conferences = bookmarks["private"]["bookmarks"]["conferences"] conferences = bookmarks["private"]["bookmarks"]["conferences"]
for conference in conferences: for conference in conferences:
if conference["jid"] and conference["autojoin"]: if conference["jid"] and conference["autojoin"]:
@ -42,13 +43,10 @@ class XmppGroupchat:
conference["nick"] = self.alias conference["nick"] = self.alias
logging.error('Alias (i.e. Nicknname) is missing for ' logging.error('Alias (i.e. Nicknname) is missing for '
'bookmark {}'.format(conference['name'])) 'bookmark {}'.format(conference['name']))
# jid_from = str(self.boundjid) if self.is_component else None await self.plugin['xep_0045'].join_muc_wait(conference["jid"],
self.plugin['xep_0045'].join_muc(conference["jid"],
conference["nick"], conference["nick"],
# pfrom=jid_from, presence_options = {"pfrom" : jid_from},
# If a room password is needed, use: password=None)
# password=the_room_password,
)
logging.info('Autojoin groupchat\n' logging.info('Autojoin groupchat\n'
'Name : {}\n' 'Name : {}\n'
'JID : {}\n' 'JID : {}\n'
@ -61,7 +59,7 @@ class XmppGroupchat:
.format(conference['name'])) .format(conference['name']))
def join(self, inviter, jid): async def join(self, inviter, jid):
# token = await initdb( # token = await initdb(
# muc_jid, # muc_jid,
# sqlite.get_setting_value, # sqlite.get_setting_value,
@ -86,15 +84,14 @@ class XmppGroupchat:
'Inviter : {}\n' 'Inviter : {}\n'
.format(jid, inviter)) .format(jid, inviter))
jid_from = str(self.boundjid) if self.is_component else None jid_from = str(self.boundjid) if self.is_component else None
self.plugin['xep_0045'].join_muc(jid, await self.plugin['xep_0045'].join_muc_wait(jid,
self.alias, self.alias,
pfrom=jid_from presence_options = {"pfrom" : jid_from},
# If a room password is needed, use: password=None)
# password=the_room_password,
)
def leave(self, jid): def leave(self, jid):
jid_from = str(self.boundjid) if self.is_component else None
message = ('This news bot will now leave this groupchat.\n' message = ('This news bot will now leave this groupchat.\n'
'The JID of this news bot is xmpp:{}?message' 'The JID of this news bot is xmpp:{}?message'
.format(self.boundjid.bare)) .format(self.boundjid.bare))
@ -108,4 +105,4 @@ class XmppGroupchat:
self.plugin['xep_0045'].leave_muc(jid, self.plugin['xep_0045'].leave_muc(jid,
self.alias, self.alias,
status_message, status_message,
self.boundjid) jid_from)

View file

@ -102,7 +102,7 @@ async def message(self, message):
message_text.lower().endswith('.opml')): message_text.lower().endswith('.opml')):
url = message_text url = message_text
key_list = ['status'] key_list = ['status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'dnd' status_type = 'dnd'
status_message = '📥️ Procesing request to import feeds...' status_message = '📥️ Procesing request to import feeds...'
# pending_tasks_num = len(self.pending_tasks[jid_bare]) # pending_tasks_num = len(self.pending_tasks[jid_bare])
@ -122,7 +122,7 @@ async def message(self, message):
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
return return
@ -321,11 +321,20 @@ async def message(self, message):
title = ' '.join(message_text.split(' ')[1:]) title = ' '.join(message_text.split(' ')[1:])
if not title: if not title:
title = uri.get_hostname(url) title = uri.get_hostname(url)
counter = 0
hostname = uri.get_hostname(url)
node = hostname + ':' + str(counter)
while True:
if sqlite.check_node_exist(db_file, node):
counter += 1
node = hostname + ':' + str(counter)
else:
break
if url.startswith('http'): if url.startswith('http'):
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
exist = sqlite.get_feed_id_and_name(db_file, url) exist = sqlite.get_feed_id_and_name(db_file, url)
if not exist: if not exist:
await sqlite.insert_feed(db_file, url, title) await sqlite.insert_feed(db_file, url, title, node)
await action.scan(self, jid_bare, db_file, url) await action.scan(self, jid_bare, db_file, url)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self.settings, jid_bare, Config.add_settings_jid(self.settings, jid_bare,
@ -333,10 +342,10 @@ async def message(self, message):
old = Config.get_setting_value(self.settings, jid_bare, old = Config.get_setting_value(self.settings, jid_bare,
'old') 'old')
if old: if old:
# task.clean_tasks_xmpp(self, jid_bare, ['status']) # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
# await send_status(jid) # await send_status(jid)
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
else: else:
feed_id = sqlite.get_feed_id(db_file, url) feed_id = sqlite.get_feed_id(db_file, url)
feed_id = feed_id[0] feed_id = feed_id[0]
@ -541,7 +550,7 @@ async def message(self, message):
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
else: else:
response = ('Unsupported filetype.\n' response = ('Unsupported filetype.\n'
'Try: md or opml') 'Try: md or opml')
@ -645,7 +654,7 @@ async def message(self, message):
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
if response: if response:
logging.warning('Error for URL {}: {}'.format(url, error)) logging.warning('Error for URL {}: {}'.format(url, error))
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
@ -653,7 +662,7 @@ async def message(self, message):
message_lowercase.endswith('.opml')): message_lowercase.endswith('.opml')):
url = message_text url = message_text
key_list = ['status'] key_list = ['status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'dnd' status_type = 'dnd'
status_message = '📥️ Procesing request to import feeds...' status_message = '📥️ Procesing request to import feeds...'
# pending_tasks_num = len(self.pending_tasks[jid_bare]) # pending_tasks_num = len(self.pending_tasks[jid_bare])
@ -674,12 +683,109 @@ async def message(self, message):
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
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('send '):
if is_operator(self, jid_bare):
info = message_text[5:].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:
node = info[2]
else:
counter = 0
hostname = uri.get_hostname(url)
node = hostname + ':' + str(counter)
while True:
if sqlite.check_node_exist(db_file, node):
counter += 1
node = 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:'):
url = uri.feed_to_http(url)
url = (uri.replace_hostname(url, 'feed')) or url
result = await action.add_feed(self, jid_bare, db_file, url, node)
if isinstance(result, list):
results = result
response = ("Web 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['node']:
response = ('> {}\nNode "{}" is already '
'allocated to index {}'
.format(result['link'],
result['node'],
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 Must not include "/".')
else:
response = ('No action has been taken.'
'\n'
'Missing argument. '
'Enter PubSub JID and subscription URL '
'(and optionally: NodeName).')
else:
response = ('This action is restricted. '
'Type: adding node.')
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
case _ if (message_lowercase.startswith('http') or case _ if (message_lowercase.startswith('http') or
message_lowercase.startswith('feed:')): message_lowercase.startswith('feed:')):
url = message_text url = message_text
# task.clean_tasks_xmpp(self, jid_bare, ['status']) # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
status_type = 'dnd' status_type = 'dnd'
status_message = ('📫️ Processing request to fetch data from {}' status_message = ('📫️ Processing request to fetch data from {}'
.format(url)) .format(url))
@ -694,8 +800,17 @@ async def message(self, message):
url = uri.feed_to_http(url) url = uri.feed_to_http(url)
url = (uri.replace_hostname(url, 'feed')) or url url = (uri.replace_hostname(url, 'feed')) or url
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
counter = 0
hostname = uri.get_hostname(url)
node = hostname + ':' + str(counter)
while True:
if sqlite.check_node_exist(db_file, node):
counter += 1
node = hostname + ':' + str(counter)
else:
break
# try: # try:
result = await action.add_feed(self, jid_bare, db_file, url) result = await action.add_feed(self, jid_bare, db_file, url, node)
if isinstance(result, list): if isinstance(result, list):
results = result results = result
response = ("Web feeds found for {}\n\n```\n" response = ("Web feeds found for {}\n\n```\n"
@ -722,12 +837,12 @@ async def message(self, message):
response = ('> {}\nNews source "{}" has been ' response = ('> {}\nNews source "{}" has been '
'added to subscription list.' 'added to subscription list.'
.format(result['link'], result['name'])) .format(result['link'], result['name']))
# task.clean_tasks_xmpp(self, jid_bare, ['status']) # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
print(self.pending_tasks) print(self.pending_tasks)
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
# except: # except:
# response = ( # response = (
# '> {}\nNews source is in the process ' # '> {}\nNews source is in the process '
@ -768,8 +883,8 @@ async def message(self, message):
self.settings, jid_bare, db_file, key, val_new) self.settings, jid_bare, db_file, key, val_new)
# NOTE Perhaps this should be replaced by functions # NOTE Perhaps this should be replaced by functions
# clean and start # clean and start
task.refresh_task(self, jid_bare, task.task_send, key, task.refresh_task(self, jid_bare,
val_new) task.task_message, key, val_new)
response = ('Updates will be sent every {} minutes ' response = ('Updates will be sent every {} minutes '
'(was: {}).'.format(val_new, val_old)) '(was: {}).'.format(val_new, val_old))
except: except:
@ -870,11 +985,11 @@ async def message(self, message):
case _ if message_lowercase.startswith('next'): case _ if message_lowercase.startswith('next'):
num = message_text[5:] num = message_text[5:]
if num: if num:
await action.xmpp_send_update(self, jid_bare, num) await action.xmpp_send_message(self, jid_bare, num)
else: else:
await action.xmpp_send_update(self, jid_bare) await action.xmpp_send_message(self, jid_bare)
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
case 'old': case 'old':
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
key = 'old' key = 'old'
@ -932,7 +1047,7 @@ async def message(self, message):
url = data[0] url = data[0]
if url: if url:
key_list = ['status'] key_list = ['status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'dnd' status_type = 'dnd'
status_message = ('📫️ Processing request to fetch data ' status_message = ('📫️ Processing request to fetch data '
'from {}'.format(url)) 'from {}'.format(url))
@ -1028,7 +1143,7 @@ async def message(self, message):
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
case _ if message_lowercase.startswith('recent '): case _ if message_lowercase.startswith('recent '):
num = message_text[7:] num = message_text[7:]
if num: if num:
@ -1087,20 +1202,20 @@ async def message(self, message):
'News source does not exist. ' 'News source does not exist. '
.format(url)) .format(url))
# refresh_task(self, jid_bare, send_status, 'status', 20) # refresh_task(self, jid_bare, send_status, 'status', 20)
# task.clean_tasks_xmpp(self, jid_bare, ['status']) # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
else: else:
response = ('No action has been taken.' response = ('No action has been taken.'
'\n' '\n'
'Missing argument. ' 'Missing argument. '
'Enter feed URL or index number.') 'Enter subscription URL or index number.')
case _ if message_lowercase.startswith('reset'): case _ if message_lowercase.startswith('reset'):
# TODO Reset also by ID # TODO Reset also by ID
ix_url = message_text[6:] ix_url = message_text[6:]
key_list = ['status'] key_list = ['status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'dnd' status_type = 'dnd'
status_message = '📫️ Marking entries as read...' status_message = '📫️ Marking entries as read...'
# pending_tasks_num = len(self.pending_tasks[jid_bare]) # pending_tasks_num = len(self.pending_tasks[jid_bare])
@ -1152,7 +1267,7 @@ async def message(self, message):
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
case _ if message_lowercase.startswith('search '): case _ if message_lowercase.startswith('search '):
query = message_text[7:] query = message_text[7:]
if query: if query:
@ -1179,7 +1294,7 @@ async def message(self, message):
status_type=status_type) status_type=status_type)
await asyncio.sleep(5) await asyncio.sleep(5)
key_list = ['check', 'status', 'interval'] key_list = ['check', 'status', 'interval']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
response = 'Updates are enabled.' response = 'Updates are enabled.'
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
case 'stats': case 'stats':
@ -1204,7 +1319,7 @@ async def message(self, message):
.format(feed_id)) .format(feed_id))
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
key_list = ['status'] key_list = ['status']
await task.start_tasks_xmpp(self, jid_bare, key_list) await task.start_tasks_xmpp_chat(self, jid_bare, key_list)
case _ if message_lowercase.startswith('rename '): case _ if message_lowercase.startswith('rename '):
message_text = message_text[7:] message_text = message_text[7:]
feed_id = message_text.split(' ')[0] feed_id = message_text.split(' ')[0]
@ -1264,7 +1379,7 @@ async def message(self, message):
await Config.set_setting_value( await Config.set_setting_value(
self.settings, jid_bare, db_file, key, val) self.settings, jid_bare, db_file, key, val)
key_list = ['interval', 'status'] key_list = ['interval', 'status']
task.clean_tasks_xmpp(self, jid_bare, key_list) task.clean_tasks_xmpp_chat(self, jid_bare, key_list)
status_type = 'xa' status_type = 'xa'
status_message = '📪️ Send "Start" to receive Jabber updates' status_message = '📪️ Send "Start" to receive Jabber updates'
XmppPresence.send(self, jid_bare, status_message, XmppPresence.send(self, jid_bare, status_message,

View file

@ -1,7 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# TODO Implement XEP-0472: Pubsub Social Feed """
Functions create_node and create_entry are derived from project atomtopubsub.
"""
import hashlib import hashlib
import slixmpp.plugins.xep_0060.stanza.pubsub as pubsub import slixmpp.plugins.xep_0060.stanza.pubsub as pubsub
@ -10,7 +14,21 @@ from slixmpp.xmlstream import ET
class XmppPubsub: class XmppPubsub:
# TODO Make use of var "xep" with match/case async def get_pubsub_services(self):
jids = [self.boundjid.bare]
iq = await self['xep_0030'].get_items(jid=self.boundjid.domain)
items = iq['disco_items']['items']
for item in items:
iq = await self['xep_0030'].get_info(jid=item[0])
identities = iq['disco_info']['identities']
for identity in identities:
if identity[0] == 'pubsub' and identity[1] == 'service':
jid = item[0]
jids.extend([jid])
return jids
# TODO Make use of var "xep" with match/case (XEP-0060, XEP-0277, XEP-0472)
def create_node(self, jid, node, xep ,title, summary=None): def create_node(self, jid, node, xep ,title, summary=None):
jid_from = str(self.boundjid) if self.is_component else None jid_from = str(self.boundjid) if self.is_component else None
iq = self.Iq(stype='set', iq = self.Iq(stype='set',
@ -61,7 +79,7 @@ class XmppPubsub:
# It provides nicer urls. # It provides nicer urls.
# Respond to atomtopubsub: # Respond to atomtopubsub:
# I think it would be a good idea to use md5 checksum of Url as Id for # I think it would be beneficial to use md5 checksum of Url as Id for
# cross reference, and namely - in another project to utilize PubSub as # cross reference, and namely - in another project to utilize PubSub as
# links sharing system (see del.icio.us) - to share node entries. # links sharing system (see del.icio.us) - to share node entries.
@ -76,10 +94,10 @@ class XmppPubsub:
node_entry.set('xmlns', 'http://www.w3.org/2005/Atom') node_entry.set('xmlns', 'http://www.w3.org/2005/Atom')
title = ET.SubElement(node_entry, "title") title = ET.SubElement(node_entry, "title")
title.text = entry.title title.text = entry['title']
updated = ET.SubElement(node_entry, "updated") updated = ET.SubElement(node_entry, "updated")
updated.text = entry.updated updated.text = entry['updated']
# Content # Content
if version == 'atom3': if version == 'atom3':