diff --git a/css/stylesheet.css b/css/stylesheet.css index dbc74f1..9450ea1 100644 --- a/css/stylesheet.css +++ b/css/stylesheet.css @@ -198,6 +198,12 @@ label, text-transform: uppercase; } +#action > a, +#action-bar > a { + padding-left: 1em; + padding-right: 1em; +} + #number-of-pages .inactive { background: #7a7a7a; } diff --git a/fasi.py b/fasi.py index ac670ea..e8b2e8d 100644 --- a/fasi.py +++ b/fasi.py @@ -91,7 +91,7 @@ class HttpInstance: #try: if True: - exception = jid_detail = messages_10 = note = node_title = \ + exception = jid_vcard = messages_10 = note = node_title = \ node_note = number_of_pages = page_number = previous = \ selection = services_sorted = subject = None node_name = 'urn:xmpp:microblog:0' @@ -102,54 +102,54 @@ class HttpInstance: filename = 'details/{}.toml'.format(jid_bare) if os.path.exists(filename) and os.path.getsize(filename) > 0: jid_details = Data.open_file_toml(filename) - action = jid_details['action'] - count = jid_details['count'] - instance = jid_details['instance'] - jid_info = { - 'error' : jid_details['error'], - 'text' : jid_details['error_text'], - 'condition' : jid_details['error_condition']} - jid_kind = jid_details['kind'] - link_href = jid_details['link_href'] - messages = jid_details['messages'] - nodes = jid_details['nodes'] - note = jid_details['note'] - title = jid_details['name'] - xmpp_uri = jid_details['uri'] - view_href = jid_details['view_href'] else: - jid_data = await FileUtilities.cache_jid_data(jabber_id, password, jid_bare, node_name, alias=alias) - count = jid_data['count'] - jid_detail = jid_data['jid_detail'] - jid_info = jid_data['jid_info'] - jid_kind = jid_data['jid_kind'] - jid_details = jid_data['jid_details'] - note = jid_data['note'] - title = jid_data['title'] - - # Group chat messages - # NOTE TODO - page_number = request.query_params.get('page', '') - if page_number: - try: - page_number = int(page_number) - ix = (page_number -1) * 10 - except: - ix = 0 - page_number = 1 - else: + jid_details = await FileUtilities.cache_jid_data( + jabber_id, password, jid_bare, node_name, alias=alias) + + action = jid_details['action'] + count = jid_details['count'] + instance = jid_details['instance'] + items = jid_details['items'] + jid_info = { + 'error' : jid_details['error'], + 'text' : jid_details['error_text'], + 'condition' : jid_details['error_condition']} + jid_kind = jid_details['kind'] + jid_vcard = { + 'name' : jid_details['name'], + 'note' : jid_details['note'], + 'type' : jid_details['image_type']} + link_href = jid_details['link_href'] + messages = jid_details['messages'] + nodes = jid_details['nodes'] + note = jid_details['note'] + title = jid_details['name'] + xmpp_uri = jid_details['uri'] + view_href = jid_details['view_href'] + + # Group chat messages + # NOTE TODO + page_number = request.query_params.get('page', '') + if page_number: + try: + page_number = int(page_number) + ix = (page_number -1) * 10 + except: ix = 0 page_number = 1 - messages_10 = messages[ix:][:10] - number_of_pages = int(len(messages) / 10) - if number_of_pages < len(messages) / 10: number_of_pages += 1 + else: + ix = 0 + page_number = 1 + messages_10 = messages[ix:][:10] + number_of_pages = int(len(messages) / 10) + if number_of_pages < len(messages) / 10: number_of_pages += 1 # Query URI links action, instance, link_href, links, node_name, view_href, xmpp_uri = XmppUtilities.set_query_uri_link( jid_bare, jid_info, jid_kind, node_name) # Graphic files - filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_detail) + filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_vcard) #except Exception as e: else: @@ -157,7 +157,9 @@ class HttpInstance: action = 'Error' title = 'Slixmpp error' xmpp_uri = note = jid - filename = jid_bare = link_href = link_tex = node_note = node_title = number_of_pages = page_number = previous = selection = services = services_sorted = url = None + filename = jid_bare = link_href = link_tex = node_note = \ + node_title = number_of_pages = page_number = previous = \ + selection = services = services_sorted = url = None #if title == 'remote-server-timeout': # raise HTTPException(status_code=408, detail='remote-server-timeout') @@ -201,109 +203,123 @@ class HttpInstance: #try: if True: - entries = exception = jid_detail = note = node_note = \ - number_of_pages = page_number = previous = selection = \ - services_sorted = None + entries = [] + exception = jid_vcard = note = node_note = number_of_pages = \ + page_number = previous = selection = services_sorted = None node_title = node_name - link_href = 'xmpp:{}?pubsub;node={};action=subscribe'.format(jid_bare, node_name) + link_href = 'xmpp:{}?pubsub;node={};action=subscribe'.format( + jid_bare, node_name) link_text = 'Subscribe' xmpp_uri = '{}?;node={}'.format(jid_bare, node_name) filename = 'details/{}.toml'.format(jid_bare) if os.path.exists(filename) and os.path.getsize(filename) > 0: jid_details = Data.open_file_toml(filename) - action = jid_details['action'] - count = jid_details['count'] - instance = jid_details['instance'] - jid_info = { - 'error' : jid_details['error'], - 'text' : jid_details['error_text'], - 'condition' : jid_details['error_condition']} - jid_kind = jid_details['kind'] - link_href = jid_details['link_href'] - messages = jid_details['messages'] - nodes = jid_details['nodes'] - note = jid_details['note'] - title = jid_details['name'] - xmpp_uri = jid_details['uri'] - view_href = jid_details['view_href'] - if node_name not in nodes: - node_item_ids = await XmppXep0060.get_node_item_ids(xmpp_instance, jid_bare, node_name) - if isinstance(node_item_ids, stanza.iq.Iq): - nodes[node_name] = node_item_ids['disco_items']['items'] else: - jid_data = await FileUtilities.cache_jid_data(jabber_id, password, jid_bare, node_name, item_id) - count = jid_data['count'] - jid_detail = jid_data['jid_detail'] - jid_info = jid_data['jid_info'] - jid_kind = jid_data['jid_kind'] - jid_details = jid_data['jid_details'] - note = jid_data['note'] - title = jid_data['title'] + jid_details = await FileUtilities.cache_jid_data( + jabber_id, password, jid_bare, node_name, item_id) - # Node items - # NOTE TODO - # page_number = request.query_params.get('page', '') - # if page_number: - # try: - # page_number = int(page_number) - # ix = (page_number -1) * 10 - # except: - # ix = 0 - # page_number = 1 - # else: - # ix = 0 - # page_number = 1 - # item_ids_10 = item_ids[ix:][:10] + action = jid_details['action'] + count = jid_details['count'] + instance = jid_details['instance'] + items = jid_details['items'] + jid_info = { + 'error' : jid_details['error'], + 'text' : jid_details['error_text'], + 'condition' : jid_details['error_condition']} + jid_kind = jid_details['kind'] + jid_vcard = { + 'name' : jid_details['name'], + 'note' : jid_details['note'], + 'type' : jid_details['image_type']} + link_href = jid_details['link_href'] + messages = jid_details['messages'] + nodes = jid_details['nodes'] + note = jid_details['note'] + title = jid_details['name'] + xmpp_uri = jid_details['uri'] + view_href = jid_details['view_href'] - # if item_id: - # previous = True - # node_items = await XmppXep0060.get_node_items(xmpp_instance, jid_bare, node_name, item_ids=[item_id]) - # else: - # node_items = await XmppXep0060.get_node_items(xmpp_instance, jid_bare, node_name, item_ids=item_ids_10) - # number_of_pages = int(len(item_ids) / 10) - # if number_of_pages < len(item_ids) / 10: number_of_pages += 1 + xmpp_instance = XmppInstance(jabber_id, password, jid_bare) + xmpp_instance.connect() - # if not node_items: - # action = 'Warning' - # node_title = jid_info['condition'] - # node_note = jid_info['text'] - # services = services_sorted = None - # elif isinstance(node_items, IqTimeout): - # action = 'Warning' - # node_title = 'Timeout' - # node_note = 'Timeout error' - # services = services_sorted = None - # elif isinstance(node_items, IqError): - # action = 'Warning' - # breakpoint() - # node_title = node_items['condition'] - # node_note = node_items['text'] - # services = services_sorted = None - # else: - # if 'items' in node_item_ids['disco_items']: - # for item_id in node_item_ids['disco_items']['items']: - # item_ids.append(item_id[2]) - # # NOTE Consider to skip the reversal of order, because, then, items can be found at the same page. - # item_ids.reverse() - # nodes[node_name] = item_ids - #title = title or node_name - # if not node_title: node_title = node_name - # node_note = jid_bare - # for item in node_items['pubsub']['items']: - # item_payload = item['payload'] - # entry = Syndication.extract_items(item_payload) - # if entry: entry['id'] = item['id'] - # entries.append(entry) - # #if len(entries) > 10: break - # if entries: entries.reverse() + # Node item IDs + if node_name not in nodes: + nodes[node_name] = {} + node_item_ids = await XmppXep0060.get_node_item_ids( + xmpp_instance, jid_bare, node_name) + #node_item_ids = await XmppUtilities.get_item_ids_of_node( + # jabber_id, password, jid_bare, node_name, nodes) + if isinstance(node_item_ids['iq'], stanza.iq.Iq): + nodes[node_name]['count'] = len(node_item_ids['iq']['disco_items']['items']) + nodes[node_name]['item_ids'] = [] + for item in node_item_ids['iq']['disco_items']['items']: + nodes[node_name]['item_ids'].append( + [item[0] or '', item[1] or '', item[2] or '']) + + # Node items + if item_id: + previous = True + node_items = await XmppXep0060.get_node_items( + xmpp_instance, jid_bare, node_name, item_ids=[item_id]) + else: + item_ids = [] + for item in nodes[node_name]['item_ids']: + item_ids.append(item[2]) + # NOTE Consider to neglect the reversal of order, because, then, items can be found at the same page. + item_ids.reverse() + page_number = request.query_params.get('page', '') + if page_number: + try: + page_number = int(page_number) + ix = (page_number -1) * 10 + except: + ix = 0 + page_number = 1 + else: + ix = 0 + page_number = 1 + item_ids_10 = item_ids[ix:][:10] + number_of_pages = int(len(item_ids) / 10) + if number_of_pages < len(item_ids) / 10: number_of_pages += 1 + node_items = await XmppXep0060.get_node_items( + xmpp_instance, jid_bare, node_name, item_ids=item_ids_10) + if not node_items: + action = 'Warning' + node_title = jid_info['condition'] + node_note = jid_info['text'] + services = services_sorted = None + elif isinstance(node_items, IqTimeout): + action = 'Warning' + node_title = 'Timeout' + node_note = 'Timeout error' + services = services_sorted = None + elif isinstance(node_items, IqError): + action = 'Warning' + breakpoint() + node_title = node_items['condition'] + node_note = node_items['text'] + services = services_sorted = None + else: + #title = title or node_name + if not node_title: node_title = node_name + node_note = jid_bare + for item in node_items['pubsub']['items']: + item_payload = item['payload'] + entry = Syndication.extract_items(item_payload) + if entry: entry['id'] = item['id'] + entries.append(entry) + #if len(entries) > 10: break + if entries: entries.reverse() + + xmpp_instance.disconnect() # Query URI links action, instance, link_href, links, node_name, view_href, xmpp_uri = XmppUtilities.set_query_uri_link( jid_bare, jid_info, jid_kind, node_name, item_id) # Graphic files - filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_detail) + filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_vcard) #except Exception as e: else: @@ -479,7 +495,7 @@ class HttpInstance: #try: if True: - action = count = exception = instance = jid_detail = \ + action = count = exception = instance = jid_vcard = \ jid_info = link_href = message = note = selection = title = \ view_href = xmpp_uri = None #node_name = 'urn:xmpp:microblog:0' @@ -487,37 +503,45 @@ class HttpInstance: filename = 'details/{}.toml'.format(jid_bare) if os.path.exists(filename) and os.path.getsize(filename) > 0: jid_details = Data.open_file_toml(filename) - action = jid_details['action'] - count = jid_details['count'] - instance = jid_details['instance'] - jid_info = { - 'error' : jid_details['error'], - 'text' : jid_details['error_text'], - 'condition' : jid_details['error_condition']} - jid_kind = jid_details['kind'] - link_href = jid_details['link_href'] - messages = jid_details['messages'] - nodes = jid_details['nodes'] - note = jid_details['note'] - title = jid_details['name'] - xmpp_uri = jid_details['uri'] - view_href = jid_details['view_href'] else: - jid_data = await FileUtilities.cache_jid_data(jabber_id, password, jid_bare, node_name, alias=alias) - count = jid_data['count'] - jid_detail = jid_data['jid_detail'] - jid_info = jid_data['jid_info'] - jid_kind = jid_data['jid_kind'] - jid_details = jid_data['jid_details'] - note = jid_data['note'] - title = jid_data['title'] + jid_details = await FileUtilities.cache_jid_data( + jabber_id, password, jid_bare, node_name, alias=alias) + + # Set node name to 'urn:xmpp:microblog:0' + jid_kind = jid_details['kind'] + if jid_kind not in ('conference', 'mix', 'muc') and '@' in jid_bare and not node_name: + node_name = 'urn:xmpp:microblog:0' + + action = jid_details['action'] + nodes = jid_details['nodes'] + count = nodes[node_name]['count'] if node_name else jid_details['count'] + instance = jid_details['instance'] + items = jid_details['items'] + jid_info = { + 'error' : jid_details['error'], + 'text' : jid_details['error_text'], + 'condition' : jid_details['error_condition']} + jid_vcard = { + 'name' : jid_details['name'], + 'note' : jid_details['note'], + 'type' : jid_details['image_type']} + link_href = jid_details['link_href'] + messages = jid_details['messages'] + note = jid_details['note'] + title = jid_details['name'] + xmpp_uri = jid_details['uri'] + view_href = jid_details['view_href'] + + if node_name not in nodes: + nodes[node_name] = await XmppUtilities.get_item_ids_of_node( + jabber_id, password, jid_bare, node_name, nodes) # Query URI links action, instance, link_href, links, node_name, view_href, xmpp_uri = XmppUtilities.set_query_uri_link( jid_bare, jid_info, jid_kind, node_name) # Graphic files - filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_detail) + filename, filepath, filetype, selection = FileUtilities.handle_photo(jid_bare, jid_vcard) #except Exception as e: else: @@ -526,7 +550,7 @@ class HttpInstance: action = 'Error' title = 'Slixmpp error' xmpp_uri = jid - count = filename = jid_bare = jid_detail = jid_kind = links = \ + count = filename = jid_bare = jid_vcard = jid_kind = links = \ message = selection = url = None template_file = 'jid.xhtml' @@ -578,7 +602,7 @@ class HttpInstance: async def main_get(request: Request): jabber_id = request.query_params.get('jid', '') if jabber_id: - response = RedirectResponse(url='/' + jabber_id) + response = RedirectResponse(url='/j/' + jabber_id) else: template_file = 'main.xhtml' template_dict = { @@ -605,7 +629,7 @@ class FileUtilities: async def cache_jid_data(jabber_id, password, jid_bare, node_name=None, item_id=None, alias=None): count = title = '' - jid_detail = { + jid_vcard = { 'name' : '', 'note' : '', 'type' : '', @@ -642,7 +666,7 @@ class FileUtilities: conference_title = identity[3] break vcard_temp = vcard_data['iq']['vcard_temp'] - jid_detail = { + jid_vcard = { 'name' : vcard_temp['FN'] or conference_title or '', 'note' : vcard_temp['notes'] or node_id or '', 'type' : vcard_temp['PHOTO']['TYPE'] or '', @@ -654,24 +678,27 @@ class FileUtilities: iq = jid_items['iq'] iq_disco_items = iq['disco_items'] iq_disco_items_items = iq_disco_items['items'] - iq_disco_items_set = {''} - #iq_disco_items_list = [] + #iq_disco_items_set = {''} + iq_disco_items_list = [] iq_disco_items_items_list = [] for item in iq_disco_items_items: if jid_kind == 'muc': - iq_disco_items_set.update([item[2]]) - # iq_disco_items_list.append(item[1]) + #iq_disco_items_set.update([item[2]]) + iq_disco_items_list.append(item[2]) else: - iq_disco_items_set.update([item[1]]) + #iq_disco_items_set.update([item[1]]) + iq_disco_items_list.append(item[1]) iq_disco_items_items_list.append( [item[0] or '', item[1] or '', item[2] or '']) - count = len(iq_disco_items_set) + #count = len(iq_disco_items_set) + count = len(iq_disco_items_list) # Title print('Title') if jid_kind not in ('conference', 'mix', 'muc') and '@' in jid_bare: + # NOTE Variables node_name and node_title do not appear to be utilized. node_name = 'urn:xmpp:microblog:0' - title = node_title = 'Journal' + node_title = 'Journal' elif jid_kind == 'pubsub': category = 'unsorted' for item in iq_disco_items_items: @@ -692,8 +719,8 @@ class FileUtilities: print(jid_info) # String 'undefined' is sourced from JID discuss@conference.conversejs.org if not title: - if jid_detail['name'] and not 'undefined' in jid_detail['name']: - title = jid_detail['name'] + if jid_vcard['name'] and not 'undefined' in jid_vcard['name']: + title = jid_vcard['name'] else: title = jid_bare.split('@')[0] @@ -746,15 +773,15 @@ class FileUtilities: # Node items print('Node items') nodes = {} - nodes[node_name] = {} - if node_name and node_name in iq_disco_items_set: - #if node_name and node_name in iq_disco_items_list: + #if node_name and node_name in iq_disco_items_set: + if node_name and node_name in iq_disco_items_list: action = 'Browse' node_item_ids = await XmppXep0060.get_node_item_ids(xmpp_instance, jid_bare, node_name) - if isinstance(node_item_ids, stanza.iq.Iq): - nodes[node_name]['count'] = len(node_item_ids['disco_items']['items']) + if isinstance(node_item_ids['iq'], stanza.iq.Iq): + nodes[node_name] = {} + nodes[node_name]['count'] = len(node_item_ids['iq']['disco_items']['items']) nodes[node_name]['item_ids'] = [] - for item_id in node_item_ids['disco_items']['items']: + for item_id in node_item_ids['iq']['disco_items']['items']: nodes[node_name]['item_ids'].append( [item_id[0] or '', item_id[1] or '', item_id[2] or '']) @@ -762,13 +789,13 @@ class FileUtilities: # Notes print('Notes') - jid_detail_note = jid_detail['note'] - if isinstance(jid_detail_note, list) and len(jid_detail_note): - note = jid_detail_note[0]['NOTE'] + jid_vcard_note = jid_vcard['note'] + if isinstance(jid_vcard_note, list) and len(jid_vcard_note): + note = jid_vcard_note[0]['NOTE'] else: - note = jid_detail_note - #if not note and jid_detail['name'] and not 'undefined' in jid_detail['name'] and title != jid_detail['name']: - # note = jid_detail['name'] + note = jid_vcard_note + #if not note and jid_vcard['name'] and not 'undefined' in jid_vcard['name'] and title != jid_vcard['name']: + # note = jid_vcard['name'] jid_details = { 'action' : action or '', @@ -776,10 +803,11 @@ class FileUtilities: 'error' : jid_info['error'], 'error_text' : jid_info['text'] or '', 'error_condition' : jid_info['condition'] or '', - 'items' : iq_disco_items_items_list, - 'link_href' : link_href, + 'image_type' : jid_vcard['type'], 'instance' : instance or '', + 'items' : iq_disco_items_items_list, 'kind' : jid_kind or '', + 'link_href' : link_href, 'messages' : messages or '', 'name' : title, 'nodes' : nodes, @@ -792,19 +820,9 @@ class FileUtilities: filename = 'details/{}.toml'.format(jid_bare) Data.save_to_toml(filename, jid_details) - result = { - 'count' : nodes[node_name]['count'] if node_name else count or '', - 'jid_detail' : jid_detail, - 'jid_info' : jid_info, - 'jid_items' : jid_items, - 'jid_kind' : jid_kind, - 'jid_details' : jid_details, - 'note' : note, - 'title' : title} + return jid_details - return result - - def handle_photo(jid_bare, jid_detail): + def handle_photo(jid_bare, jid_vcard): filetype = selection = None filecirca = 'photo/{}.*'.format(jid_bare) filepath = glob.glob(filecirca) @@ -812,10 +830,10 @@ class FileUtilities: filepath = filepath[0] filetype = filepath.split('.').pop() filename = '{}.{}'.format(jid_bare, filetype) - elif jid_detail: + elif jid_vcard: mimetype = filename = filepath = None - if jid_detail['type']: - mimetype = jid_detail['type'] + if jid_vcard['type']: + mimetype = jid_vcard['type'] if mimetype: filetype = mimetype.split('/')[1] if filetype == 'svg+xml': filetype = 'svg' @@ -825,7 +843,7 @@ class FileUtilities: # Write the decoded bytes to a file with open(filepath, 'wb') as file: - file.write(jid_detail['bin']) + file.write(jid_vcard['bin']) if not filepath or not os.path.exists(filepath) or os.path.getsize(filepath) == 0: filename = 'default.svg' @@ -1021,16 +1039,12 @@ class Syndication: class XmppUtilities: - async def count_jid_items(xmpp_instance, jid_bare, node_name, jid_kind): - if jid_kind in ('mix', 'muc', 'conference', 'server'): - jid_items = await XmppXep0030.get_jid_items(xmpp_instance, jid_bare) - if isinstance(jid_items['iq'], stanza.iq.Iq): - count = len(jid_items['iq']['disco_items']['items']) - elif jid_kind in ('account', 'pubsub'): - node_item_ids = await XmppXep0060.get_node_item_ids(xmpp_instance, jid_bare, node_name) - if isinstance(node_item_ids, stanza.iq.Iq): - count = len(node_item_ids['disco_items']['items']) - return count + async def get_item_ids_of_node(jabber_id, password, jid_bare, node_name, nodes): + xmpp_instance = XmppInstance(jabber_id, password, jid_bare) + xmpp_instance.connect() + node_item_ids = await XmppXep0060.get_node_item_ids(xmpp_instance, jid_bare, node_name) + xmpp_instance.disconnect() + return node_item_ids def set_query_uri_link(jid_bare, jid_info, jid_kind, node_name=None, item_id=None): links = [] @@ -1322,21 +1336,28 @@ class XmppXep0060: async def get_node_item_ids(self, jid_bare, node_name): try: + error = False + condition = text = None iq = await self['xep_0030'].get_items( jid_bare, node_name) # Broken. See https://codeberg.org/poezio/slixmpp/issues/3548 #iq = await self['xep_0060'].get_item_ids( # jid_bare, node_name, timeout=5) - result = iq - except IqError as e: - if e.iq['error']['text'] == 'Node not found': - result = 'Node not found' - elif e.iq['error']['condition'] == 'item-not-found': - result = 'Item not found' - else: - result = None - except IqTimeout as e: - result = e + except (IqError, IqTimeout) as e: + error = True + condition = e.iq['error']['condition'] + text = e.iq['error']['text'] + if not text: + if condition: + text = 'Could not retrieve node items' + else: + text = 'Unknown Error' + iq = None + result = { + 'error' : error, + 'condition' : condition, + 'text' : text, + 'iq' : iq} return result class XmppXep0369: