Add About, Bookmarks and Manual forms

This commit is contained in:
Schimon Jehudah 2024-02-14 03:04:49 +00:00
parent 12689b8ef1
commit dba7eefb96
6 changed files with 234 additions and 103 deletions

View file

@ -617,9 +617,10 @@ 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 += ('{}\n' message += ('Name: {}\n'
'Room: {}\n'
'\n' '\n'
.format(conference['jid'])) .format(conference['name'], conference['jid']))
message += ('```\nTotal of {} groupchats.\n' message += ('```\nTotal of {} groupchats.\n'
.format(len(conferences))) .format(len(conferences)))
return message return message

View file

@ -46,11 +46,10 @@ DEALINGS IN THE SOFTWARE.
note = """ note = """
You can run Slixfeed as a client, from your own computer, server, \ You can run Slixfeed as a client, from your own computer, server, \
and even on a Linux phone (i.e. Droidian, Kupfer, Mobian, NixOS, \ and even from a Linux phone (i.e. Droidian, Kupfer, Mobian, NixOS, \
postmarketOS). You can even use Termux. postmarketOS), and even from Termux.
All you need is one of the above and an XMPP account to connect \
All you need is one of the above and an XMPP account to \ Slixfeed to. Good luck!
connect Slixfeed to.
""" """
operators = """ operators = """
@ -100,41 +99,41 @@ https://gitgud.io/sjehuda/slixfeed
""" """
thanks = """ thanks = """
Alixander Court <alixandercourt.com> (Utah), \ Alixander Court <alixandercourt.com> (Utah); \
Chriss Farrell (SalixOS, Oregon), \ Chriss Farrell (SalixOS, Oregon); \
Christian Dersch (SalixOS), \ Christian Dersch (SalixOS); \
Cyrille Pontvieux <enialis.net> (SalixOS, France), \ Cyrille Pontvieux <enialis.net> (SalixOS, France); \
Denis Fomin (Gajim, Russia), \ Denis Fomin (Gajim, Russia); \
Dimitris Tzemos (SalixOS, Greece), \ Dimitris Tzemos (SalixOS, Greece); \
Emmanuel Gil Peyrot (Poezio, France), \ Emmanuel Gil Peyrot (Poezio, France); \
Florent Le Coz (Poezio, France), \ Florent Le Coz (Poezio, France); \
George Vlahavas <vlahavas.com> (SalixOS, Greece), \ George Vlahavas <vlahavas.com> (SalixOS, Greece); \
Guus der Kinderen <igniterealtime.org> (Openfire, Netherlands), \ Guus der Kinderen <igniterealtime.org> (Openfire, Netherlands); \
habnabit_ from #python on irc.libera.chat, \ habnabit_ from #python on irc.libera.chat; \
Imar van Erven Dorens <simplicit.nl> (SalixOS, Netherlands), \ Imar van Erven Dorens <simplicit.nl> (SalixOS, Netherlands); \
imattau (atomtopubsub), \ imattau (atomtopubsub); \
Jaussoin Timothée <mov.im> (Movim, France), \ Jaussoin Timothée <mov.im> (Movim, France); \
Justin Karneges <jblog.andbit.net> (Psi, California), \ Justin Karneges <jblog.andbit.net> (Psi, California); \
Kevin Smith <isode.com> (Swift IM, Wales), \ Kevin Smith <isode.com> (Swift IM, Wales); \
Lars Windolf (Liferea, Germany), \ Lars Windolf (Liferea, Germany); \
Luis Henrique Mello (SalixOS, Brazil), \ Luis Henrique Mello (SalixOS, Brazil); \
magicfelix, \ magicfelix; \
Markus Muttilainen (SalixOS), \ Markus Muttilainen (SalixOS); \
Martin <debacle@debian.org> (Debian, Germany), \ Martin <debacle@debian.org> (Debian, Germany); \
Mathieu Pasquet (slixmpp, France), \ Mathieu Pasquet (slixmpp, France); \
Maxime Buquet (slixmpp, France), \ Maxime Buquet (slixmpp, France); \
mirux (Germany), \ mirux (Germany); \
Phillip Watkins (SalixOS, United Kingdom), \ Phillip Watkins (SalixOS, United Kingdom); \
Pierrick Le Brun (SalixOS, France), \ Pierrick Le Brun (SalixOS, France); \
Raphael Groner (Fedora, Germany), \ Raphael Groner (Fedora, Germany); \
Remko Tronçon <mko.re> (Psi , Belgium), \ Remko Tronçon <mko.re> (Psi , Belgium); \
Simone "roughnecks" Canaletti <woodpeckersnest.space> (Italy), \ 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); \
Thorsten Fröhlich (France), \ Thorsten Fröhlich (France); \
Thorsten Mühlfelder (SalixOS, Germany), \ Thorsten Mühlfelder (SalixOS, Germany); \
Tim Beech (SalixOS, Brazil), \ Tim Beech (SalixOS, Brazil); \
Yann Leboulanger (Gajim, France). Yann Leboulanger (Gajim, France).
""" """

View file

@ -797,7 +797,7 @@ async def mark_entry_as_read(cur, ix):
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 goven feed. Count entries of given feed.
Parameters Parameters
---------- ----------

View file

@ -17,9 +17,7 @@ class XmppBookmark:
async def get(self): async def get(self):
result = await self.plugin['xep_0048'].get_bookmarks() result = await self.plugin['xep_0048'].get_bookmarks()
bookmarks = result['private']['bookmarks'] conferences = result['private']['bookmarks']['conferences']
conferences = bookmarks['conferences'] # We might not want this here
# conferences = bookmarks
return conferences return conferences
@ -38,21 +36,37 @@ class XmppBookmark:
return properties return properties
async def add(self, muc_jid): async def add(self, jid=None, properties=None):
result = await self.plugin['xep_0048'].get_bookmarks() result = await self.plugin['xep_0048'].get_bookmarks()
bookmarks = result['private']['bookmarks'] conferences = result['private']['bookmarks']['conferences']
conferences = bookmarks['conferences'] groupchats = []
mucs = []
for conference in conferences: for conference in conferences:
jid = conference['jid'] groupchats.extend([conference])
mucs.extend([jid]) if properties:
if muc_jid not in mucs: properties['jid'] = properties['room'] + '@' + properties['host']
else:
properties = {
'jid' : jid,
'alias' : self.alias,
'name' : jid.split('@')[0],
'autojoin' : True,
'password' : None,
}
if jid not in groupchats:
bookmarks = Bookmarks() bookmarks = Bookmarks()
mucs.extend([muc_jid]) for groupchat in groupchats:
for muc in mucs: # if groupchat['jid'] == groupchat['name']:
bookmarks.add_conference(muc, # groupchat['name'] = groupchat['name'].split('@')[0]
self.alias, bookmarks.add_conference(groupchat['jid'],
autojoin=True) groupchat['alias'],
name=groupchat['name'],
autojoin=groupchat['autojoin'],
password=groupchat['password'])
bookmarks.add_conference(properties['jid'],
properties['alias'],
name=properties['name'],
autojoin=properties['autojoin'],
password=properties['password'])
await self.plugin['xep_0048'].set_bookmarks(bookmarks) await self.plugin['xep_0048'].set_bookmarks(bookmarks)
# bookmarks = Bookmarks() # bookmarks = Bookmarks()
# await self.plugin['xep_0048'].set_bookmarks(bookmarks) # await self.plugin['xep_0048'].set_bookmarks(bookmarks)
@ -63,19 +77,18 @@ class XmppBookmark:
# await self['xep_0402'].publish(bm) # await self['xep_0402'].publish(bm)
async def remove(self, muc_jid): async def remove(self, jid):
result = await self.plugin['xep_0048'].get_bookmarks() result = await self.plugin['xep_0048'].get_bookmarks()
bookmarks = result['private']['bookmarks'] conferences = result['private']['bookmarks']['conferences']
conferences = bookmarks['conferences'] groupchats = []
mucs = []
for conference in conferences: for conference in conferences:
jid = conference['jid'] if not conference['jid'] == jid:
mucs.extend([jid]) groupchats.extend([conference])
if muc_jid in mucs: bookmarks = Bookmarks()
bookmarks = Bookmarks() for groupchat in groupchats:
mucs.remove(muc_jid) bookmarks.add_conference(groupchat['jid'],
for muc in mucs: groupchat['nick'],
bookmarks.add_conference(muc, name=groupchat['name'],
self.alias, autojoin=groupchat['autojoin'],
autojoin=True) password=groupchat['password'])
await self.plugin['xep_0048'].set_bookmarks(bookmarks) await self.plugin['xep_0048'].set_bookmarks(bookmarks)

View file

@ -201,6 +201,7 @@ class Slixfeed(slixmpp.ClientXMPP):
async def on_session_start(self, event): async def on_session_start(self, event):
# self.send_presence()
profile.set_identity(self, 'client') profile.set_identity(self, 'client')
self.service_commands() self.service_commands()
self.service_reactions() self.service_reactions()
@ -214,26 +215,26 @@ class Slixfeed(slixmpp.ClientXMPP):
# Service.reactions(self) # Service.reactions(self)
async def on_session_resumed(self, event): async def on_session_resumed(self, event):
self.send_presence() # self.send_presence()
self['xep_0115'].update_caps(preserve=True)
await XmppGroupchat.autojoin(self)
profile.set_identity(self, 'client') profile.set_identity(self, 'client')
# self.service_commands()
# self.service_reactions()
self['xep_0115'].update_caps()
await XmppGroupchat.autojoin(self)
# Service.commands(self) # Service.commands(self)
# Service.reactions(self) # Service.reactions(self)
self.service_commands()
self.service_reactions()
async def on_disco_info(self, DiscoInfo): async def on_disco_info(self, DiscoInfo):
jid = DiscoInfo['from'] jid = DiscoInfo['from']
self.send_presence(pto=jid) # self.service_commands()
await self['xep_0115'].update_caps(jid=jid, # self.service_reactions()
preserve=True) # self.send_presence(pto=jid)
self.service_commands() await self['xep_0115'].update_caps(jid=jid)
self.service_reactions()
# TODO Request for subscription # TODO Request for subscription
@ -356,19 +357,25 @@ class Slixfeed(slixmpp.ClientXMPP):
if jid in self.boundjid.bare: if jid in self.boundjid.bare:
return return
if message['type'] in ('chat', 'normal'): if message['type'] in ('chat', 'normal'):
# task.clean_tasks_xmpp(self, jid, ['status'])
await task.start_tasks_xmpp(self, jid, ['status'])
# NOTE: Required for Cheogram # NOTE: Required for Cheogram
await self['xep_0115'].update_caps(jid=jid)
# self.send_presence(pto=jid)
# task.clean_tasks_xmpp(self, jid, ['status'])
await asyncio.sleep(5)
await task.start_tasks_xmpp(self, jid, ['status'])
async def on_chatstate_composing(self, message): async def on_chatstate_composing(self, message):
if message['type'] in ('chat', 'normal'): if message['type'] in ('chat', 'normal'):
jid = message['from'].bare jid = message['from'].bare
# NOTE: Required for Cheogram
await self['xep_0115'].update_caps(jid=jid)
# self.send_presence(pto=jid)
# task.clean_tasks_xmpp(self, jid, ['status']) # task.clean_tasks_xmpp(self, jid, ['status'])
await asyncio.sleep(5)
status_message = ('💡 Send "help" for manual, or "info" for ' status_message = ('💡 Send "help" for manual, or "info" for '
'information.') 'information.')
XmppPresence.send(self, jid, status_message) XmppPresence.send(self, jid, status_message)
# NOTE: Required for Cheogram
async def on_chatstate_gone(self, message): async def on_chatstate_gone(self, message):
@ -465,12 +472,12 @@ class Slixfeed(slixmpp.ClientXMPP):
self['xep_0050'].add_command(node='filters', self['xep_0050'].add_command(node='filters',
name='🕸️ Manage filters', name='🕸️ Manage filters',
handler=self._handle_filters) handler=self._handle_filters)
self['xep_0050'].add_command(node='roster',
name='🧾️ Manage roster',
handler=self._handle_roster)
self['xep_0050'].add_command(node='bookmarks', self['xep_0050'].add_command(node='bookmarks',
name='📔️ Organize bookmarks', name='📔️ Organize bookmarks - Restricted',
handler=self._handle_bookmarks) handler=self._handle_bookmarks)
self['xep_0050'].add_command(node='roster',
name='🧾️ Organize roster - Restricted',
handler=self._handle_roster)
self['xep_0050'].add_command(node='subscriptions', self['xep_0050'].add_command(node='subscriptions',
name='📰️ Subscriptions - All', name='📰️ Subscriptions - All',
handler=self._handle_subscriptions) handler=self._handle_subscriptions)
@ -483,6 +490,12 @@ class Slixfeed(slixmpp.ClientXMPP):
self['xep_0050'].add_command(node='subscriptions_index', self['xep_0050'].add_command(node='subscriptions_index',
name='📑️ Subscriptions - Indexed', name='📑️ Subscriptions - Indexed',
handler=self._handle_subscription) handler=self._handle_subscription)
self['xep_0050'].add_command(node='credit',
name='💡️ Credit',
handler=self._handle_credit)
self['xep_0050'].add_command(node='help',
name='🛟️ Help',
handler=self._handle_help)
# self['xep_0050'].add_command(node='search', # self['xep_0050'].add_command(node='search',
# name='Search', # name='Search',
# handler=self._handle_search) # handler=self._handle_search)
@ -756,6 +769,62 @@ class Slixfeed(slixmpp.ClientXMPP):
pass pass
async def _handle_credit(self, iq, session):
import slixfeed.action as action
# form = self['xep_0004'].make_form('result', 'Thanks')
# form['instructions'] = action.manual('information.toml', 'thanks')
# session['payload'] = form
text = '💡️ We are Jabber\n\n'
fren = action.manual('information.toml', 'thanks')
fren = "".join(fren)
fren = fren.split(';')
fren = "\n".join(fren)
text += fren
text += '\n\nYOU!\n\n🫵️\n\n- Join us -\n\n🤝️'
session['notes'] = [['info', text]]
return session
async def _handle_help(self, iq, session):
filename = 'commands.toml'
import tomllib
config_dir = config.get_default_config_directory()
with open(config_dir + '/' + filename, mode="rb") as commands:
cmds = tomllib.load(commands)
form = self['xep_0004'].make_form('result', 'Manual')
form['instructions'] = '🛟️ Help manual for interactive chat'
# text = '🛟️ Help and Information about Slixfeed\n\n'
# for cmd in cmds:
# name = cmd.capitalize()
# elements = cmds[cmd]
# text += name + '\n'
# for key, value in elements.items():
# text += " " + key.capitalize() + '\n'
# for line in value.split("\n"):
# text += " " + line + '\n'
# form['instructions'] = text
for cmd in cmds:
name = cmd.capitalize()
form.add_field(var='title',
ftype='fixed',
value=name)
elements = cmds[cmd]
for key, value in elements.items():
key = key.replace('_', ' ')
key = key.capitalize()
form.add_field(var='title',
ftype='text-multi',
label=key,
value=value)
session['payload'] = form
return session
async def _handle_bookmarks(self, iq, session): async def _handle_bookmarks(self, iq, session):
jid = session['from'].bare jid = session['from'].bare
if jid == config.get_value('accounts', 'XMPP', 'operator'): if jid == config.get_value('accounts', 'XMPP', 'operator'):
@ -769,9 +838,9 @@ class Slixfeed(slixmpp.ClientXMPP):
conferences = await XmppBookmark.get(self) conferences = await XmppBookmark.get(self)
for conference in conferences: for conference in conferences:
options.addOption(conference['name'], conference['jid']) options.addOption(conference['name'], conference['jid'])
session['payload'] = form
session['next'] = self._handle_bookmarks_editor session['next'] = self._handle_bookmarks_editor
session['has_next'] = True session['has_next'] = True
session['payload'] = form
else: else:
logging.warning('An unauthorized attempt to access bookmarks has ' logging.warning('An unauthorized attempt to access bookmarks has '
'been detected!\n' 'been detected!\n'
@ -788,7 +857,7 @@ class Slixfeed(slixmpp.ClientXMPP):
properties = await XmppBookmark.properties(self, jid) properties = await XmppBookmark.properties(self, jid)
jid = session['from'].bare jid = session['from'].bare
form = self['xep_0004'].make_form('form', 'Edit bookmark') form = self['xep_0004'].make_form('form', 'Edit bookmark')
form['instructions'] = 'Edit bookmark {}'.format(properties['name']) form['instructions'] = '📝️ Edit bookmark {}'.format(properties['name'])
jid = properties['jid'].split('@') jid = properties['jid'].split('@')
room = jid[0] room = jid[0]
host = jid[1] host = jid[1]
@ -822,16 +891,49 @@ class Slixfeed(slixmpp.ClientXMPP):
ftype='boolean', ftype='boolean',
label='Auto-join', label='Auto-join',
value=properties['autojoin']) value=properties['autojoin'])
options = form.add_field(var='action', # options = form.add_field(var='action',
ftype='list-single', # ftype='list-single',
label='Action', # label='Action',
value='join') # value='join')
# options.addOption('Add', 'add') # options.addOption('Add', 'add')
options.addOption('Join', 'join') # options.addOption('Join', 'join')
options.addOption('Remove', 'remove') # options.addOption('Remove', 'remove')
session['payload'] = form session['payload'] = form
session['next'] = False session['next'] = self._handle_bookmarks_complete
session['has_next'] = False session['has_next'] = True
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', 'Bookmarks')
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])
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
session['next'] = None
return session return session
@ -927,7 +1029,7 @@ class Slixfeed(slixmpp.ClientXMPP):
options = form.add_field(var='quantum', options = form.add_field(var='quantum',
ftype='list-single', ftype='list-single',
label='Amount', label='Amount',
desc='Set amount of updates per update.', desc='Set amount of items per update.',
value=value) value=value)
i = 1 i = 1
while i <= 5: while i <= 5:
@ -961,7 +1063,7 @@ class Slixfeed(slixmpp.ClientXMPP):
jid = session['from'].bare jid = session['from'].bare
form = self['xep_0004'].make_form('form', form = self['xep_0004'].make_form('form',
'Settings for {}'.format(jid)) 'Settings for {}'.format(jid))
form['instructions'] = ('🛡️ Settings have beem saved') form['instructions'] = ('🛡️ Settings have been saved')
jid_file = jid jid_file = jid
db_file = config.get_pathname_to_database(jid_file) db_file = config.get_pathname_to_database(jid_file)

View file

@ -16,6 +16,11 @@ TODO
message.reply("Share online status to activate bot.").send() message.reply("Share online status to activate bot.").send()
return return
3) Set timeout for moderator interaction.
If moderator interaction has been made, and moderator approves the bot, then
the bot will add the given groupchat to bookmarks; otherwise, the bot will
send a message that it was not approved and therefore leaves the groupchat.
""" """
import logging import logging
@ -379,12 +384,21 @@ async def message(self, message):
else: else:
response = 'Missing value.' response = 'Missing value.'
XmppMessage.send_reply(self, message, response) XmppMessage.send_reply(self, message, response)
case _ if message_lowercase.startswith('bookmark +'):
if jid == config.get_value('accounts', 'XMPP', 'operator'):
muc_jid = message_text[11:]
await XmppBookmark.add(self, jid=muc_jid)
response = ('Groupchat {} has been added to bookmarks.'
.format(muc_jid))
else:
response = ('This action is restricted. '
'Type: adding bookmarks.')
XmppMessage.send_reply(self, message, response)
case _ if message_lowercase.startswith('bookmark -'): case _ if message_lowercase.startswith('bookmark -'):
if jid == config.get_value('accounts', 'XMPP', 'operator'): if jid == config.get_value('accounts', 'XMPP', 'operator'):
muc_jid = message_text[11:] muc_jid = message_text[11:]
await XmppBookmark.remove(self, muc_jid) await XmppBookmark.remove(self, muc_jid)
response = ('Groupchat {} has been removed ' response = ('Groupchat {} has been removed from bookmarks.'
'from bookmarks.'
.format(muc_jid)) .format(muc_jid))
else: else:
response = ('This action is restricted. ' response = ('This action is restricted. '
@ -572,6 +586,7 @@ async def message(self, message):
if muc_jid: if muc_jid:
# TODO probe JID and confirm it's a groupchat # TODO probe JID and confirm it's a groupchat
await XmppGroupchat.join(self, jid, muc_jid) await XmppGroupchat.join(self, jid, muc_jid)
# await XmppBookmark.add(self, jid=muc_jid)
response = ('Joined groupchat {}' response = ('Joined groupchat {}'
.format(message_text)) .format(message_text))
else: else:
@ -909,6 +924,7 @@ async def message(self, message):
if muc_jid: if muc_jid:
# TODO probe JID and confirm it's a groupchat # TODO probe JID and confirm it's a groupchat
await XmppGroupchat.join(self, jid, muc_jid) await XmppGroupchat.join(self, jid, muc_jid)
# await XmppBookmark.add(self, jid=muc_jid)
response = ('Joined groupchat {}' response = ('Joined groupchat {}'
.format(message_text)) .format(message_text))
else: else: