diff --git a/__main__.py b/__main__.py deleted file mode 100644 index 5f66aee..0000000 --- a/__main__.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python3 - -# Slixmark: The XMPP Bookmark Manager -# Copyright (C) 2024 Schimon Zackary -# This file is part of Slixmark. -# See the file LICENSE for copying permission. - -import buku -from bukubot.about import Documentation -from bukubot.config import Configuration -from bukubot.xmpp.chat import Chat -from bukubot.xmpp.client import Client -from getpass import getpass -from argparse import ArgumentParser -import logging -import os -import slixmpp -import sys - -# bookmarks_db = buku.BukuDb(dbfile='temp.db') -# bookmarks_db.get_tag_all -# bookmarks_db.search_keywords_and_filter_by_tags -# bookmarks_db.exclude_results_from_search - - - - -def main(): - # Setup the command line arguments. - parser = ArgumentParser(description=Client.__doc__) - - # Output verbosity options. - parser.add_argument("-q", "--quiet", help="set logging to ERROR", - action="store_const", dest="loglevel", - const=logging.ERROR, default=logging.INFO) - parser.add_argument("-d", "--debug", help="set logging to DEBUG", - action="store_const", dest="loglevel", - const=logging.DEBUG, default=logging.INFO) - - # JID and password options. - parser.add_argument("-j", "--jid", dest="jid", - help="JID to use") - parser.add_argument("-p", "--password", dest="password", - help="password to use") - - args = parser.parse_args() - - # Setup logging. - logging.basicConfig(level=args.loglevel, - format='%(levelname)-8s %(message)s') - - if args.jid is None: - args.jid = input("Username: ") - if args.password is None: - args.password = getpass("Password: ") - - # Setup the bot and register plugins. Note that while plugins may - # have interdependencies, the order in which you register them does - # not matter. - xmpp = Client(args.jid, args.password) - xmpp.connect() - xmpp.process() - - -if __name__ == '__main__': - main() diff --git a/about.py b/about.py deleted file mode 100644 index d696806..0000000 --- a/about.py +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -class Documentation: - - def about(): - return ('BukuBot' - '\n' - 'Jabber/XMPP Bookmark Manager' - '\n\n' - 'BukuBot is an XMPP bot that facilitates accessing and ' - 'managing bookmarks remotely.' - '\n\n' - 'BukuBot is written in Python' - '\n\n' - 'It is utilizing buku to handle bookmarks, and slixmpp to ' - 'communicate in the XMPP telecommunication network.' - '\n\n' - 'https://git.xmpp-it.net/sch/BukuBot' - '\n\n' - 'Copyright 2024 Schimon Jehudah Zackary' - '\n\n' - 'Made in Switzerland' - '\n\n' - 'πŸ‡¨πŸ‡­οΈ') - - def commands(): - return ("add URL [tag1,tag2,tag3,...]" - "\n" - " Bookmark URL along with comma-separated tags." - "\n\n" - "mod name " - "\n" - " Modify bookmark title." - "\n" - "mod note " - "\n" - " Modify bookmark description." - "\n" - "tag [+|-] [tag1,tag2,tag3,...]" - "\n" - " Modify bookmark tags. Appends or deletes tags, if flag tag " - "is preceded by \'+\' or \'-\' respectively." - "\n" - "del or " - "\n" - " Delete a bookmark by ID or URL." - "\n" - "\n" - "id " - "\n" - " Print a bookmark by ID." - "\n" - "last" - "\n" - " Print most recently bookmarked item." - "\n" - "tag " - "\n" - " Search bookmarks of given tag." - "\n" - "search " - "\n" - " Search bookmarks by a given search query." - "\n" - "search any " - "\n" - " Search bookmarks by a any given keyword." - # "\n" - # "regex" - # "\n" - # " Search bookmarks using Regular Expression." - "\n") - - def notice(): - return ('Copyright 2024 Schimon Jehudah Zackary' - '\n\n' - 'Permission is hereby granted, free of charge, to any person ' - 'obtaining a copy of this software and associated ' - 'documentation files (the β€œSoftware”), to deal in the ' - 'Software without restriction, including without limitation ' - 'the rights to use, copy, modify, merge, publish, distribute, ' - 'sublicense, and/or sell copies of the Software, and to ' - 'permit persons to whom the Software is furnished to do so, ' - 'subject to the following conditions:' - '\n\n' - 'The above copyright notice and this permission notice shall ' - 'be included in all copies or substantial portions of the ' - 'Software.' - '\n\n' - 'THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY ' - 'KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE ' - 'WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR ' - 'PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR ' - 'COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ' - 'LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR ' - 'OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ' - 'SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.') - diff --git a/config.py b/config.py deleted file mode 100644 index 7366f61..0000000 --- a/config.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import buku -import os -import sys - -class Configuration: - - def init_db(jid_bare): - filename = jid_bare + '.db' - data_dir = Configuration.get_db_directory() - pathname = data_dir + '/' + filename - bookmarks_db = buku.BukuDb(dbfile=pathname) - return bookmarks_db - - def get_db_directory(): - if os.environ.get('HOME'): - data_home = os.path.join(os.environ.get('HOME'), '.local', 'share') - return os.path.join(data_home, 'bukubot') - elif sys.platform == 'win32': - data_home = os.environ.get('APPDATA') - if data_home is None: - return os.path.join( - os.path.dirname(__file__) + '/bukubot_data') - else: - return os.path.join(os.path.dirname(__file__) + '/bukubot_data') diff --git a/documentation/screenshots/adhoc_add.jpg b/documentation/screenshots/adhoc_add.jpg deleted file mode 100644 index 08e95fa..0000000 Binary files a/documentation/screenshots/adhoc_add.jpg and /dev/null differ diff --git a/documentation/screenshots/adhoc_browse.jpg b/documentation/screenshots/adhoc_browse.jpg deleted file mode 100644 index 36abaf7..0000000 Binary files a/documentation/screenshots/adhoc_browse.jpg and /dev/null differ diff --git a/documentation/screenshots/adhoc_commands.jpg b/documentation/screenshots/adhoc_commands.jpg deleted file mode 100644 index 2135385..0000000 Binary files a/documentation/screenshots/adhoc_commands.jpg and /dev/null differ diff --git a/documentation/screenshots/adhoc_edit.jpg b/documentation/screenshots/adhoc_edit.jpg deleted file mode 100644 index 0d68830..0000000 Binary files a/documentation/screenshots/adhoc_edit.jpg and /dev/null differ diff --git a/documentation/screenshots/adhoc_search.jpg b/documentation/screenshots/adhoc_search.jpg deleted file mode 100644 index d4bcf03..0000000 Binary files a/documentation/screenshots/adhoc_search.jpg and /dev/null differ diff --git a/documentation/screenshots/chat_search.jpg b/documentation/screenshots/chat_search.jpg deleted file mode 100644 index f8300fa..0000000 Binary files a/documentation/screenshots/chat_search.jpg and /dev/null differ diff --git a/log.py b/log.py deleted file mode 100644 index 12d201b..0000000 --- a/log.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" - -To use this class, first, instantiate Logger with the name of your module -or class, then call the appropriate logging methods on that instance. - -logger = Logger(__name__) -logger.debug('This is a debug message') - -""" - -import logging - -class Logger: - - def __init__(self, name): - self.logger = logging.getLogger(name) - self.logger.setLevel(logging.WARNING) - - ch = logging.StreamHandler() - ch.setLevel(logging.WARNING) - - formatter = logging.Formatter('[%(asctime)s] %(levelname)s: %(name)s: %(message)s') - ch.setFormatter(formatter) - - self.logger.addHandler(ch) - - def critical(self, message): - self.logger.critical(message) - - def debug(self, message): - self.logger.debug(message) - - def error(self, message): - self.logger.error(message) - - def info(self, message): - self.logger.info(message) - - def warning(self, message): - self.logger.warning(message) - - # def check_difference(function_name, difference): - # if difference > 1: - # Logger.warning(message) diff --git a/version.py b/version.py deleted file mode 100644 index 05585a8..0000000 --- a/version.py +++ /dev/null @@ -1,2 +0,0 @@ -__version__ = '0.0.3' -__version_info__ = (0, 0, 3) diff --git a/xmpp/chat.py b/xmpp/chat.py deleted file mode 100644 index 3884be3..0000000 --- a/xmpp/chat.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -from bukubot.about import Documentation -from bukubot.config import Configuration - -try: - import tomllib -except: - import tomli as tomllib - - -class Chat: - - def action(self, message): - """ - Process incoming message stanzas. Be aware that this also - includes MUC messages and error messages. It is usually - a good idea to check the messages's type before processing - or sending replies. - - Arguments: - message -- The received message stanza. See the documentation - for stanza objects and the Message stanza to see - how it may be used. - """ - jid_bare = message['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - if message['type'] in ('chat', 'normal'): - message_text = " ".join(message['body'].split()) - message_lowercase = message_text.lower() - match message_lowercase: - case 'help': - message_body = '```\n' + Documentation.commands() + '\n```' - case _ if message_lowercase.startswith('add '): - message_lowercase_split = message_lowercase[4:].split(' ') - link = message_lowercase_split[0] - tags = ' '.join(message_lowercase_split[1:]) - tags = tags.replace(' ,', ',') - tags = tags.replace(', ', ',') - idx = bookmarks_db.get_rec_id(link) - if idx: - message_body = '*URL already exists.*' - else: - idx = bookmarks_db.add_rec(url=link, tags_in=tags) - message_body = ('*New bookmark has been added as {}.*' - .format(idx)) - case _ if message_lowercase.startswith('id'): - idx = message_lowercase[2:] - result = bookmarks_db.get_rec_by_id(idx) - message_body = Chat.format_message(result, extended=True) - case 'last': - idx = bookmarks_db.get_max_id() - result = bookmarks_db.get_rec_by_id(idx) - message_body = Chat.format_message(result) - case _ if message_lowercase.startswith('search any '): - query = message_lowercase[11:] - query = query.split(' ') - results = bookmarks_db.searchdb(query, - all_keywords=False, - deep=True, - regex=False) - message_body = '*Results for query: {}*\n\n'.format(query) - for result in results: - message_body += Chat.format_message(result) + '\n\n' - message_body += '*Total of {} results*'.format(len(results)) - case _ if message_lowercase.startswith('search '): - query = message_lowercase[7:] - query = query.split(' ') - results = bookmarks_db.searchdb(query, - all_keywords=True, - deep=True, - regex=False) - message_body = '*Results for query: {}*\n\n'.format(query) - for result in results: - message_body += Chat.format_message(result) + '\n\n' - message_body += '*Total of {} results*\n\n'.format(len(results)) - # elif message.startswith('regex'): - # message_body = bookmark_regexp(message[7:]) - case _ if message_lowercase.startswith('del '): - val = message_lowercase[4:] - try: - idx = int(val) - except: - idx = bookmarks_db.get_rec_id(val) - bookmark = bookmarks_db.get_rec_by_id(idx) - message_body = Chat.format_message(bookmark, extended=True) if bookmark else '' - result = bookmarks_db.delete_rec(idx) - if result: - message_body += '\n*Bookmark has been deleted.*' - else: - message_body += '\n*No action has been taken for index {}*'.format(idx) - case _ if message_lowercase.startswith('mod '): - message_lowercase_split = message_lowercase[4:].split(' ') - if len(message_lowercase_split) > 2: - arg = message_lowercase_split[0] - val = message_lowercase_split[1] - new = ' '.join(message_lowercase_split[2:]) - message_body = '' - try: - idx = int(val) - except: - idx = bookmarks_db.get_rec_id(val) - match arg: - case 'name': - result = bookmarks_db.update_rec(idx, title_in=new) - case 'note': - result = bookmarks_db.update_rec(idx, desc=new) - case _: - result = None - message_body = ('*Invalid argument. ' - 'Must be "name" or "note".*\n') - bookmark = bookmarks_db.get_rec_by_id(idx) - message_body += Chat.format_message(bookmark, extended=True) if bookmark else '' - if result: - message_body += '\n*Bookmark has been deleted.*' - else: - message_body += '\n*No action has been taken for index {}*'.format(idx) - else: - message_body = ('Missing argument. ' - 'Require three arguments: ' - '(1) "name" or "note"; ' - '(2) or ; ' - '(3) .') - case _ if (message_lowercase.startswith('tag +') or - message_lowercase.startswith('tag -')): - message_lowercase_split = message_lowercase[4:].split(' ') - if len(message_lowercase_split) > 2: - arg = message_lowercase_split[0] - val = message_lowercase_split[1] - try: - idx = int(val) - except: - idx = bookmarks_db.get_rec_id(val) - # tag = ',' + ' '.join(message_lowercase_split[2:]) + ',' - # tag = ' '.join(message_lowercase_split[2:]) - tag = arg + ',' + ' '.join(message_lowercase_split[2:]) - tag = tag.replace(' ,', ',') - tag = tag.replace(', ', ',') - result = bookmarks_db.update_rec(idx, tags_in=tag) - bookmark = bookmarks_db.get_rec_by_id(idx) - if result: - message_body = Chat.format_message(bookmark, extended=True) if bookmark else '' - message_body += '\n*Bookmark has been updated.*' - else: - message_body = '\n*No action has been taken for index {}*'.format(idx) - else: - message_body = ('Missing argument. ' - 'Require three arguments: ' - '(1) + or - sign; ' - '(2) or ; ' - '(3) .') - case _ if message_lowercase.startswith('tag'): - tag = message_lowercase[4:] - results = bookmarks_db.search_by_tag(tag) - message_body = '*Results for tag: {}*\n\n'.format(tag) - for result in results: - message_body += Chat.format_message(result) + '\n\n' - message_body += '*Total of {} results*'.format(len(results)) - case _: - message_body = ('Unknown command. Send "help" for list ' - 'of commands.') - message.reply(message_body).send() - #message.reply("Thanks for sending\n%(body)s" % message).send() - - def format_message(bookmark, extended=False): - # idx = bookmark.id - # url = bookmark.url - # name = bookmark.title if bookmark.title else 'Untitled' - # desc = bookmark.desc if bookmark.desc else 'No comment' - idx = bookmark[0] - url = bookmark[1] - name = bookmark[2] if bookmark[2] else 'Untitled' - desc = bookmark[4] if bookmark[4] else None - # rec = '\n πŸ”–οΈ {} [{}]\n πŸ”—οΈ {}\n 🏷️ {}'.format(title, index, link, tags) - if extended: - tags = '' if bookmark.tags_raw == ',' else ", ".join(bookmark.tags_raw.split(","))[2:-2] - tags = tags if tags else 'No tags' - message_body = ('{}. {}\n{}\n{}\n{}'.format(idx, name, url, desc, tags)) - else: - message_body = ('{}. {}\n{}'.format(idx, name, url)) - return message_body diff --git a/xmpp/client.py b/xmpp/client.py deleted file mode 100644 index f704dbb..0000000 --- a/xmpp/client.py +++ /dev/null @@ -1,698 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -import slixmpp -from bukubot.xmpp.chat import Chat -from bukubot.config import Configuration -from bukubot.about import Documentation - -from bukubot.log import Logger -from bukubot.version import __version__ - -try: - import tomllib -except: - import tomli as tomllib - - -# time_now = datetime.now() -# time_now = time_now.strftime("%H:%M:%S") - -# def print_time(): -# # return datetime.now().strftime("%H:%M:%S") -# now = datetime.now() -# current_time = now.strftime("%H:%M:%S") -# return current_time - -logger = Logger(__name__) - -class Client(slixmpp.ClientXMPP): - - """ - bukubot - Bookmark manager chat bot for Jabber/XMPP. - bukubot is a bookmark manager bot based on buku and slixmpp. - """ - - def __init__(self, jid, password): - slixmpp.ClientXMPP.__init__(self, jid, password) - - print('client') - - self.register_plugin('xep_0030') # Service Discovery - self.register_plugin('xep_0004') # Data Forms - self.register_plugin('xep_0060') # Publish-Subscribe - self.register_plugin('xep_0050') # Ad-Hoc Commands - self.register_plugin('xep_0115') # Entity Capabilities - self.register_plugin('xep_0122') # Data Forms Validation - self.register_plugin('xep_0199') # XMPP Ping - - # Connect to the XMPP server and start processing XMPP stanzas. - # self.connect() - # self.process() - - # The session_start event will be triggered when - # the bot establishes its connection with the server - # and the XML streams are ready for use. We want to - # listen for this event so that we we can initialize - # our roster. - self.add_event_handler("session_start", self.process_session_start) - - # The message event is triggered whenever a message - # stanza is received. Be aware that that includes - # MUC messages and error messages. - self.add_event_handler("message", self.process_message) - self.add_event_handler("disco_info", self.process_disco_info) - - async def process_session_start(self, event): - """ - Process the session_start event. - - Typical actions for the session_start event are - requesting the roster and broadcasting an initial - presence stanza. - - Arguments: - event -- An empty dictionary. The session_start - event does not provide any additional - data. - """ - self.command_list() - self.send_presence() - # await self.get_roster() - await self['xep_0115'].update_caps() - - async def process_disco_info(self, DiscoInfo): - jid = DiscoInfo['from'] - await self['xep_0115'].update_caps(jid=jid) - # jid_bare = DiscoInfo['from'].bare - # self.bookmarks_db = buku.BukuDb(dbfile=jid_bare + '.db') - - def process_message(self, message): - Chat.action(self, message) - - def command_list(self): - self['xep_0050'].add_command(node='add', - name='πŸ”–οΈ Add', - handler=self._handle_add) - self['xep_0050'].add_command(node='random', - name='🎲️ Random', - handler=self._handle_random) - self['xep_0050'].add_command(node='modify', - name='πŸ“‘οΈ Browse', - handler=self._handle_browse) - self['xep_0050'].add_command(node='search', - name='πŸ”οΈ Search', - handler=self._handle_search) - # self['xep_0050'].add_command(node='tag', - # name='🏷️ Tags', - # handler=self._handle_tag) - # self['xep_0050'].add_command(node='statistics', - # name='πŸ“ŠοΈ Statistics', - # handler=self._handle_stats) - self['xep_0050'].add_command(node='help', - name='πŸ“”οΈ Help', - handler=self._handle_help) - self['xep_0050'].add_command(node='license', - name='βœ’οΈ License', - handler=self._handle_license) - self['xep_0050'].add_command(node='about', - name='πŸ“œοΈ About', - handler=self._handle_about) - - def _handle_add(self, iq, session): - # jid = session['from'].bare - # jid_file = jid - # db_file = config.get_pathname_to_database(jid_file) - form = self['xep_0004'].make_form('form', 'Add') - form['instructions'] = 'Add a new bookmark' - form.add_field(desc='URL to bookmark.', - ftype='text-single', - label='URL', - required=True, - var='url') - form.add_field(desc='Title to add manually.', - ftype='text-single', - label='Title', - var='title') - form.add_field(desc='Description of the bookmark.', - ftype='text-multi', - label='Note', - var='note') - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - var='tag') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - var='immutable') - session['has_next'] = True - session['next'] = self._handle_edit_single - session['payload'] = form - return session - - def _handle_edit_single(self, payload, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - form = self['xep_0004'].make_form('form', 'Edit') - form['instructions'] = 'Edit bookmark' - url = payload['values']['url'] - idx = bookmarks_db.get_rec_id(url) - if not idx: - immu = payload['values']['immutable'] - desc = payload['values']['note'] - tags = payload['values']['tag'] - name = payload['values']['title'] - fetch = True if not name else False - idx = bookmarks_db.add_rec(desc=desc, - fetch=fetch, - immutable=immu, - tags_in=tags, - url=url) - bookmark = bookmarks_db.get_rec_by_id(idx) - form.add_field(ftype='text-single', - label='ID #', - value=str(idx)) - form.add_field(ftype='text-single', - label='Title', - value=bookmark[2]) - form.add_field(ftype='text-single', - label='URL', - value=bookmark[1]) - form.add_field(ftype='text-multi', - label='Note', - value=bookmark[4]) - options = form.add_field(ftype='list-multi', - label='Tags') - for tag in bookmark[3].split(','): - options.addOption(tag, tag) - form.add_field(ftype='boolean', - label='Immutable', - value=str(bookmark[5])) - session['allow_complete'] = True - session['has_next'] = False - session['next'] = None - session['payload'] = form - return session - - def _handle_browse(self, iq, session): - form = self['xep_0004'].make_form('form', 'Browse') - form['instructions'] = 'Browse bookmark' - options = form.add_field(desc='Items per page.', - label='Items', - ftype='list-single', - value='20', - var='limit') - i = 10 - while i <= 50: - x = str(i) - options.addOption(x, x) - i += 10 - # options['validate']['datatype'] = 'xs:integer' - # options['validate']['range'] = { 'minimum': 10, 'maximum': 50 } - form.add_field(ftype='hidden', - value='0', - var='count') - session['has_next'] = True - session['next'] = self._handle_browse_all - session['payload'] = form - return session - - def _handle_tag(self, iq, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - form = self['xep_0004'].make_form('form', 'Tags') - form['instructions'] = ('Select tags to browse') - options = form.add_field(desc='Select tag to list its items.', - ftype='list-single', - label='Tags', - var='tag') - tags = bookmarks_db.get_tag_all() - counter = 0 - for tag in tags[0]: - if counter == 100: break - options.addOption(tag, tag) - counter += 1 - session['has_next'] = True - session['next'] = self._handle_browse_all - session['payload'] = form - return session - - def _handle_browse_all(self, payload, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - vals = payload['values'] - if 'url' in vals and vals['url']: - act = vals['action'] - url = vals['url'] - form = self['xep_0004'].make_form('form', 'Edit') - match act: - case 'edit': - if len(url) > 1: - form['instructions'] = 'Modify bookmarks' - idxs = '' - tags = '' - for i in url: - idx = bookmarks_db.get_rec_id(i) - idxs += ',' + str(idx) - bookmark = bookmarks_db.get_rec_by_id(idx) - tags += bookmark[3] - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - value=bookmark[3], - var='tags_new') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - value=True, - var='immutable') - form.add_field(ftype='hidden', - value=idxs, - var='ids') - # session['next'] = self._handle_edit_single(payload, session) - else: - form['instructions'] = 'Modify bookmark' - idx = bookmarks_db.get_rec_id(url[0]) - bookmark = bookmarks_db.get_rec_by_id(idx) - form.add_field(ftype='fixed', - label='ID #', - value=str(idx), - var='id') - form.add_field(ftype='text-single', - label='Title', - value=bookmark[2], - var='title') - form.add_field(ftype='text-single', - label='URL', - value=bookmark[1], - var='url') - form.add_field(ftype='text-multi', - label='Note', - value=bookmark[4], - var='description') - form.add_field(ftype='hidden', - value=bookmark[3], - var='tags_old') - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - value=bookmark[3], - var='tags_new') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - value=str(bookmark[5]), - var='immutable') - case 'remove': - form['instructions'] = ('The following items were deleted from ' - 'bookmarks.\nProceed to finish or ' - 'select items to restore.') - options = form.add_field(desc='Select items to restore', - ftype='list-multi', - label='Deleted items', - var='url') - for i in url: - idx = bookmarks_db.get_rec_id(i) - rec = bookmarks_db.get_rec_by_id(idx) - bookmarks_db.delete_rec(idx) - options.addOption(rec.title, i) - session['cancel'] = self._handle_cancel - # session['allow_complete'] = True - session['has_next'] = True - session['next'] = self._handle_action_result - session['payload'] = form - else: - limit = vals['limit'] if 'limit' in vals else 0 - if isinstance(limit, list): limit = limit[0] - count = vals['count'] if 'count' in vals else 0 - if isinstance(count, list): count = count[0] - form = self['xep_0004'].make_form('form', 'Browse') - form['instructions'] = ('Select bookmarks to modify') - options = form.add_field(desc='Select an action', - ftype='list-single', - label='Action', - required=True, - value='edit', - var='action') - options.addOption('Edit', 'edit') - options.addOption('Remove', 'remove') - options = form.add_field(desc='Selection of several bookmarks will ' - 'only allow to modify tags.', - ftype='list-multi', - label='Bookmark', - var='url') - bookmarks = bookmarks_db.get_rec_all() - # bookmarks = sorted(bookmarks, key=lambda x: x.title) - counter = int(count) - limiter = counter + int(limit) - for bookmark in bookmarks[counter:limiter]: - if counter == limiter: break - options.addOption(bookmark[2], bookmark[1]) - counter += 1 - form.add_field(ftype='hidden', - value=str(counter), - var='count') - form.add_field(ftype='hidden', - value=str(limit), - var='limit') - session['has_next'] = True - session['next'] = self._handle_browse_all - session['payload'] = form - return session - - def _handle_action_result(self, payload, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - vals = payload['values'] - if 'id' in vals: - idx = vals['id'] - idx = int(idx) - tags_new = vals['tags_new'] - tags_new = tags_new.replace(' ,', ',') - tags_new = tags_new.replace(', ', ',') - tags_old = vals['tags_old'][0] - tags = tags_old.split(',') - tags_to_remove = '-,' - for tag in tags: - if tag not in tags_new: - tags_to_remove += ',' + tag - bookmarks_db.update_rec(idx, - url=vals['url'], - title_in=vals['title'], - tags_in='+,' + tags_new, - desc=vals['description'], - immutable=vals['immutable']) - bookmarks_db.update_rec(idx, - tags_in=tags_to_remove) - form = self['xep_0004'].make_form('result', 'Done') - rec = bookmarks_db.get_rec_by_id(idx) - form.add_field(ftype='text-single', - label='Title', - value=rec.title) - form.add_field(ftype='text-single', - label='URL', - value=rec.url) - form.add_field(ftype='text-single', - label='Note', - value=rec.desc) - form.add_field(ftype='text-single', - label='Tags', - value=rec.tags_raw) - form.add_field(ftype='text-single', - label='Immutable', - value=str(rec.flags)) - elif 'ids' in vals: - immutable = vals['immutable'] - tags_new = vals['tags_new'] - tags_new = tags_new.replace(' ,', ',') - tags_new = tags_new.replace(', ', ',') - idxs = vals['ids'].split(',') - for idx in idxs: - bookmarks_db.update_rec(idx, - tags_in='+,' + tags_new, - immutable=immutable) - form = self['xep_0004'].make_form('result', 'Done') - form.add_field(ftype='text-single', - label='Tags', - value=tags_new) - form.add_field(ftype='text-single', - label='Immutable', - value=immutable) - elif 'url' in vals: - url = vals['url'] - form = self['xep_0004'].make_form('result', 'Add') - form['instructions'] = ('The following items have been added to ' - 'the bookmarks\nNote: You will have to ' - 'manually tag these items, if you would.') - for i in url: - idx = bookmarks_db.add_rec(url=i) - rec = bookmarks_db.get_rec_by_id(idx) - form.add_field(ftype='fixed', - value=str(idx)) - form.add_field(ftype='text-single', - value=rec.title) - form.add_field(ftype='text-single', - value=rec.url) - session['allow_complete'] = True - session['has_next'] = False - session['next'] = None - session['payload'] = form - return session - - def _handle_random(self, iq, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - bookmarks = bookmarks_db.get_rec_all() - if bookmarks: - import random - bookmark = random.choice(bookmarks) - form = self['xep_0004'].make_form('form', 'Random') - form['instructions'] = 'Bookmark #{}'.format(bookmark[0]) - form.add_field(ftype='fixed', - # ftype='text-single', - label='URL', - # required=True, - value=bookmark[1], - var='url') - form.add_field(ftype='text-single', - label='Title', - value=bookmark[2], - var='title') - form.add_field(ftype='text-multi', - label='Note', - value=bookmark[4], - var='note') - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - value=bookmark[3], - var='tag') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - value=str(bookmark[5]), - var='immutable') - session['has_next'] = True - session['next'] = self._handle_edit_single - session['payload'] = form - else: - text_note = ('There are no bookmarks, yet.') - session['notes'] = [['info', text_note]] - return session - - def _handle_search(self, iq, session): - form = self['xep_0004'].make_form('form', 'Search') - form['instructions'] = 'Search for bookmarks' - form.add_field(desc='Enter a search term to query.', - ftype='text-single', - label='Search', - var='query') - options = form.add_field(desc='Select type of search.', - ftype='list-single', - label='Search by', - value='any', - var='type') - options.addOption('All keywords', 'all') - options.addOption('Any keyword', 'any') - options.addOption('Tag', 'tag') - form.add_field(desc='Search for matching substrings.', - ftype='boolean', - label='Deep', - value=True, - var='deep') - form.add_field(desc='Match a regular expression.', - ftype='boolean', - label='Regular Expression', - var='regex') - session['allow_prev'] = False - session['has_next'] = True - session['next'] = self._handle_search_result - session['payload'] = form - session['prev'] = None - return session - - def _handle_search_result(self, payload, session): - jid_bare = session['from'].bare - bookmarks_db = Configuration.init_db(jid_bare) - vals = payload['values'] - if 'url' in vals and vals['url']: - act = vals['action'] - url = vals['url'] - form = self['xep_0004'].make_form('form', 'Edit') - match act: - case 'edit': - if len(url) > 1: - form['instructions'] = 'Modify bookmarks' - idxs = '' - tags = '' - for i in url: - idx = bookmarks_db.get_rec_id(i) - idxs += ',' + str(idx) - bookmark = bookmarks_db.get_rec_by_id(idx) - tags += bookmark[3] - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - value=bookmark[3], - var='tags_new') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - value=True, - var='immutable') - form.add_field(ftype='hidden', - value=idxs, - var='ids') - # session['next'] = self._handle_edit_single(payload, session) - else: - form['instructions'] = 'Modify bookmark' - idx = bookmarks_db.get_rec_id(url[0]) - bookmark = bookmarks_db.get_rec_by_id(idx) - form.add_field(ftype='fixed', - label='ID #', - value=str(idx), - var='id') - form.add_field(ftype='text-single', - label='Title', - value=bookmark[2], - var='title') - form.add_field(ftype='text-single', - label='URL', - value=bookmark[1], - var='url') - form.add_field(ftype='text-multi', - label='Note', - value=bookmark[4], - var='description') - form.add_field(ftype='hidden', - value=bookmark[3], - var='tags_old') - form.add_field(desc='Comma-separated tags.', - ftype='text-single', - label='Tags', - value=bookmark[3], - var='tags_new') - form.add_field(desc='Check to disable automatic title fetch.', - ftype='boolean', - label='Immutable', - value=str(bookmark[5]), - var='immutable') - case 'remove': - form['instructions'] = ('The following items were deleted from ' - 'bookmarks.\nProceed to finish or ' - 'select items to restore.') - options = form.add_field(desc='Select items to restore', - ftype='list-multi', - label='Deleted items', - var='url') - for i in url: - idx = bookmarks_db.get_rec_id(i) - rec = bookmarks_db.get_rec_by_id(idx) - bookmarks_db.delete_rec(idx) - options.addOption(rec.title, i) - session['cancel'] = self._handle_cancel - # session['allow_complete'] = True - session['has_next'] = True - session['next'] = self._handle_action_result - session['payload'] = form - else: - count = vals['count'] if 'count' in vals else 0 - if isinstance(count, list): count = count[0] - # count = count if count else 0 - query = vals['query'] - if isinstance(query, list): query = query[0] - stype = vals['type'] - if isinstance(stype, list): stype = stype[0] - deep = vals['deep'] - if isinstance(deep, list): deep = deep[0] - deep = True if '1' else False - regex = vals['regex'] - if isinstance(regex, list): regex = regex[0] - regex = True if '1' else False - match stype: - case 'all': - bookmarks = bookmarks_db.searchdb(query, - all_keywords=True, - deep=deep, - regex=regex) - case 'any': - bookmarks = bookmarks_db.searchdb(query, - all_keywords=False, - deep=deep, - regex=regex) - case 'tag': - bookmarks = bookmarks_db.search_by_tag(query) - # bookmarks = sorted(bookmarks, key=lambda x: x.title) - if bookmarks: - form = self['xep_0004'].make_form('form', 'Browse') - form['instructions'] = ('Select bookmarks to modify') - options = form.add_field(desc='Select an action', - ftype='list-single', - label='Action', - required=True, - value='edit', - var='action') - options.addOption('Edit', 'edit') - options.addOption('Remove', 'remove') - options = form.add_field(desc='Selection of several bookmarks ' - 'will only allow to modify tags.', - ftype='list-multi', - label='Bookmark', - var='url') - counter = int(count) - limiter = counter + 10 - for bookmark in bookmarks[counter:limiter]: - if counter == limiter: break - options.addOption(bookmark[2], bookmark[1]) - counter += 1 - form.add_field(ftype='hidden', - value=str(counter), - var='count') - form.add_field(ftype='hidden', - value=query, - var='query') - form.add_field(ftype='hidden', - value=stype, - var='type') - deep = '1'if deep else '' - form.add_field(ftype='hidden', - value=deep, - var='deep') - regex = '1'if regex else '' - form.add_field(ftype='hidden', - value=regex, - var='regex') - session['has_next'] = True - session['next'] = self._handle_search_result - session['payload'] = form - else: - text_note = 'No results were yielded for: {}'.format(query) - session['notes'] = [['info', text_note]] - session['allow_prev'] = True - session['prev'] = self._handle_search - return session - - def _handle_cancel(self, payload, session): - text_note = ('Operation has been cancelled.' - '\n\n' - 'No action was taken.') - session['notes'] = [['info', text_note]] - return session - - def _handle_help(self, iq, session): - text_note = Documentation.commands() - session['notes'] = [['info', text_note]] - return session - - def _handle_license(self, iq, session): - text_note = Documentation.notice() - session['notes'] = [['info', text_note]] - return session - - def _handle_about(self, iq, session): - text_note = Documentation.about() - session['notes'] = [['info', text_note]] - return session - -