Add functionality to set feed name (i.e. command rename).

Improve forms.
This commit is contained in:
Schimon Jehudah 2024-02-19 00:26:10 +00:00
parent 7b98d32d7f
commit 85f1ba18f0
9 changed files with 1023 additions and 666 deletions

View file

@ -705,6 +705,7 @@ async def add_feed(db_file, url):
while True:
exist = await sqlite.get_feed_id_and_name(db_file, url)
if not exist:
status_code = None
result = await fetch.http(url)
if not result['error']:
document = result['content']

View file

@ -174,6 +174,10 @@ enable = """
enable <id>
Enable updates for feed of given <id>.
"""
rename = """
rename <id> <name>
Rename feed of given <id> with new <name>.
"""
remove = """
remove <id>
Remove feed of from subscription list by given <id>.

View file

@ -933,6 +933,36 @@ def get_feed_title(db_file, feed_id):
return title
async def set_feed_title(db_file, feed_id, name):
"""
Set new name for feed.
Parameters
----------
db_file : str
Path to database file.
feed_id : str
Index of feed.
name : str
New name.
"""
async with DBLOCK:
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
UPDATE feeds
SET name = :name
WHERE id = :feed_id
"""
)
par = {
"name": name,
"feed_id": feed_id
}
cur.execute(sql, par)
def get_entry_url(db_file, ix):
with create_connection(db_file) as conn:
cur = conn.cursor()

View file

@ -1,2 +1,2 @@
__version__ = '0.1.11'
__version_info__ = (0, 1, 11)
__version__ = '0.1.12'
__version_info__ = (0, 1, 12)

View file

@ -54,7 +54,9 @@ class XmppBookmark:
'autojoin' : True,
'password' : None,
}
if jid not in groupchats:
# FIXME Ad-hoc bookmark form is stuck
# if jid not in groupchats:
if properties['jid'] not in groupchats:
bookmarks = Bookmarks()
for groupchat in groupchats:
# if groupchat['jid'] == groupchat['name']:

View file

@ -472,6 +472,9 @@ class Slixfeed(slixmpp.ClientXMPP):
self['xep_0050'].add_command(node='promoted',
name='🔮️ Featured',
handler=self._handle_promoted)
self['xep_0050'].add_command(node='discover',
name='🔍️ Discover',
handler=self._handle_promoted)
self['xep_0050'].add_command(node='subscription',
name='🔗️ Add', # 🪶️
handler=self._handle_subscription_add)
@ -491,8 +494,8 @@ class Slixfeed(slixmpp.ClientXMPP):
self['xep_0050'].add_command(node='filters',
name='🛡️ Filters',
handler=self._handle_filters)
self['xep_0050'].add_command(node='schedule',
name='📅 Schedule',
self['xep_0050'].add_command(node='scheduler',
name='📅 Scheduler',
handler=self._handle_schedule)
self['xep_0050'].add_command(node='help',
name='📔️ Manual',
@ -550,8 +553,8 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
form = self['xep_0004'].make_form('form', 'Filter editor')
form['instructions'] = '🛡️ Edit and manage filters' # 🪄
form = self['xep_0004'].make_form('form', 'Filters')
form['instructions'] = 'Editing filters' # 🪄️ 🛡
value = sqlite.get_filter_value(db_file, 'allow')
if value: value = str(value[0])
form.add_field(var='allow',
@ -566,9 +569,10 @@ class Slixfeed(slixmpp.ClientXMPP):
label='Deny list',
value=value,
desc=('Keywords to deny (comma-separated keywords).'))
session['payload'] = form
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_filters_complete
session['has_next'] = True
session['payload'] = form
return session
@ -590,8 +594,8 @@ class Slixfeed(slixmpp.ClientXMPP):
form = payload
jid = session['from'].bare
form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = ('✅️ Filters have been updated')
# form = self['xep_0004'].make_form('result', 'Done')
# form['instructions'] = ('✅️ Filters have been updated')
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
# In this case (as is typical), the payload is a form
@ -608,38 +612,41 @@ class Slixfeed(slixmpp.ClientXMPP):
await sqlite.update_filter_value(db_file, [key, val])
elif val:
await sqlite.set_filter_value(db_file, [key, val])
form.add_field(var=key.capitalize() + ' list',
ftype='text-single',
value=val)
session['payload'] = form
session["has_next"] = False
# form.add_field(var=key.capitalize() + ' list',
# ftype='text-single',
# value=val)
form['title'] = 'Done'
form['instructions'] = 'has been completed!'
# session["has_next"] = False
session['next'] = None
session['payload'] = form
return session
async def _handle_subscription_add(self, iq, session):
jid = session['from'].bare
form = self['xep_0004'].make_form('form', 'Add Subscription')
form['instructions'] = '📰️ Add a new subscription'
options = form.add_field(var='subscription',
# TODO Make it possible to add several subscriptions at once;
# Similarly to BitTorrent trackers list
# ftype='text-multi',
# label='Subscription URLs',
# desc=('Add subscriptions one time per '
# 'subscription.'),
ftype='text-single',
label='Subscription URL',
desc='Enter subscription URL.',
required=True)
form.add_field(var='scan',
ftype='boolean',
label='Scan',
desc='Scan URL for validity.',
value=True)
session['payload'] = form
session['next'] = self._handle_subscription_new
form = self['xep_0004'].make_form('form', 'Subscription')
form['instructions'] = 'Adding subscription'
form.add_field(var='subscription',
# TODO Make it possible to add several subscriptions at once;
# Similarly to BitTorrent trackers list
# ftype='text-multi',
# label='Subscription URLs',
# desc=('Add subscriptions one time per '
# 'subscription.'),
ftype='text-single',
label='URL',
desc='Enter subscription URL.',
required=True)
# form.add_field(var='scan',
# ftype='boolean',
# label='Scan',
# desc='Scan URL for validity (recommended).',
# value=True)
session['allow_prev'] = False
session['has_next'] = True
session['next'] = self._handle_subscription_new
session['prev'] = None
session['payload'] = form
return session
@ -647,23 +654,36 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
# scan = payload['values']['scan']
url = payload['values']['subscription']
result = await action.add_feed(db_file, url)
if isinstance(result, list):
results = result
form = self['xep_0004'].make_form('form', 'Select subscription')
form['instructions'] = ('🔍️ Discovered {} subscriptions for {}'
form = self['xep_0004'].make_form('form', 'Subscriptions')
form['instructions'] = ('Discovered {} subscriptions for {}'
.format(len(results), url))
options = form.add_field(var='subscriptions',
options = form.add_field(var='subscription',
ftype='list-single',
label='Subscriptions',
label='Subscription',
desc=('Select a subscription to add.'),
required=True)
for result in results:
options.addOption(result['name'], result['link'])
session['payload'] = form
session['next'] = self._handle_subscription_editor
# NOTE Disabling "allow_prev" until Cheogram would allow to display
# items of list-single as buttons when button "back" is enabled.
# session['allow_prev'] = True
session['has_next'] = True
session['next'] = self._handle_subscription_new
session['payload'] = form
# session['prev'] = self._handle_subscription_add
elif result['error']:
response = ('Failed to load URL <{}> Reason: {}'
.format(url, result['code']))
session['allow_prev'] = True
session['next'] = None
session['notes'] = [['error', response]]
session['payload'] = None
session['prev'] = self._handle_subscription_add
elif result['exist']:
# response = ('News source "{}" is already listed '
# 'in the subscription list at index '
@ -671,53 +691,70 @@ class Slixfeed(slixmpp.ClientXMPP):
# result['link']))
# session['notes'] = [['warn', response]] # Not supported by Gajim
# session['notes'] = [['info', response]]
form = self['xep_0004'].make_form('form', 'Edit subscription')
form['instructions'] = ('📰️ ' + result['name'])
options = form.add_field(var='subscriptions',
form = self['xep_0004'].make_form('form', 'Subscription')
form['instructions'] = ('Subscription already exists at index {}.'
'\n'
'Would you want to edit this subscription?'
.format(result['index']))
options = form.add_field(var='subscription',
ftype='list-single',
label='Edit sbscription #{}'.format(result['index']),
# desc='Click URL to edit subscription.',
label='Subscription',
desc='Continue to edit subscription.',
value=result['link'])
options.addOption(result['name'], result['link'])
session['payload'] = form
# NOTE Should we allow "Complete"?
# Do all clients provide button "Cancel".
session['allow_complete'] = False
session['has_next'] = True
session['next'] = self._handle_subscription_editor
session['payload'] = form
# session['has_next'] = False
elif result['error']:
response = ('Failed to load URL {}'
'\n\n'
'Reason: {}'
.format(url, result['code']))
session['notes'] = [['error', response]]
session['next'] = None
else:
# response = ('News source "{}" has been '
# 'added to subscription list.\n{}'
# .format(result['name'], result['link']))
# session['notes'] = [['info', response]]
form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = ('✅️ News source "{}" has been added to '
'subscription list as index {}'
form = self['xep_0004'].make_form('form', 'Subscription')
# form['instructions'] = ('✅️ News source "{}" has been added to '
# 'subscription list as index {}'
# '\n\n'
# 'Choose next to continue to subscription '
# 'editor.'
# .format(result['name'], result['index']))
form['instructions'] = ('New subscription'
'\n'
'"{}"'
'\n\n'
'Continue to edit subscription?'
.format(result['name'], result['index']))
options = form.add_field(var='subscriptions',
ftype='text-single',
label=result['link'],
desc='Choose next to edit subscription.',
options = form.add_field(var='subscription',
ftype='list-single',
# Should Gajim allows editing text-single
# field when form is of type "result"?
# ftype='text-single',
label='Subscription',
desc='Continue to edit subscription.',
value=result['link'])
session['payload'] = form
options.addOption(result['name'], result['link'])
session['allow_complete'] = True
session['allow_prev'] = False
session['has_next'] = False
session['next'] = self._handle_subscription_editor
session['has_next'] = True
session['payload'] = form
session['prev'] = None
return session
async def _handle_subscriptions(self, iq, session):
jid = session['from'].bare
form = self['xep_0004'].make_form('form', 'Subscriptions')
form['instructions'] = '📰️ Manage subscriptions'
form['instructions'] = 'Managing subscriptions'
# form.addField(var='interval',
# ftype='text-single',
# label='Interval period')
options = form.add_field(var='subscriptions',
ftype='list-multi',
# ftype='list-multi', # TODO To be added soon
ftype='list-single',
label='Subscriptions',
desc=('Select subscriptions to perform '
'actions upon.'),
@ -794,7 +831,6 @@ class Slixfeed(slixmpp.ClientXMPP):
subscriptions_ = sorted(subscriptions_, key=lambda x: x[0])
for subscription_ in subscriptions_:
# for subscription in categorized_subscriptions[category]:
# breakpoint()
title = subscription_[0]
url = subscription_[1]
options.addOption(title, url)
@ -808,30 +844,14 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
if 'subscriptions' in payload['values']:
if 'subscription' in payload['values']:
urls = payload['values']['subscription']
elif 'subscriptions' in payload['values']:
urls = payload['values']['subscriptions']
url_count = len(urls)
form = self['xep_0004'].make_form('form', 'Subscription')
if isinstance(urls, list) and url_count > 1:
form = self['xep_0004'].make_form('form', 'Subscription editor')
form['instructions'] = '📂️ Editing {} subscriptions'.format(url_count)
form.add_field(var='options',
ftype='fixed',
value='Options')
options = form.add_field(var='action',
ftype='list-single',
label='Action',
value='none')
options.addOption('None', 'none')
counter = 0
for url in urls:
feed_id = await sqlite.get_feed_id(db_file, url)
feed_id = feed_id[0]
count = sqlite.get_number_of_unread_entries_by_feed(db_file, feed_id)
counter += count[0]
if int(counter):
options.addOption('Mark {} entries as read'.format(counter), 'reset')
options.addOption('Delete {} subscriptions'.format(url_count), 'delete')
options.addOption('Export {} subscriptions'.format(url_count), 'export')
form['instructions'] = 'Editing {} subscriptions'.format(url_count)
else:
if isinstance(urls, list):
url = urls[0]
@ -839,11 +859,13 @@ class Slixfeed(slixmpp.ClientXMPP):
else:
url = urls
feed_id = await sqlite.get_feed_id(db_file, url)
feed_id = feed_id[0]
title = sqlite.get_feed_title(db_file, feed_id)
title = title[0]
form = self['xep_0004'].make_form('form', 'Subscription editor')
form['instructions'] = '📂️ Editing subscription #{}'.format(feed_id)
if feed_id:
feed_id = feed_id[0]
title = sqlite.get_feed_title(db_file, feed_id)
title = title[0]
form['instructions'] = 'Editing subscription #{}'.format(feed_id)
else:
form['instructions'] = 'Adding subscription'
form.add_field(ftype='fixed',
value='Properties')
form.add_field(var='name',
@ -854,26 +876,24 @@ class Slixfeed(slixmpp.ClientXMPP):
# url = form.add_field(ftype='fixed',
# value=url)
#url['validate']['datatype'] = 'xs:anyURI'
form.add_field(var='url',
ftype='text-single',
label='URL',
value=url)
form.add_field(ftype='fixed',
value='Options')
options = form.add_field(var='action',
options = form.add_field(var='url',
ftype='list-single',
label='Action',
value='none')
options.addOption('None', 'none')
count = sqlite.get_number_of_unread_entries_by_feed(db_file, feed_id)
count = count[0]
if int(count):
options.addOption('Mark {} entries as read'.format(count), 'reset')
options.addOption('Delete subscription', 'delete')
form.add_field(var='enable',
ftype='boolean',
label='Enable',
value=True)
label='URL',
value=url)
options.addOption(url, url)
feed_id_str = str(feed_id)
options = form.add_field(var='id',
ftype='list-single',
label='ID #',
value=feed_id_str)
options.addOption(feed_id_str, feed_id_str)
form.add_field(var='tags',
ftype='text-single',
# ftype='text-multi',
label='Tags',
value='')
form.add_field(ftype='fixed',
value='Options')
options = form.add_field(var='priority',
ftype='list-single',
label='Priority',
@ -885,42 +905,57 @@ class Slixfeed(slixmpp.ClientXMPP):
num = str(i)
options.addOption(num, num)
i += 1
form.add_field(ftype='fixed',
value='Labels')
options = form.add_field(var='category',
ftype='list-single',
label='Category',
value='none')
options.addOption('None', 'none')
options.addOption('Activity', 'activity')
options.addOption('Catalogues', 'catalogues')
options.addOption('Clubs', 'clubs')
options.addOption('Events', 'events')
options.addOption('Forums', 'forums')
options.addOption('Music', 'music')
options.addOption('News', 'news')
options.addOption('Organizations', 'organizations')
options.addOption('Podcasts', 'podcasts')
options.addOption('Projects', 'projects')
options.addOption('Schools', 'schools')
options.addOption('Stores', 'stores')
options.addOption('Tutorials', 'tutorials')
options.addOption('Videos', 'videos')
options = form.add_field(var='tags',
ftype='text-single',
# ftype='text-multi',
label='Tags',
value='')
session['payload'] = form
form.add_field(var='enabled',
ftype='boolean',
label='Enabled',
value=True)
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_subscription_complete
session['has_next'] = True
session['payload'] = form
return session
async def _handle_subscription_complete(self, payload, session):
jid = session['from'].bare
values = payload['values']
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
# url = values['url']
# feed_id = await sqlite.get_feed_id(db_file, url)
# feed_id = feed_id[0]
# if feed_id: feed_id = feed_id[0]
feed_id = values['id']
enabled = values['enabled']
# if enabled:
# enabled_status = 1
# else:
# enabled_status = 0
# await sqlite.mark_feed_as_read(db_file, feed_id)
enabled_status = 1 if enabled else 0
if not enabled_status: await sqlite.mark_feed_as_read(db_file, feed_id)
await sqlite.set_enabled_status(db_file, feed_id, enabled_status)
name = values['name']
await sqlite.set_feed_title(db_file, feed_id, name)
values['priority']
values['tags']
# form = self['xep_0004'].make_form('form', 'Subscription')
# form['instructions'] = ('📁️ Subscription #{} has been {}'
# .format(feed_id, action))
form = payload
form['title'] = 'Done'
form['instructions'] = ('has been completed!')
# session["has_next"] = False
session['next'] = None
session['payload'] = form
# session['type'] = 'submit'
return session
async def _handle_subscription_selector(self, payload, session):
jid = session['from'].bare
form = self['xep_0004'].make_form('form', 'Subscribe')
form['instructions'] = ('📰️ Select a subscriptions to add\n'
form = self['xep_0004'].make_form('form', 'Add Subscription')
form['instructions'] = ('📰️ Select a subscription to add\n'
'Subsciptions discovered for {}'
.format(url))
# form.addField(var='interval',
@ -955,13 +990,6 @@ class Slixfeed(slixmpp.ClientXMPP):
return session
async def _handle_subscription_complete(self, payload, session):
form = self['xep_0004'].make_form('form', 'Subscription editor')
form['instructions'] = ('📁️ Subscription #{} has been {}'
.format(feed_id, action))
pass
async def _handle_about(self, iq, session):
# form = self['xep_0004'].make_form('result', 'Thanks')
# form['instructions'] = action.manual('information.toml', 'thanks')
@ -1004,21 +1032,22 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_import(self, iq, session):
form = self['xep_0004'].make_form('form', 'Import')
form['instructions'] = '🗞️ Import feeds from OPML'
form['instructions'] = 'Importing feeds'
url = form.add_field(var='url',
ftype='text-single',
label='URL',
desc='Enter URL to OPML file.',
desc='Enter URL to an OPML file.',
required=True)
url['validate']['datatype'] = 'xs:anyURI'
session['payload'] = form
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_import_complete
session['has_next'] = True
session['payload'] = form
return session
async def _handle_import_complete(self, payload, session):
session['next'] = None
form = payload
url = payload['values']['url']
if url.startswith('http') and url.endswith('.opml'):
jid = session['from'].bare
@ -1027,47 +1056,55 @@ class Slixfeed(slixmpp.ClientXMPP):
count = await action.import_opml(db_file, url)
try:
int(count)
form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = ('✅️ Feeds have been imported')
message = '{} feeds have been imported to {}.'.format(count, jid)
form.add_field(var='message',
# form = self['xep_0004'].make_form('result', 'Done')
# form['instructions'] = ('✅️ Feeds have been imported')
form['title'] = 'Done'
form['instructions'] = ('has been completed!')
message = '{} feeds have been imported.'.format(count)
form.add_field(var='Message',
ftype='text-single',
value=message)
session['payload'] = form
session["has_next"] = False
except:
session['payload'] = None
session['notes'] = [['error', 'Import failed. Filetype does not appear to be an OPML file.']]
session['has_next'] = False
else:
session['payload'] = None
session['notes'] = [['error', 'Import aborted. Send URL of OPML file.']]
session['has_next'] = False
session["has_next"] = False
session['next'] = None
return session
async def _handle_export(self, iq, session):
form = self['xep_0004'].make_form('form', 'Export')
form['instructions'] = '🗞️ Export feeds'
form['instructions'] = 'Exporting subscription list'
options = form.add_field(var='filetype',
ftype='list-multi',
label='Format',
desc='Choose export format.',
desc='Choose export format. You are advised '
'to export into OPML file, if you want '
'to easily import your feeds into a Feed '
'Reader, such as Liferea or Qute RSS.',
value='opml',
required=True)
options.addOption('Markdown', 'md')
options.addOption('OPML', 'opml')
# options.addOption('HTML', 'html')
# options.addOption('XBEL', 'xbel')
session['payload'] = form
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_export_complete
session['has_next'] = True
session['payload'] = form
return session
async def _handle_export_complete(self, payload, session):
form = payload
jid = session['from'].bare
jid_file = jid.replace('/', '_')
form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = ('✅️ Feeds have been exported')
# form = self['xep_0004'].make_form('result', 'Done')
# form['instructions'] = ('✅️ Feeds have been exported')
exts = payload['values']['filetype']
for ext in exts:
filename = await action.export_feeds(self, jid, jid_file, ext)
@ -1076,9 +1113,11 @@ class Slixfeed(slixmpp.ClientXMPP):
ftype='text-single',
label=ext,
value=url)
session['payload'] = form
form['title'] = 'Done'
form['instructions'] = ('has been completed!')
session["has_next"] = False
session['next'] = None
session['payload'] = form
return session
@ -1105,10 +1144,11 @@ class Slixfeed(slixmpp.ClientXMPP):
url = action.pick_a_feed()
form = self['xep_0004'].make_form('form', 'Subscribe')
# NOTE Refresh button would be of use
form['instructions'] = '🔮️ Featured subscriptions' # 🎲️
form['instructions'] = 'Featured subscriptions'
options = form.add_field(var='subscription',
ftype="list-single",
label=url['name'],
label='Subscribe',
desc='Click to subscribe.',
value=url['link'])
options.addOption(url['name'], url['link'])
jid = session['from'].bare
@ -1125,13 +1165,16 @@ class Slixfeed(slixmpp.ClientXMPP):
'exist' : False}
elif isinstance(result, list):
for url in result:
if url['link']: options.addOption(url['name'], url['link'])
if url['link']: options.addOption('{}\n{}'.format(url['name'], url['link']), url['link'])
else:
url = result
# Automatically set priority to 5 (highest)
if url['link']: options.addOption(url['name'], url['link'])
session['payload'] = form
session['allow_prev'] = True
session['has_next'] = False
session['next'] = self._handle_subscription_new
session['payload'] = form
session['prev'] = self._handle_promoted
return session
@ -1206,13 +1249,13 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
if jid == config.get_value('accounts', 'XMPP', 'operator'):
form = self['xep_0004'].make_form('form', 'Subscribers')
form['instructions'] = '📖️ Organize subscribers'
form['instructions'] = 'Committing subscriber action'
options = form.add_field(var='jid',
ftype='list-single',
label='Contacts',
label='Jabber ID',
desc='Select a contact.',
required=True)
contacts = await XmppRoster.get(self)
contacts = await XmppRoster.get_contacts(self)
for contact in contacts:
contact_name = contacts[contact]['name']
contact_name = contact_name if contact_name else contact
@ -1251,13 +1294,13 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
if jid == config.get_value('accounts', 'XMPP', 'operator'):
form = self['xep_0004'].make_form('form', 'Contacts')
form['instructions'] = '📖️ Organize contacts'
form['instructions'] = 'Organize contacts'
options = form.add_field(var='jid',
ftype='list-single',
label='Contact',
desc='Select a contact.',
required=True)
contacts = await XmppRoster.get(self)
contacts = await XmppRoster.get_contacts(self)
for contact in contacts:
contact_name = contacts[contact]['name']
contact_name = contact_name if contact_name else contact
@ -1284,25 +1327,26 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_contact_action(self, payload, session):
jid = payload['values']['jid']
form = self['xep_0004'].make_form('form', 'Contact editor')
form = self['xep_0004'].make_form('form', 'Contacts')
session['allow_complete'] = True
roster = await XmppRoster.get_contacts(self)
properties = roster[jid]
match payload['values']['action']:
case 'edit':
form['instructions'] = '📖️ Edit contact'
roster = await XmppRoster.get(self)
properties = roster[jid]
form['instructions'] = 'Editing contact'
options = form.add_field(var='jid',
ftype='list-single',
label='Jabber ID',
value=jid)
options.addOption(jid, jid)
form.add_field(var='name',
ftype='text-single',
label='Name',
value=properties['name'])
session['allow_complete'] = True
session['next'] = self._handle_contacts_complete
case 'view':
session['has_next'] = False
session['next'] = None
session['allow_complete'] = None
form = self['xep_0004'].make_form('form', 'Contact info')
form['instructions'] = '📖️ Contact details'
roster = await XmppRoster.get(self)
properties = roster[jid]
form['instructions'] = 'Viewing contact'
contact_name = properties['name']
contact_name = contact_name if contact_name else jid
form.add_field(var='name',
@ -1333,54 +1377,33 @@ class Slixfeed(slixmpp.ClientXMPP):
ftype='fixed',
label='Subscription',
value=properties['subscription'])
session['allow_complete'] = None
session['next'] = None
# session['allow_complete'] = True
session['allow_prev'] = True
session['has_next'] = False
# session['next'] = None
session['payload'] = form
session['prev'] = self._handle_contacts
session['allow_prev'] = True
# session['next'] = None
# session['has_next'] = False
# session['allow_complete'] = True
return session
async def _handle_contacts_complete(self, payload, session):
pass
async def _handle_contacts_view(self, payload, session):
jid = payload['values']['jid']
roster = await XmppRoster.get(self)
properties = roster[jid]
form = self['xep_0004'].make_form('result', 'Contact')
contact_name = properties['name']
contact_name = contact_name if contact_name else jid
form['instructions'] = '📝️ Edit contact {}'.format(contact_name)
form.add_field(var='name',
ftype='boolean',
label='From',
value=properties['from'])
form.add_field(var='to',
ftype='boolean',
label='To',
value=properties['to'])
form.add_field(var='pending_in',
ftype='boolean',
label='Pending in',
value=properties['pending_in'])
form.add_field(var='pending_out',
ftype='boolean',
label='Pending out',
value=properties['pending_out'])
form.add_field(var='whitelisted',
ftype='boolean',
label='Whitelisted',
value=properties['whitelisted'])
form.add_field(var='subscription',
ftype='text-single',
label='Subscription',
value=properties['subscription'])
session['payload'] = form
session['next'] = self._handle_bookmarks_complete
session['has_next'] = True
def _handle_contacts_complete(self, payload, session):
values = payload['values']
jid = values['jid']
name = values['name']
name_old = XmppRoster.get_contact_name(self, jid)
if name == name_old:
session['payload'] = None
session['notes'] = [['info', 'No action has been taken. Reason: '
'New name is identical to the current one.']]
else:
XmppRoster.set_contact_name(self, jid, name)
form = payload
form['title'] = 'Done'
form['instructions'] = ('has been completed!')
session['payload'] = form
session['next'] = None
return session
@ -1388,11 +1411,12 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
if jid == config.get_value('accounts', 'XMPP', 'operator'):
form = self['xep_0004'].make_form('form', 'Bookmarks')
form['instructions'] = '📖️ Organize bookmarks'
options = form.add_field(var='bookmarks',
form['instructions'] = 'Bookmarks'
options = form.add_field(var='jid',
ftype='list-single',
label='Select a bookmark',
desc='Select a bookmark to edit.')
label='Jabber ID',
desc='Select a bookmark to edit.',
required=True)
conferences = await XmppBookmark.get(self)
for conference in conferences:
options.addOption(conference['name'], conference['jid'])
@ -1411,13 +1435,18 @@ class Slixfeed(slixmpp.ClientXMPP):
async def _handle_bookmarks_editor(self, payload, session):
jid = payload['values']['bookmarks']
jid = payload['values']['jid']
properties = await XmppBookmark.properties(self, jid)
form = self['xep_0004'].make_form('form', 'Bookmark editor')
form['instructions'] = '📝️ Edit bookmark {}'.format(properties['name'])
jid = properties['jid'].split('@')
room = jid[0]
host = jid[1]
form = self['xep_0004'].make_form('form', 'Bookmarks')
form['instructions'] = 'Editing bookmark'
jid_split = properties['jid'].split('@')
room = jid_split[0]
host = jid_split[1]
options = form.addField(var='jid',
ftype='list-single',
label='Jabber ID',
value=jid)
options.addOption(jid, jid)
form.addField(var='name',
ftype='text-single',
label='Name',
@ -1457,43 +1486,33 @@ class Slixfeed(slixmpp.ClientXMPP):
# options.addOption('Add', 'add')
# options.addOption('Join', 'join')
# options.addOption('Remove', 'remove')
session['payload'] = form
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_bookmarks_complete
session['has_next'] = True
session['payload'] = form
return session
async def _handle_bookmarks_complete(self, payload, session):
"""
Process a command result from the user.
Arguments:
payload -- Either a single item, such as a form, or a list
of items or forms if more than one form was
provided to the user. The payload may be any
stanza, such as jabber:x:oob for out of band
data, or jabber:x:data for typical data forms.
session -- A dictionary of data relevant to the command
session. Additional, custom data may be saved
here to persist across handler callbacks.
"""
form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = ('✅️ Bookmark has been saved')
# In this case (as is typical), the payload is a form
# form = self['xep_0004'].make_form('result', 'Done')
# form['instructions'] = ('✅️ Bookmark has been saved')
# # In this case (as is typical), the payload is a form
values = payload['values']
await XmppBookmark.add(self, properties=values)
for value in values:
key = str(value)
val = str(values[value])
if not val: val = 'None' # '(empty)'
form.add_field(var=key,
ftype='text-single',
label=key.capitalize(),
value=val)
session['payload'] = form # Comment when this is fixed in Gajim
session["has_next"] = False
# for value in values:
# key = str(value)
# val = str(values[value])
# if not val: val = 'None' # '(empty)'
# form.add_field(var=key,
# ftype='text-single',
# label=key.capitalize(),
# value=val)
form = payload
breakpoint()
form['title'] = 'Done'
form['instructions'] = 'has been completed!'
session['next'] = None
session['payload'] = form
return session
@ -1510,8 +1529,8 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
form = self['xep_0004'].make_form('form', 'Setting editor')
form['instructions'] = ('📮️ Customize news updates')
form = self['xep_0004'].make_form('form', 'Settings')
form['instructions'] = 'Editing settings'
value = config.get_setting_value(db_file, 'enabled')
value = int(value)
@ -1521,7 +1540,7 @@ class Slixfeed(slixmpp.ClientXMPP):
value = False
form.add_field(var='enabled',
ftype='boolean',
label='Enable',
label='Enabled',
desc='Enable news updates.',
value=value)
@ -1600,78 +1619,61 @@ class Slixfeed(slixmpp.ClientXMPP):
x = str(i)
options.addOption(x, x)
i += 50
session['payload'] = form
session['next'] = self._handle_settings_complete
session['allow_complete'] = True
session['has_next'] = False
session['next'] = self._handle_settings_complete
session['payload'] = form
return session
async def _handle_settings_complete(self, payload, session):
"""
Process a command result from the user.
Arguments:
payload -- Either a single item, such as a form, or a list
of items or forms if more than one form was
provided to the user. The payload may be any
stanza, such as jabber:x:oob for out of band
data, or jabber:x:data for typical data forms.
session -- A dictionary of data relevant to the command
session. Additional, custom data may be saved
here to persist across handler callbacks.
"""
# This looks nice in Gajim, though there are dropdown menues
# form = payload
jid = session['from'].bare
form = self['xep_0004'].make_form('form', 'Done')
form['instructions'] = ('✅️ Settings have been saved')
form = payload
# jid_file = jid
# db_file = config.get_pathname_to_database(jid_file)
# # In this case (as is typical), the payload is a form
# values = payload['values']
# for value in values:
# key = value
# val = values[value]
jid_file = jid
db_file = config.get_pathname_to_database(jid_file)
# In this case (as is typical), the payload is a form
values = payload['values']
for value in values:
key = value
val = values[value]
# if key == 'interval':
# val = int(val)
# if val < 1: val = 1
# val = val * 60
if key == 'interval':
val = int(val)
if val < 1: val = 1
val = val * 60
# if sqlite.is_setting_key(db_file, key):
# await sqlite.update_setting_value(db_file, [key, val])
# else:
# await sqlite.set_setting_value(db_file, [key, val])
if sqlite.is_setting_key(db_file, key):
await sqlite.update_setting_value(db_file, [key, val])
else:
await sqlite.set_setting_value(db_file, [key, val])
# val = sqlite.get_setting_value(db_file, key)
# val = val[0]
# if key in ('enabled', 'media', 'old'):
# if val == '1':
# val = 'Yes'
# elif val == '0':
# val = 'No'
val = sqlite.get_setting_value(db_file, key)
val = val[0]
if key in ('enabled', 'media', 'old'):
if val == '1':
val = 'Yes'
elif val == '0':
val = 'No'
# if key == 'interval':
# val = int(val)
# val = val/60
# val = int(val)
# val = str(val)
if key == 'interval':
val = int(val)
val = val/60
val = int(val)
val = str(val)
# # match value:
# # case 'enabled':
# # pass
# # case 'interval':
# # pass
# match value:
# case 'enabled':
# pass
# case 'interval':
# pass
# result = '{}: {}'.format(key.capitalize(), val)
result = '{}: {}'.format(key.capitalize(), val)
form.add_field(var=key,
ftype='fixed',
value=result)
session['payload'] = form # Comment when this is fixed in Gajim
session["has_next"] = False
# form.add_field(var=key,
# ftype='fixed',
# value=result)
form['title'] = 'Done'
form['instructions'] = 'has been completed!'
session['next'] = None
# return session
session['payload'] = form
return session

File diff suppressed because it is too large Load diff

View file

@ -320,7 +320,9 @@ async def message(self, message):
'index {}'
.format(url, name, ix))
else:
response = 'Missing URL.'
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]
@ -339,7 +341,9 @@ async def message(self, message):
'```\n{}\n```'
.format(val))
else:
response = 'Missing keywords.'
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]
@ -358,7 +362,9 @@ async def message(self, message):
'```\n{}\n```'
.format(val))
else:
response = 'Missing keywords.'
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]
@ -381,9 +387,13 @@ async def message(self, message):
'been set to {}.'
.format(val))
except:
response = 'Enter a numeric value only.'
response = ('No action has been taken.'
'\n'
'Enter a numeric value only.')
else:
response = 'Missing value.'
response = ('No action has been taken.'
'\n'
'Missing value.')
XmppMessage.send_reply(self, message, response)
case _ if message_lowercase.startswith('bookmark +'):
if jid == config.get_value('accounts', 'XMPP', 'operator'):
@ -447,7 +457,9 @@ async def message(self, message):
'```\n{}\n```'
.format(val))
else:
response = 'Missing keywords.'
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]
@ -466,7 +478,9 @@ async def message(self, message):
'```\n{}\n```'
.format(val))
else:
response = 'Missing keywords.'
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:]
@ -600,7 +614,9 @@ async def message(self, message):
jid_file,
message=message)
except:
response = 'Enter a numeric value only.'
response = ('No action has been taken.'
'\n'
'Enter a numeric value only.')
XmppMessage.send_reply(self, message, response)
case _ if message_lowercase.startswith('join'):
muc_jid = uri.check_xmpp_uri(message_text[5:])
@ -635,9 +651,13 @@ async def message(self, message):
'is set to {} characters.'
.format(val))
except:
response = 'Enter a numeric value only.'
response = ('No action has been taken.'
'\n'
'Enter a numeric value only.')
else:
response = 'Missing value.'
response = ('No action has been taken.'
'\n'
'Missing value.')
# case _ if message_lowercase.startswith('mastership'):
# key = message_text[:7]
# val = message_text[11:]
@ -735,9 +755,13 @@ async def message(self, message):
response = ('Next update will contain {} news items.'
.format(val))
except:
response = 'Enter a numeric value only.'
response = ('No action has been taken.'
'\n'
'Enter a numeric value only.')
else:
response = 'Missing value.'
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
@ -763,19 +787,25 @@ async def message(self, message):
if url.startswith('http'):
response = await action.view_feed(url)
else:
response = 'Missing URL.'
response = ('No action has been taken.'
'\n'
'Missing URL.')
case 2:
num = data[1]
if url.startswith('http'):
response = await action.view_entry(url, num)
else:
response = 'Missing URL.'
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 = 'Missing URL.'
response = ('No action has been taken.'
'\n'
'Missing URL.')
XmppMessage.send_reply(self, message, response)
await task.start_tasks_xmpp(self, jid, ['status'])
case _ if message_lowercase.startswith('recent'):
@ -790,9 +820,13 @@ async def message(self, message):
result = await sqlite.last_entries(db_file, num)
response = action.list_last_entries(result, num)
except:
response = 'Enter a numeric value only.'
response = ('No action has been taken.'
'\n'
'Enter a numeric value only.')
else:
response = 'Missing value.'
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:]
@ -825,8 +859,8 @@ async def message(self, message):
.format(url))
else:
response = ('> {}\n'
# 'No action has been made.'
'News source does not exist. '
'No action has been made.'
.format(url))
# await refresh_task(
# self,
@ -838,7 +872,10 @@ async def message(self, message):
# task.clean_tasks_xmpp(self, jid, ['status'])
await task.start_tasks_xmpp(self, jid, ['status'])
else:
response = 'Missing feed URL or index number.'
response = ('No action has been taken.'
'\n'
'Missing argument. '
'Enter feed URL or index number.')
XmppMessage.send_reply(self, message, response)
case _ if message_lowercase.startswith('reset'):
# TODO Reset also by ID
@ -880,8 +917,8 @@ async def message(self, message):
.format(url, name))
else:
response = ('> {}\n'
# 'No action has been made.'
'News source does not exist. '
'No action has been made.'
.format(url))
else:
await sqlite.mark_all_as_read(db_file)
@ -898,7 +935,9 @@ async def message(self, message):
else:
response = 'Enter at least 2 characters to search'
else:
response = 'Missing search query.'
response = ('No action has been taken.'
'\n'
'Missing search query.')
XmppMessage.send_reply(self, message, response)
case 'start':
await action.xmpp_start_updates(self, message, jid, jid_file)
@ -918,9 +957,47 @@ async def message(self, message):
'Updates are now disabled for news source "{}"'
.format(addr, name))
except:
response = 'No news source with index {}.'.format(feed_id)
response = ('No action has been taken.'
'\n'
'No news source with index {}.'
.format(feed_id))
XmppMessage.send_reply(self, message, response)
await task.start_tasks_xmpp(self, jid, ['status'])
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)
@ -932,7 +1009,9 @@ async def message(self, message):
'Updates are now enabled for news source "{}"'
.format(addr, name))
except:
response = 'No news source with index {}.'.format(ix)
response = ('No action has been taken.'
'\n'
'No news source with index {}.'.format(ix))
XmppMessage.send_reply(self, message, response)
case 'stop':
await action.xmpp_stop_updates(self, message, jid, jid_file)

View file

@ -13,12 +13,6 @@ TODO
class XmppRoster:
async def get(self):
await self.get_roster()
contacts = self.client_roster
return contacts
async def add(self, jid):
"""
Add JID to roster.
@ -39,6 +33,12 @@ class XmppRoster:
self.update_roster(jid, subscription='both')
async def get_contacts(self):
await self.get_roster()
contacts = self.client_roster
return contacts
def remove(self, jid):
"""
Remove JID from roster.
@ -53,3 +53,12 @@ class XmppRoster:
None.
"""
self.update_roster(jid, subscription='remove')
def set_contact_name(self, jid, name):
self.client_roster[jid]['name'] = name
def get_contact_name(self, jid):
name = self.client_roster[jid]['name']
return name