Fix settings update.

Add option to restore default settings.
Reorganize code.
Thank you mirux.
This commit is contained in:
Schimon Jehudah 2024-02-11 21:31:31 +00:00
parent 065311d0d8
commit f6bc76fdf8
13 changed files with 328 additions and 284 deletions

View file

@ -111,7 +111,7 @@ class JabberComponent:
xmpp.register_plugin('xep_0066') # Out of Band Data xmpp.register_plugin('xep_0066') # Out of Band Data
xmpp.register_plugin('xep_0071') # XHTML-IM xmpp.register_plugin('xep_0071') # XHTML-IM
xmpp.register_plugin('xep_0084') # User Avatar xmpp.register_plugin('xep_0084') # User Avatar
# xmpp.register_plugin('xep_0085') # Chat State Notifications xmpp.register_plugin('xep_0085') # Chat State Notifications
xmpp.register_plugin('xep_0115') # Entity Capabilities xmpp.register_plugin('xep_0115') # Entity Capabilities
xmpp.register_plugin('xep_0153') # vCard-Based Avatars xmpp.register_plugin('xep_0153') # vCard-Based Avatars
xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping
@ -137,7 +137,7 @@ class JabberClient:
xmpp.register_plugin('xep_0066') # Out of Band Data xmpp.register_plugin('xep_0066') # Out of Band Data
xmpp.register_plugin('xep_0071') # XHTML-IM xmpp.register_plugin('xep_0071') # XHTML-IM
xmpp.register_plugin('xep_0084') # User Avatar xmpp.register_plugin('xep_0084') # User Avatar
# xmpp.register_plugin('xep_0085') # Chat State Notifications xmpp.register_plugin('xep_0085') # Chat State Notifications
xmpp.register_plugin('xep_0115') # Entity Capabilities xmpp.register_plugin('xep_0115') # Entity Capabilities
xmpp.register_plugin('xep_0153') # vCard-Based Avatars xmpp.register_plugin('xep_0153') # vCard-Based Avatars
xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping xmpp.register_plugin('xep_0199', {'keepalive': True}) # XMPP Ping

View file

@ -87,6 +87,163 @@ except ImportError:
"Arc90 Lab algorithm is disabled.") "Arc90 Lab algorithm is disabled.")
async def xmpp_send_status(self, jid):
"""
Send status message.
Parameters
----------
jid : str
Jabber ID.
"""
logging.info('Sending a status message to JID {}'.format(jid))
status_text = '📜️ Slixfeed RSS News Bot'
jid_file = jid.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
enabled = await config.get_setting_value(db_file, 'enabled')
if not enabled:
status_mode = 'xa'
status_text = '📪️ Send "Start" to receive updates'
else:
feeds = await sqlite.get_number_of_items(db_file, 'feeds')
# print(await current_time(), jid, "has", feeds, "feeds")
if not feeds:
status_mode = 'available'
status_text = '📪️ Send a URL from a blog or a news website'
else:
unread = await sqlite.get_number_of_entries_unread(db_file)
if unread:
status_mode = 'chat'
status_text = '📬️ There are {} news items'.format(str(unread))
# status_text = (
# "📰 News items: {}"
# ).format(str(unread))
# status_text = (
# "📰 You have {} news items"
# ).format(str(unread))
else:
status_mode = 'available'
status_text = '📭️ No news'
# breakpoint()
# print(await current_time(), status_text, "for", jid)
XmppPresence.send(self, jid, status_text, status_type=status_mode)
# await asyncio.sleep(60 * 20)
# await refresh_task(self, jid, send_status, 'status', '90')
# loop.call_at(
# loop.time() + 60 * 20,
# loop.create_task,
# send_status(jid)
# )
async def xmpp_send_update(self, jid, num=None):
"""
Send news items as messages.
Parameters
----------
jid : str
Jabber ID.
num : str, optional
Number. The default is None.
"""
jid_file = jid.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
enabled = await config.get_setting_value(db_file, 'enabled')
if enabled:
show_media = await config.get_setting_value(db_file, 'media')
if not num:
num = await config.get_setting_value(db_file, 'quantum')
else:
num = int(num)
results = await sqlite.get_unread_entries(db_file, num)
news_digest = ''
media = None
chat_type = await get_chat_type(self, jid)
for result in results:
ix = result[0]
title_e = result[1]
url = result[2]
enclosure = result[3]
feed_id = result[4]
date = result[5]
title_f = sqlite.get_feed_title(db_file, feed_id)
title_f = title_f[0]
news_digest += list_unread_entries(result, title_f)
# print(db_file)
# print(result[0])
# breakpoint()
await sqlite.mark_as_read(db_file, ix)
# Find media
# if url.startswith("magnet:"):
# media = action.get_magnet(url)
# elif enclosure.startswith("magnet:"):
# media = action.get_magnet(enclosure)
# elif enclosure:
if show_media:
if enclosure:
media = enclosure
else:
media = await extract_image_from_html(url)
if media and news_digest:
# Send textual message
XmppMessage.send(self, jid, news_digest, chat_type)
news_digest = ''
# Send media
XmppMessage.send_oob(self, jid, media, chat_type)
media = None
if news_digest:
XmppMessage.send(self, jid, news_digest, chat_type)
# TODO Add while loop to assure delivery.
# print(await current_time(), ">>> ACT send_message",jid)
# NOTE Do we need "if statement"? See NOTE at is_muc.
# if chat_type in ('chat', 'groupchat'):
# # TODO Provide a choice (with or without images)
# XmppMessage.send(self, jid, news_digest, chat_type)
# See XEP-0367
# if media:
# # message = xmpp.Slixfeed.make_message(
# # self, mto=jid, mbody=new, mtype=chat_type)
# message = xmpp.Slixfeed.make_message(
# self, mto=jid, mbody=media, mtype=chat_type)
# message['oob']['url'] = media
# message.send()
# TODO Do not refresh task before
# verifying that it was completed.
# await start_tasks_xmpp(self, jid, ['status'])
# await refresh_task(self, jid, send_update, 'interval')
# interval = await initdb(
# jid,
# sqlite.get_settings_value,
# "interval"
# )
# self.task_manager[jid]["interval"] = loop.call_at(
# loop.time() + 60 * interval,
# loop.create_task,
# send_update(jid)
# )
# print(await current_time(), "asyncio.get_event_loop().time()")
# print(await current_time(), asyncio.get_event_loop().time())
# await asyncio.sleep(60 * interval)
# loop.call_later(
# 60 * interval,
# loop.create_task,
# send_update(jid)
# )
# print
# await handle_event()
def manual(filename, section=None, command=None): def manual(filename, section=None, command=None):
config_dir = config.get_default_config_directory() config_dir = config.get_default_config_directory()
with open(config_dir + '/' + filename, mode="rb") as commands: with open(config_dir + '/' + filename, mode="rb") as commands:
@ -119,7 +276,7 @@ async def xmpp_change_interval(self, key, val, jid, jid_file, message=None,
# 'Updates will be sent every {} minutes.' # 'Updates will be sent every {} minutes.'
# ).format(response) # ).format(response)
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -140,7 +297,7 @@ async def xmpp_start_updates(self, message, jid, jid_file):
key = 'enabled' key = 'enabled'
val = 1 val = 1
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -157,7 +314,7 @@ async def xmpp_stop_updates(self, message, jid, jid_file):
key = 'enabled' key = 'enabled'
val = 0 val = 0
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -399,27 +556,23 @@ async def list_statistics(db_file):
# value = "Default" # value = "Default"
# values.extend([value]) # values.extend([value])
message = ( message = ("```"
"```" "\nSTATISTICS\n"
"\nSTATISTICS\n" "News items : {}/{}\n"
"News items : {}/{}\n" "News sources : {}/{}\n"
"News sources : {}/{}\n" "\nOPTIONS\n"
"\nOPTIONS\n" "Items to archive : {}\n"
"Items to archive : {}\n" "Update interval : {}\n"
"Update interval : {}\n" "Items per update : {}\n"
"Items per update : {}\n" "Operation status : {}\n"
"Operation status : {}\n" "```").format(entries_unread,
"```" entries_all,
).format( feeds_active,
entries_unread, feeds_all,
entries_all, key_archive,
feeds_active, key_interval,
feeds_all, key_quantum,
key_archive, key_enabled)
key_interval,
key_quantum,
key_enabled
)
return message return message
@ -427,10 +580,8 @@ async def list_statistics(db_file):
def list_last_entries(results, num): def list_last_entries(results, num):
message = "Recent {} titles:\n\n```".format(num) message = "Recent {} titles:\n\n```".format(num)
for result in results: for result in results:
message += ( message += ("\n{}\n{}\n"
"\n{}\n{}\n" .format(str(result[0]), str(result[1])))
).format(
str(result[0]), str(result[1]))
if len(results): if len(results):
message += "```\n" message += "```\n"
else: else:
@ -441,59 +592,45 @@ def list_last_entries(results, num):
def list_feeds(results): def list_feeds(results):
message = "\nList of subscriptions:\n\n```\n" message = "\nList of subscriptions:\n\n```\n"
for result in results: for result in results:
message += ( message += ("Name : {}\n"
"Name : {}\n" "URL : {}\n"
"URL : {}\n" # "Updated : {}\n"
# "Updated : {}\n" # "Status : {}\n"
# "Status : {}\n" "ID : {}\n"
"ID : {}\n" "\n"
"\n" .format(str(result[0]), str(result[1]), str(result[2])))
).format(
str(result[0]), str(result[1]), str(result[2]))
if len(results): if len(results):
message += ( message += ('```\nTotal of {} subscriptions.\n'
"```\nTotal of {} subscriptions.\n" .format(len(results)))
).format(len(results))
else: else:
message = ( message = ('List of subscriptions is empty.\n'
"List of subscriptions is empty.\n" 'To add feed, send a URL\n'
"To add feed, send a URL\n" 'Featured feed: '
"Try these:\n" 'https://reclaimthenet.org/feed/')
# TODO Pick random from featured/recommended
"https://reclaimthenet.org/feed/"
)
return message return message
async def list_bookmarks(self): async def list_bookmarks(self):
conferences = await XmppBookmark.get(self) conferences = await XmppBookmark.get(self)
message = "\nList of groupchats:\n\n```\n" message = '\nList of groupchats:\n\n```\n'
for conference in conferences: for conference in conferences:
message += ( message += ('{}\n'
"{}\n" '\n'
"\n" .format(conference['jid']))
).format( message += ('```\nTotal of {} groupchats.\n'
conference["jid"] .format(len(conferences)))
)
message += (
"```\nTotal of {} groupchats.\n"
).format(len(conferences))
return message return message
def export_to_markdown(jid, filename, results): def export_to_markdown(jid, filename, results):
with open(filename, 'w') as file: with open(filename, 'w') as file:
file.write( file.write('# Subscriptions for {}\n'.format(jid))
'# Subscriptions for {}\n'.format(jid)) file.write('## Set of feeds exported with Slixfeed\n')
file.write(
'## Set of feeds exported with Slixfeed\n')
for result in results: for result in results:
file.write( file.write('- [{}]({})\n'.format(result[0], result[1]))
'- [{}]({})\n'.format(result[0], result[1])) file.write('\n\n* * *\n\nThis list was saved on {} from xmpp:{} using '
file.write( '[Slixfeed](https://gitgud.io/sjehuda/slixfeed)\n'
'\n\n* * *\n\nThis list was saved on {} from xmpp:{} using ' .format(dt.current_date(), jid))
'[Slixfeed](https://gitgud.io/sjehuda/slixfeed)\n'.format(
dt.current_date(), jid))
# TODO Consider adding element jid as a pointer of import # TODO Consider adding element jid as a pointer of import

View file

@ -162,9 +162,9 @@ archive = """
archive <number> archive <number>
Number of news items to archive (maximum value 500). Number of news items to archive (maximum value 500).
""" """
remove = """ default = """
remove <id> default
Remove feed of from subscription list by given <id>. Restore default settings.
""" """
disable = """ disable = """
disable <id> disable <id>
@ -174,6 +174,10 @@ enable = """
enable <id> enable <id>
Enable updates for feed of given <id>. Enable updates for feed of given <id>.
""" """
remove = """
remove <id>
Remove feed of from subscription list by given <id>.
"""
reset = """ reset = """
reset reset
Mark all entries as read and remove all archived entries Mark all entries as read and remove all archived entries

View file

@ -1,13 +1,11 @@
about = """ about = """
Slixfeed Slixfeed
A Syndication bot for the XMPP communication network. A Syndication bot for the XMPP communication network.
Slixfeed is a news broker which aims to be an easy to use and fully-\ Slixfeed is a news broker which aims to be an easy to use and fully-\
featured news aggregator bot. It provides a convenient access to \ featured news aggregator bot. It provides a convenient access to \
Blogs, News websites and even Fediverse instances, along with \ Blogs, News websites and even Fediverse instances, along with \
filtering functionality. filtering functionality.
Slixfeed is primarily designed for XMPP (aka Jabber). \ Slixfeed is primarily designed for XMPP (aka Jabber). \
Visit https://xmpp.org/software/ for more information. Visit https://xmpp.org/software/ for more information.
""" """
@ -133,8 +131,9 @@ Simone "roughnecks" Canaletti <woodpeckersnest.space> (Italy), \
Richard Lapointe (SalixOS, Connecticut), \ Richard Lapointe (SalixOS, Connecticut), \
Strix from Loqi, \ Strix from Loqi, \
Thibaud Guerin (SalixOS), \ Thibaud Guerin (SalixOS), \
Tim Beech (SalixOS, Brazil), \ Thorsten Fröhlich (France), \
Thorsten Mühlfelder (SalixOS, Germany), \ Thorsten Mühlfelder (SalixOS, Germany), \
Tim Beech (SalixOS, Brazil), \
Yann Leboulanger (Gajim, France). Yann Leboulanger (Gajim, France).
""" """

View file

@ -36,7 +36,7 @@ import tomllib
async def get_setting_value(db_file, key): async def get_setting_value(db_file, key):
value = ( value = (
await sqlite.get_settings_value(db_file, key) or sqlite.get_settings_value(db_file, key) or
get_value("settings", "Settings", key) get_value("settings", "Settings", key)
) )
value = int(value) value = int(value)

View file

@ -1808,7 +1808,19 @@ async def update_settings_value(db_file, key_value):
# ) # )
async def get_settings_value(db_file, key): async def delete_settings(db_file):
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
DELETE
FROM settings
"""
)
cur.execute(sql)
def get_settings_value(db_file, key):
""" """
Get settings value. Get settings value.

View file

@ -3,16 +3,6 @@
""" """
FIXME
0) URGENT!!! Place "await asyncio.sleep(next_update_time)" ***inside*** the
task, and not outside as it is now!
1) Function check_readiness or event "changed_status" is causing for
triple status messages and also false ones that indicate of lack
of feeds.
TODO TODO
0) Move functions send_status and send_update to module action 0) Move functions send_status and send_update to module action
@ -45,6 +35,29 @@ NOTE
""" """
"""
TIMEOUT
import signal
def handler(signum, frame):
print("Timeout!")
raise Exception("end of time")
# This line will set the alarm for 5 seconds
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)
try:
# Your command here
pass
except Exception as exc:
print(exc)
"""
import asyncio import asyncio
import logging import logging
import os import os
@ -137,7 +150,7 @@ async def start_tasks_xmpp(self, jid, tasks=None):
check_updates(jid)) check_updates(jid))
case 'status': case 'status':
self.task_manager[jid]['status'] = asyncio.create_task( self.task_manager[jid]['status'] = asyncio.create_task(
send_status(self, jid)) task_status(self, jid))
case 'interval': case 'interval':
self.task_manager[jid]['interval'] = asyncio.create_task( self.task_manager[jid]['interval'] = asyncio.create_task(
task_send(self, jid)) task_send(self, jid))
@ -152,6 +165,11 @@ async def start_tasks_xmpp(self, jid, tasks=None):
# await task # await task
async def task_status(self, jid):
await action.xmpp_send_status(self, jid)
await refresh_task(self, jid, task_status, 'status', '90')
async def task_send(self, jid): async def task_send(self, jid):
jid_file = jid.replace('/', '_') jid_file = jid.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
@ -178,118 +196,11 @@ async def task_send(self, jid):
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 xmpp_send_update(self, jid) await action.xmpp_send_update(self, jid)
await refresh_task(self, jid, task_send, 'interval') await refresh_task(self, jid, task_send, 'interval')
await start_tasks_xmpp(self, jid, ['status']) await start_tasks_xmpp(self, jid, ['status'])
async def xmpp_send_update(self, jid, num=None):
"""
Send news items as messages.
Parameters
----------
jid : str
Jabber ID.
num : str, optional
Number. The default is None.
"""
jid_file = jid.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
enabled = await config.get_setting_value(db_file, 'enabled')
if enabled:
show_media = await config.get_setting_value(db_file, 'media')
if not num:
num = await config.get_setting_value(db_file, 'quantum')
else:
num = int(num)
results = await sqlite.get_unread_entries(db_file, num)
news_digest = ''
media = None
chat_type = await get_chat_type(self, jid)
for result in results:
ix = result[0]
title_e = result[1]
url = result[2]
enclosure = result[3]
feed_id = result[4]
date = result[5]
title_f = sqlite.get_feed_title(db_file, feed_id)
title_f = title_f[0]
news_digest += action.list_unread_entries(result, title_f)
# print(db_file)
# print(result[0])
# breakpoint()
await sqlite.mark_as_read(db_file, ix)
# Find media
# if url.startswith("magnet:"):
# media = action.get_magnet(url)
# elif enclosure.startswith("magnet:"):
# media = action.get_magnet(enclosure)
# elif enclosure:
if show_media:
if enclosure:
media = enclosure
else:
media = await action.extract_image_from_html(url)
if media and news_digest:
# Send textual message
XmppMessage.send(self, jid, news_digest, chat_type)
news_digest = ''
# Send media
XmppMessage.send_oob(self, jid, media, chat_type)
media = None
if news_digest:
XmppMessage.send(self, jid, news_digest, chat_type)
# TODO Add while loop to assure delivery.
# print(await current_time(), ">>> ACT send_message",jid)
# NOTE Do we need "if statement"? See NOTE at is_muc.
# if chat_type in ('chat', 'groupchat'):
# # TODO Provide a choice (with or without images)
# XmppMessage.send(self, jid, news_digest, chat_type)
# See XEP-0367
# if media:
# # message = xmpp.Slixfeed.make_message(
# # self, mto=jid, mbody=new, mtype=chat_type)
# message = xmpp.Slixfeed.make_message(
# self, mto=jid, mbody=media, mtype=chat_type)
# message['oob']['url'] = media
# message.send()
# TODO Do not refresh task before
# verifying that it was completed.
# await start_tasks_xmpp(self, jid, ['status'])
# await refresh_task(self, jid, send_update, 'interval')
# interval = await initdb(
# jid,
# sqlite.get_settings_value,
# "interval"
# )
# self.task_manager[jid]["interval"] = loop.call_at(
# loop.time() + 60 * interval,
# loop.create_task,
# send_update(jid)
# )
# print(await current_time(), "asyncio.get_event_loop().time()")
# print(await current_time(), asyncio.get_event_loop().time())
# await asyncio.sleep(60 * interval)
# loop.call_later(
# 60 * interval,
# loop.create_task,
# send_update(jid)
# )
# print
# await handle_event()
def clean_tasks_xmpp(self, jid, tasks=None): def clean_tasks_xmpp(self, jid, tasks=None):
if not tasks: if not tasks:
tasks = ['interval', 'status', 'check'] tasks = ['interval', 'status', 'check']
@ -303,56 +214,6 @@ def clean_tasks_xmpp(self, jid, tasks=None):
.format(task, jid)) .format(task, jid))
async def send_status(self, jid):
"""
Send status message.
Parameters
----------
jid : str
Jabber ID.
"""
logging.info('Sending a status message to JID {}'.format(jid))
status_text = '📜️ Slixfeed RSS News Bot'
jid_file = jid.replace('/', '_')
db_file = config.get_pathname_to_database(jid_file)
enabled = await config.get_setting_value(db_file, 'enabled')
if not enabled:
status_mode = 'xa'
status_text = '📪️ Send "Start" to receive updates'
else:
feeds = await sqlite.get_number_of_items(db_file, 'feeds')
# print(await current_time(), jid, "has", feeds, "feeds")
if not feeds:
status_mode = 'available'
status_text = '📪️ Send a URL from a blog or a news website'
else:
unread = await sqlite.get_number_of_entries_unread(db_file)
if unread:
status_mode = 'chat'
status_text = '📬️ There are {} news items'.format(str(unread))
# status_text = (
# "📰 News items: {}"
# ).format(str(unread))
# status_text = (
# "📰 You have {} news items"
# ).format(str(unread))
else:
status_mode = 'available'
status_text = '📭️ No news'
# breakpoint()
# print(await current_time(), status_text, "for", jid)
XmppPresence.send(self, jid, status_text, status_type=status_mode)
# await asyncio.sleep(60 * 20)
await refresh_task(self, jid, send_status, 'status', '90')
# loop.call_at(
# loop.time() + 60 * 20,
# loop.create_task,
# send_status(jid)
# )
async def refresh_task(self, jid, callback, key, val=None): async def refresh_task(self, jid, callback, key, val=None):
""" """
Apply new setting at runtime. Apply new setting at runtime.

View file

@ -1,2 +1,2 @@
__version__ = '0.1.3' __version__ = '0.1.4'
__version_info__ = (0, 1, 3) __version_info__ = (0, 1, 4)

View file

@ -303,7 +303,7 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = presence['from'].bare jid = presence['from'].bare
if jid in self.boundjid.bare: if jid in self.boundjid.bare:
return return
print('JID available:', jid) logging.info('JID {} is available'.format(jid))
# FIXME TODO Find out what is the source responsible for a couple presences with empty message # FIXME TODO Find out what is the source responsible for a couple presences with empty message
# NOTE This is a temporary solution # NOTE This is a temporary solution
await asyncio.sleep(10) await asyncio.sleep(10)
@ -326,7 +326,7 @@ class Slixfeed(slixmpp.ClientXMPP):
def on_presence_unavailable(self, presence): def on_presence_unavailable(self, presence):
jid = presence['from'].bare jid = presence['from'].bare
print('JID unavailable:', jid) logging.info('JID {} is unavailable'.format(jid))
# await task.stop_tasks(self, jid) # await task.stop_tasks(self, jid)
task.clean_tasks_xmpp(self, jid) task.clean_tasks_xmpp(self, jid)
@ -346,7 +346,7 @@ class Slixfeed(slixmpp.ClientXMPP):
# If bookmarks, remove groupchat JID into file # If bookmarks, remove groupchat JID into file
def on_presence_error(self, presence): def on_presence_error(self, presence):
jid = presence["from"].bare jid = presence["from"].bare
print('JID error:', jid) logging.info('JID {} (error)'.format(jid))
task.clean_tasks_xmpp(self, jid) task.clean_tasks_xmpp(self, jid)
@ -482,7 +482,9 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_subscriptions(self, iq, session): async def _handle_subscriptions(self, iq, session):
form = self['xep_0004'].make_form('form', 'Subscriptions') jid = session['from'].bare
form = self['xep_0004'].make_form('form',
'Subscriptions for {}'.format(jid))
form['instructions'] = '📰️ Manage subscriptions.' form['instructions'] = '📰️ Manage subscriptions.'
# form.addField(var='interval', # form.addField(var='interval',
# ftype='text-single', # ftype='text-single',
@ -491,7 +493,6 @@ class Slixfeed(slixmpp.ClientXMPP):
ftype='list-multi', ftype='list-multi',
label='Select subscriptions', label='Select subscriptions',
desc='Select subscription(s) to edit.') desc='Select subscription(s) to edit.')
jid = session['from'].bare
jid_file = jid jid_file = jid
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
subscriptions = await sqlite.get_feeds(db_file) subscriptions = await sqlite.get_feeds(db_file)
@ -523,7 +524,9 @@ class Slixfeed(slixmpp.ClientXMPP):
# single: Delete, Disable, Reset and Rename # single: Delete, Disable, Reset and Rename
# several: Delete, Disable, Reset # several: Delete, Disable, Reset
async def _handle_subscription_editor(self, iq, session): async def _handle_subscription_editor(self, iq, session):
form = self['xep_0004'].make_form('form', 'Subscriptions') jid = session['from'].bare
form = self['xep_0004'].make_form('form',
'Subscriptions for {}'.format(jid))
form['instructions'] = '🗞️ Edit subscriptions.' form['instructions'] = '🗞️ Edit subscriptions.'
options = form.add_field(var='enable', options = form.add_field(var='enable',
ftype='boolean', ftype='boolean',
@ -542,7 +545,9 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_bookmarks(self, iq, session): async def _handle_bookmarks(self, iq, session):
form = self['xep_0004'].make_form('form', 'Bookmarks') jid = session['from'].bare
form = self['xep_0004'].make_form('form',
'Bookmarks for {}'.format(jid))
form['instructions'] = '📑️ Organize bookmarks.' form['instructions'] = '📑️ Organize bookmarks.'
options = form.add_field(var='bookmarks', options = form.add_field(var='bookmarks',
# ftype='list-multi' # ftype='list-multi'
@ -559,7 +564,9 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_bookmarks_editor(self, iq, session): async def _handle_bookmarks_editor(self, iq, session):
form = self['xep_0004'].make_form('form', 'Bookmarks') jid = session['from'].bare
form = self['xep_0004'].make_form('form',
'Bookmarks for {}'.format(jid))
form['instructions'] = '📝️ Edit bookmarks.' form['instructions'] = '📝️ Edit bookmarks.'
form.addField(var='name', form.addField(var='name',
ftype='text-single', ftype='text-single',
@ -605,11 +612,13 @@ class Slixfeed(slixmpp.ClientXMPP):
session. Additional, custom data may be saved session. Additional, custom data may be saved
here to persist across handler callbacks. here to persist across handler callbacks.
""" """
form = self['xep_0004'].make_form('form', 'Settings')
form['instructions'] = ('📮️ Customize news updates.')
jid = session['from'].bare jid = session['from'].bare
jid_file = jid jid_file = jid
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
form = self['xep_0004'].make_form('form',
'Settings for {}'.format(jid))
form['instructions'] = ('📮️ Customize news updates.')
value = await config.get_setting_value(db_file, 'enabled') value = await config.get_setting_value(db_file, 'enabled')
value = int(value) value = int(value)
if value: if value:
@ -621,6 +630,19 @@ class Slixfeed(slixmpp.ClientXMPP):
label='Enable', label='Enable',
desc='Enable news updates.', desc='Enable news updates.',
value=value) value=value)
value = await config.get_setting_value(db_file, 'media')
value = int(value)
if value:
value = True
else:
value = False
form.add_field(var='media',
ftype='boolean',
desc='Send audio, images or videos if found.',
label='Display media',
value=value)
value = await config.get_setting_value(db_file, 'old') value = await config.get_setting_value(db_file, 'old')
value = int(value) value = int(value)
if value: if value:
@ -629,11 +651,11 @@ class Slixfeed(slixmpp.ClientXMPP):
value = True value = True
form.add_field(var='old', form.add_field(var='old',
ftype='boolean', ftype='boolean',
desc='Do not mark items of newly added subscriptions ' desc='Send old items of newly added subscriptions.',
'as read.',
# label='Send only new items', # label='Send only new items',
label='Include old news', label='Include old news',
value=value) value=value)
value = await config.get_setting_value(db_file, 'interval') value = await config.get_setting_value(db_file, 'interval')
value = str(int(value/60)) value = str(int(value/60))
options = form.add_field(var='interval', options = form.add_field(var='interval',
@ -647,6 +669,7 @@ class Slixfeed(slixmpp.ClientXMPP):
lab = str(int(i/60)) lab = str(int(i/60))
options.addOption(lab, var) options.addOption(lab, var)
i += 60 i += 60
value = await config.get_setting_value(db_file, 'archive') value = await config.get_setting_value(db_file, 'archive')
value = str(value) value = str(value)
options = form.add_field(var='archive', options = form.add_field(var='archive',
@ -658,7 +681,8 @@ class Slixfeed(slixmpp.ClientXMPP):
while i <= 500: while i <= 500:
x = str(i) x = str(i)
options.addOption(x, x) options.addOption(x, x)
i += 1 i += 50
value = await config.get_setting_value(db_file, 'quantum') value = await config.get_setting_value(db_file, 'quantum')
value = str(value) value = str(value)
options = form.add_field(var='quantum', options = form.add_field(var='quantum',
@ -667,10 +691,11 @@ class Slixfeed(slixmpp.ClientXMPP):
desc='Set amount of updates per update.', desc='Set amount of updates per update.',
value='3') value='3')
i = 1 i = 1
while i <= 10: while i <= 5:
x = str(i) x = str(i)
options.addOption(x, x) options.addOption(x, x)
i += 1 i += 1
session['payload'] = form session['payload'] = form
session['next'] = self._handle_settings_complete session['next'] = self._handle_settings_complete
session['has_next'] = False session['has_next'] = False
@ -701,7 +726,7 @@ class Slixfeed(slixmpp.ClientXMPP):
for value in values: for value in values:
key = value key = value
val = values[value] val = values[value]
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])

View file

@ -621,7 +621,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
for value in values: for value in values:
key = value key = value
val = values[value] val = values[value]
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])

View file

@ -44,31 +44,32 @@ class XmppConnect:
rtt = None rtt = None
try: try:
rtt = await self['xep_0199'].ping(jid, timeout=10) rtt = await self['xep_0199'].ping(jid, timeout=10)
logging.info("Success! RTT: %s", rtt) logging.info('Success! RTT: %s', rtt)
except IqError as e: except IqError as e:
logging.info("Error pinging %s: %s", logging.info('Error pinging %s: %s',
jid, jid,
e.iq['error']['condition']) e.iq['error']['condition'])
except IqTimeout: except IqTimeout:
logging.info("No response from %s", jid) logging.info('No response from %s', jid)
if not rtt: if not rtt:
logging.info('Disconnecting...')
self.disconnect() self.disconnect()
await asyncio.sleep(60 * 1) await asyncio.sleep(60 * 1)
async def recover(self, message): async def recover(self, message):
logging.warning(message) logging.warning(message)
print(current_time(), message, "Attempting to reconnect.") print(current_time(), message, 'Attempting to reconnect.')
self.connection_attempts += 1 self.connection_attempts += 1
# if self.connection_attempts <= self.max_connection_attempts: # if self.connection_attempts <= self.max_connection_attempts:
# self.reconnect(wait=5.0) # wait a bit before attempting to reconnect # self.reconnect(wait=5.0) # wait a bit before attempting to reconnect
# else: # else:
# print(current_time(),"Maximum connection attempts exceeded.") # print(current_time(),"Maximum connection attempts exceeded.")
# logging.error("Maximum connection attempts exceeded.") # logging.error("Maximum connection attempts exceeded.")
print(current_time(), "Attempt number", self.connection_attempts) print(current_time(), 'Attempt number', self.connection_attempts)
seconds = (get_value("accounts", "XMPP", "reconnect_timeout")) or 30 seconds = (get_value('accounts', 'XMPP', 'reconnect_timeout')) or 30
seconds = int(seconds) seconds = int(seconds)
print(current_time(), "Next attempt within", seconds, "seconds") print(current_time(), 'Next attempt within', seconds, 'seconds')
# NOTE asyncio.sleep doesn't interval as expected # NOTE asyncio.sleep doesn't interval as expected
# await asyncio.sleep(seconds) # await asyncio.sleep(seconds)
sleep(seconds) sleep(seconds)

View file

@ -363,11 +363,12 @@ async def message(self, message):
response = 'Value may not be greater than 500.' response = 'Value may not be greater than 500.'
else: else:
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, if sqlite.get_settings_value(db_file, key):
[key, val]): print('update archive')
await sqlite.update_settings_value(db_file, await sqlite.update_settings_value(db_file,
[key, val]) [key, val])
else: else:
print('set archive')
await sqlite.set_settings_value(db_file, await sqlite.set_settings_value(db_file,
[key, val]) [key, val])
response = ('Maximum archived items has ' response = ('Maximum archived items has '
@ -389,6 +390,11 @@ async def message(self, message):
response = ('This action is restricted. ' response = ('This action is restricted. '
'Type: removing bookmarks.') 'Type: removing bookmarks.')
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
case 'default':
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 'bookmarks': case 'bookmarks':
if jid == config.get_value('accounts', 'XMPP', 'operator'): if jid == config.get_value('accounts', 'XMPP', 'operator'):
response = await action.list_bookmarks(self) response = await action.list_bookmarks(self)
@ -573,8 +579,7 @@ async def message(self, message):
try: try:
val = int(val) val = int(val)
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, if sqlite.get_settings_value(db_file, key):
[key, val]):
await sqlite.update_settings_value(db_file, await sqlite.update_settings_value(db_file,
[key, val]) [key, val])
else: else:
@ -619,7 +624,7 @@ async def message(self, message):
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
key = 'media' key = 'media'
val = 0 val = 0
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -629,7 +634,7 @@ async def message(self, message):
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
key = 'media' key = 'media'
val = 1 val = 1
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -639,7 +644,7 @@ async def message(self, message):
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
key = 'old' key = 'old'
val = 0 val = 0
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -650,7 +655,7 @@ async def message(self, message):
# num = message_text[5:] # num = message_text[5:]
# await task.send_update(self, jid, num) # await task.send_update(self, jid, num)
await task.xmpp_send_update(self, jid) await action.xmpp_send_update(self, jid)
# task.clean_tasks_xmpp(self, jid, ['interval', 'status']) # task.clean_tasks_xmpp(self, jid, ['interval', 'status'])
# await task.start_tasks_xmpp(self, jid, ['status', 'interval']) # await task.start_tasks_xmpp(self, jid, ['status', 'interval'])
@ -662,7 +667,7 @@ async def message(self, message):
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
key = 'old' key = 'old'
val = 1 val = 1
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, [key, val]) await sqlite.update_settings_value(db_file, [key, val])
else: else:
await sqlite.set_settings_value(db_file, [key, val]) await sqlite.set_settings_value(db_file, [key, val])
@ -678,7 +683,7 @@ async def message(self, message):
# 'Every update will contain {} news items.' # 'Every update will contain {} news items.'
# ).format(response) # ).format(response)
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)
if await sqlite.get_settings_value(db_file, key): if sqlite.get_settings_value(db_file, key):
await sqlite.update_settings_value(db_file, await sqlite.update_settings_value(db_file,
[key, val]) [key, val])
else: else:

View file

@ -12,12 +12,12 @@ async def get_chat_type(self, jid):
Check whether a JID is of MUC. Check whether a JID is of MUC.
If iqresult["disco_info"]["features"] contains XML namespace If iqresult["disco_info"]["features"] contains XML namespace
of 'http://jabber.org/protocol/muc', then it is a "groupchat". of 'http://jabber.org/protocol/muc', then it is a 'groupchat'.
Unless it has forward slash, which would indicate that it is Unless it has forward slash, which would indicate that it is
a chat which is conducted through a groupchat. a chat which is conducted through a groupchat.
Otherwise, determine type "chat". Otherwise, determine type 'chat'.
Parameters Parameters
---------- ----------
@ -27,7 +27,7 @@ async def get_chat_type(self, jid):
Returns Returns
------- -------
chat_type : str chat_type : str
"chat" or "groupchat. 'chat' or 'groupchat'.
""" """
try: try:
iqresult = await self["xep_0030"].get_info(jid=jid) iqresult = await self["xep_0030"].get_info(jid=jid)