forked from sch/Blasta
Compare commits
4 commits
systemd-un
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
0ab40eedec | ||
|
ea255d84e0 | ||
|
c31278b576 | ||
|
21e3aa34aa |
5 changed files with 270 additions and 168 deletions
325
blasta.py
325
blasta.py
|
@ -11,6 +11,7 @@ TODO
|
|||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
from asyncio import Lock
|
||||
from datetime import datetime
|
||||
|
@ -51,7 +52,7 @@ DBLOCK = Lock()
|
|||
|
||||
class Data:
|
||||
|
||||
def cache_items_and_tags(entries, jid, tag=None):
|
||||
def cache_items_and_tags_search(entries, jid, query):
|
||||
"""Create a cache file of node items and tags."""
|
||||
item_ids = []
|
||||
tags = {}
|
||||
|
@ -59,13 +60,7 @@ class Data:
|
|||
entry_tags = entry['tags']
|
||||
entry_url_hash = entry['url_hash']
|
||||
tags_to_include = []
|
||||
if tag:
|
||||
if tag in entry_tags:
|
||||
item_ids.append(entry_url_hash)
|
||||
tags_to_include += entry_tags
|
||||
for tag_to_include in tags_to_include:
|
||||
tags[tag_to_include] = tags[tag_to_include]+1 if tag_to_include in tags else 1
|
||||
else:
|
||||
if query in ' '.join([entry['title'], entry['link'], entry['summary'], ' '.join(entry_tags)]):
|
||||
item_ids.append(entry_url_hash)
|
||||
tags_to_include += entry_tags
|
||||
for tag_to_include in tags_to_include:
|
||||
|
@ -73,20 +68,60 @@ class Data:
|
|||
if tags:
|
||||
tags = dict(sorted(tags.items(), key=lambda item: (-item[1], item[0])))
|
||||
tags = dict(list(tags.items())[:30])
|
||||
if tag: del tags[tag]
|
||||
if item_ids:
|
||||
filename = 'data/{}_query.toml'.format(jid)
|
||||
data = {
|
||||
'item_ids' : item_ids,
|
||||
'tags' : tags}
|
||||
Data.save_to_toml(filename, data)
|
||||
|
||||
def cache_items_and_tags_filter(entries, jid, tag):
|
||||
"""Create a cache file of node items and tags."""
|
||||
item_ids = []
|
||||
tags = {}
|
||||
for entry in entries:
|
||||
entry_tags = entry['tags']
|
||||
entry_url_hash = entry['url_hash']
|
||||
tags_to_include = []
|
||||
if tag in entry_tags:
|
||||
item_ids.append(entry_url_hash)
|
||||
tags_to_include += entry_tags
|
||||
for tag_to_include in tags_to_include:
|
||||
tags[tag_to_include] = tags[tag_to_include]+1 if tag_to_include in tags else 1
|
||||
if tags:
|
||||
tags = dict(sorted(tags.items(), key=lambda item: (-item[1], item[0])))
|
||||
tags = dict(list(tags.items())[:30])
|
||||
del tags[tag]
|
||||
if item_ids:
|
||||
directory = 'data/{}/'.format(jid)
|
||||
if not exists(directory):
|
||||
mkdir(directory)
|
||||
if tag:
|
||||
filename = 'data/{}/{}.toml'.format(jid, tag)
|
||||
filename = 'data/{}/{}.toml'.format(jid, tag)
|
||||
# Add support for search query
|
||||
#if tag:
|
||||
# filename = 'data/{}/query:{}.toml'.format(jid, query)
|
||||
#if tag:
|
||||
# filename = 'data/{}/tag:{}.toml'.format(jid, tag)
|
||||
else:
|
||||
filename = 'data/{}.toml'.format(jid)
|
||||
#filename = 'data/{}/query:{}.toml'.format(jid, query)
|
||||
#filename = 'data/{}/tag:{}.toml'.format(jid, tag)
|
||||
data = {
|
||||
'item_ids' : item_ids,
|
||||
'tags' : tags}
|
||||
Data.save_to_toml(filename, data)
|
||||
|
||||
def cache_items_and_tags(entries, jid):
|
||||
"""Create a cache file of node items and tags."""
|
||||
item_ids = []
|
||||
tags = {}
|
||||
for entry in entries:
|
||||
entry_tags = entry['tags']
|
||||
entry_url_hash = entry['url_hash']
|
||||
tags_to_include = []
|
||||
item_ids.append(entry_url_hash)
|
||||
tags_to_include += entry_tags
|
||||
for tag_to_include in tags_to_include:
|
||||
tags[tag_to_include] = tags[tag_to_include]+1 if tag_to_include in tags else 1
|
||||
if tags:
|
||||
tags = dict(sorted(tags.items(), key=lambda item: (-item[1], item[0])))
|
||||
tags = dict(list(tags.items())[:30])
|
||||
if item_ids:
|
||||
filename = 'data/{}.toml'.format(jid)
|
||||
data = {
|
||||
'item_ids' : item_ids,
|
||||
'tags' : tags}
|
||||
|
@ -190,10 +225,9 @@ class Data:
|
|||
entries_cache_node = Data.extract_iq_items_extra(iq, jabber_id)
|
||||
data_items = {node_type : entries_cache_node}
|
||||
Data.save_to_toml(filename_items, data_items)
|
||||
return ['fine', iq] # TODO Remove this line
|
||||
else:
|
||||
print('iq problem')
|
||||
breakpoint()
|
||||
print('iq problem')
|
||||
return ['error', iq]
|
||||
else:
|
||||
entries_cache = Data.open_file_toml(filename_items)
|
||||
if not node_type in entries_cache: return ['error', 'Directory "{}" is empty'. format(node_type)]
|
||||
|
@ -229,10 +263,10 @@ class Data:
|
|||
entries_iq = Data.extract_iq_items_extra(iq, jabber_id)
|
||||
entries_cache_node_new += entries_iq
|
||||
else:
|
||||
print('iq problem')
|
||||
breakpoint()
|
||||
print('iq problem')
|
||||
|
||||
# TODO
|
||||
# Handle this concern in a different fashion,
|
||||
# instead of stopping the whole operation.
|
||||
return ['error', iq]
|
||||
entries_cache_node += entries_cache_node_new
|
||||
|
||||
if node_type == 'public':
|
||||
|
@ -397,6 +431,14 @@ class HttpInstance:
|
|||
# httponly=False, # True
|
||||
# samesite='lax')
|
||||
|
||||
@self.app.exception_handler(403)
|
||||
def not_found_exception_handler(request: Request, exc: HTTPException):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
message = 'Blasta system message » Access denied.'
|
||||
description = 'Access denied (403)'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
|
||||
@self.app.exception_handler(404)
|
||||
def not_found_exception_handler(request: Request, exc: HTTPException):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
|
@ -421,6 +463,22 @@ class HttpInstance:
|
|||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
|
||||
# TODO
|
||||
@self.app.get('/admin')
|
||||
def admin_get(request: Request):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
authorized = None
|
||||
if authorized:
|
||||
template_file = 'connect.xhtml'
|
||||
template_dict = {
|
||||
'request' : request,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
else:
|
||||
raise HTTPException(status_code=403, detail='Access denied')
|
||||
|
||||
@self.app.get('/connect')
|
||||
def connect_get(request: Request):
|
||||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
|
@ -432,7 +490,7 @@ class HttpInstance:
|
|||
'request' : request,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/contact')
|
||||
|
@ -450,7 +508,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/disconnect')
|
||||
|
@ -478,7 +536,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about')
|
||||
|
@ -490,7 +548,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/folksonomy')
|
||||
|
@ -502,7 +560,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/ideas')
|
||||
|
@ -518,7 +576,7 @@ class HttpInstance:
|
|||
'journal' : journal,
|
||||
'origin' : origin}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/philosophy')
|
||||
|
@ -530,7 +588,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/projects')
|
||||
|
@ -542,7 +600,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/software')
|
||||
|
@ -554,7 +612,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/thanks')
|
||||
|
@ -566,7 +624,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/xmpp')
|
||||
|
@ -578,7 +636,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/xmpp/atomsub')
|
||||
|
@ -590,7 +648,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/xmpp/libervia')
|
||||
|
@ -602,7 +660,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/xmpp/movim')
|
||||
|
@ -614,7 +672,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/about/xmpp/pubsub')
|
||||
|
@ -630,7 +688,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/feeds')
|
||||
|
@ -642,7 +700,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/questions')
|
||||
|
@ -654,7 +712,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/syndication')
|
||||
|
@ -671,7 +729,7 @@ class HttpInstance:
|
|||
'origin' : origin,
|
||||
'pubsub_jid' : jabber_id_pubsub}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/help/utilities')
|
||||
|
@ -689,7 +747,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/jid', response_class=HTMLResponse)
|
||||
|
@ -762,20 +820,48 @@ class HttpInstance:
|
|||
# NOTE Does it work?
|
||||
# It does not seem to actually filter tags.
|
||||
# NOTE Yes. It does work.
|
||||
# See function "cache_items_and_tags".
|
||||
|
||||
# TODO Search by query
|
||||
#if param_query:
|
||||
|
||||
if param_tags or param_tld or param_filetype or param_protocol:
|
||||
# See function "cache_items_and_tags_filter".
|
||||
if param_query:
|
||||
query = param_query
|
||||
entries_cache = Data.open_file_toml(filename_items)
|
||||
entries_cache_node = entries_cache[node_type]
|
||||
filename_cache = 'data/{}_query.toml'.format(jid)
|
||||
Data.cache_items_and_tags_search(entries_cache_node, jid, query)
|
||||
if exists(filename_cache) and getsize(filename_cache):
|
||||
data = Data.open_file_toml(filename_cache)
|
||||
item_ids_all = data['item_ids']
|
||||
related_tags = data['tags']
|
||||
if len(item_ids_all) <= index_last:
|
||||
index_last = len(item_ids_all)
|
||||
page_next = None
|
||||
item_ids_selection = []
|
||||
for item_id in item_ids_all[index_first:index_last]:
|
||||
item_ids_selection.append(item_id)
|
||||
entries = []
|
||||
for entry in entries_cache_node:
|
||||
for item_id in item_ids_selection:
|
||||
if entry['url_hash'] == item_id:
|
||||
entries.append(entry)
|
||||
for entry in entries:
|
||||
entry['published_mod'] = Utilities.convert_iso8601_to_readable(entry['published'])
|
||||
entry['tags'] = entry['tags'][:5]
|
||||
description = 'Your {} bookmarks with "{}"'.format(node_type, query)
|
||||
message = 'Listing {} bookmarks {} - {} out of {}.'.format(node_type, index_first+1, index_last, len(item_ids_all))
|
||||
#item_id_next = entries[len(entries)-1]
|
||||
else:
|
||||
description = 'No {} bookmarks with "{}" were found for {}'.format(node_type, query, jid)
|
||||
message = 'Blasta system message » No entries.'
|
||||
page_next = None
|
||||
page_prev = None
|
||||
elif param_tags or param_tld or param_filetype or param_protocol:
|
||||
tags_list = param_tags.split('+')
|
||||
if len(tags_list) == 1:
|
||||
tag = param_tags
|
||||
entries_cache = Data.open_file_toml(filename_items)
|
||||
entries_cache_node = entries_cache[node_type]
|
||||
filename_cache = 'data/{}/{}.toml'.format(jid, tag)
|
||||
Data.cache_items_and_tags(entries_cache_node, jid, tag)
|
||||
if exists(filename_cache) or getsize(filename_cache):
|
||||
Data.cache_items_and_tags_filter(entries_cache_node, jid, tag)
|
||||
if exists(filename_cache) and getsize(filename_cache):
|
||||
data = Data.open_file_toml(filename_cache)
|
||||
item_ids_all = data['item_ids']
|
||||
related_tags = data['tags']
|
||||
|
@ -811,7 +897,7 @@ class HttpInstance:
|
|||
filename_cache = 'data/{}.toml'.format(jid)
|
||||
#if len(entries_cache_node) and not exists(filename_cache):
|
||||
Data.cache_items_and_tags(entries_cache_node, jid)
|
||||
if exists(filename_cache) or getsize(filename_cache):
|
||||
if exists(filename_cache) and getsize(filename_cache):
|
||||
data = Data.open_file_toml(filename_cache)
|
||||
item_ids_all = data['item_ids']
|
||||
related_tags = data['tags']
|
||||
|
@ -864,10 +950,11 @@ class HttpInstance:
|
|||
for tag, instances in SQLite.get_30_tags_by_jid(db_file, jid, index_first):
|
||||
tags_dict[tag] = instances
|
||||
if not entries_database:
|
||||
message = 'Blasta system message » Error: No entries were found.'
|
||||
description = 'No results'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
#message = 'Blasta system message » Error: No entries were found.'
|
||||
#description = 'No results'
|
||||
#path = 'error'
|
||||
#return result_post(request, jabber_id, description, message, path)
|
||||
raise HTTPException(status_code=404, detail='No entries were found')
|
||||
if entries_count:
|
||||
entries = []
|
||||
for entry in entries_database:
|
||||
|
@ -991,13 +1078,14 @@ class HttpInstance:
|
|||
'origin': origin,
|
||||
'path': path}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
else:
|
||||
description = 'An XMPP account is required'
|
||||
message = 'Blasta system message » Please connect with your XMPP account to view this directory.'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
if not entries: raise HTTPException(status_code=404, detail='No entries were found')
|
||||
template_dict = {
|
||||
'request': request,
|
||||
'description': description,
|
||||
|
@ -1025,7 +1113,7 @@ class HttpInstance:
|
|||
else:
|
||||
template_file = 'browse.xhtml'
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/blasta.svg')
|
||||
|
@ -1118,10 +1206,11 @@ class HttpInstance:
|
|||
tags_of_entries = SQLite.get_30_tags_by_entries_recent(db_file, index_first)
|
||||
entries_count = SQLite.get_entries_count(db_file)
|
||||
if not entries_database:
|
||||
message = 'Blasta system message » Error: No entries were found.'
|
||||
description = 'No results'
|
||||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
#message = 'Blasta system message » Error: No entries were found.'
|
||||
#description = 'No results'
|
||||
#path = 'error'
|
||||
#return result_post(request, jabber_id, description, message, path)
|
||||
raise HTTPException(status_code=404, detail='No entries were found')
|
||||
tags_dict = {}
|
||||
#for tag, instances in SQLite.get_tags_30(db_file):
|
||||
for tag, instances in tags_of_entries:
|
||||
|
@ -1196,7 +1285,7 @@ class HttpInstance:
|
|||
else:
|
||||
template_file = 'browse.xhtml'
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
"""
|
||||
|
@ -1298,19 +1387,21 @@ class HttpInstance:
|
|||
path = 'error'
|
||||
return result_post(request, jabber_id, description, message, path)
|
||||
else:
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:settings:0', 'routine')
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:configuration:0', 'routine')
|
||||
routine = None
|
||||
if isinstance(iq, slixmpp.stanza.iq.Iq):
|
||||
payload = iq['pubsub']['items']['item']['payload']
|
||||
routine = payload.text if payload else None
|
||||
else:
|
||||
routine = None
|
||||
if payload:
|
||||
xmlns = '{jabber:x:data}'
|
||||
element_value = payload.find('.//' + xmlns + 'field[@var="routine"]/' + xmlns + 'value')
|
||||
if isinstance(element_value, ET.Element): routine = element_value.text
|
||||
match routine:
|
||||
case 'private':
|
||||
response = RedirectResponse(url='/private')
|
||||
case 'read':
|
||||
response = RedirectResponse(url='/read')
|
||||
case _:
|
||||
response = RedirectResponse(url='/jid/' + jabber_id)
|
||||
response = RedirectResponse(url='/jid/')
|
||||
|
||||
else:
|
||||
#del accounts[jabber_id]
|
||||
|
@ -1349,7 +1440,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/private', response_class=HTMLResponse)
|
||||
|
@ -1381,7 +1472,7 @@ class HttpInstance:
|
|||
jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request)
|
||||
if jabber_id:
|
||||
xmpp_instance = accounts[jabber_id]
|
||||
if not await XmppPubsub.is_node_exist(xmpp_instance, 'xmpp:blasta:settings:0'):
|
||||
if not await XmppPubsub.is_node_exist(xmpp_instance, 'xmpp:blasta:configuration:0'):
|
||||
iq = XmppPubsub.create_node_config(xmpp_instance, jabber_id)
|
||||
await iq.send(timeout=15)
|
||||
access_models = {}
|
||||
|
@ -1392,10 +1483,13 @@ class HttpInstance:
|
|||
access_models[node_type] = access_model
|
||||
settings = {}
|
||||
for setting in ['enrollment', 'routine']:
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:settings:0', setting)
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:configuration:0', setting)
|
||||
if isinstance(iq, slixmpp.stanza.iq.Iq):
|
||||
payload = iq['pubsub']['items']['item']['payload']
|
||||
if payload: settings[setting] = payload.text
|
||||
if payload:
|
||||
xmlns = '{jabber:x:data}'
|
||||
element_value = payload.find('.//' + xmlns + 'field[@var="' + setting + '"]/' + xmlns + 'value')
|
||||
if isinstance(element_value, ET.Element): settings[setting] = element_value.text
|
||||
template_file = 'profile.xhtml'
|
||||
template_dict = {
|
||||
'access_models' : access_models,
|
||||
|
@ -1405,7 +1499,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
description = 'You are not connected'
|
||||
|
@ -1422,15 +1516,15 @@ class HttpInstance:
|
|||
xmpp_instance = accounts[jabber_id]
|
||||
if routine:
|
||||
message = 'The routine directory has been set to {}'.format(routine)
|
||||
payload = Xml.create_setting_entry(routine)
|
||||
iq = await XmppPubsub.publish_node_item(
|
||||
xmpp_instance, jabber_id, 'xmpp:blasta:settings:0', 'routine', payload)
|
||||
payload = Xml.create_setting_entry(xmpp_instance, 'routine', routine)
|
||||
iq = await XmppPubsub.publish_node_item( # NOTE Consider "configurations" as item ID (see Movim)
|
||||
xmpp_instance, jabber_id, 'xmpp:blasta:configuration:0', 'routine', payload)
|
||||
if enroll:
|
||||
if enroll == '1': message = 'Your database is shared with the Blasta system'
|
||||
else: message = 'Your database is excluded from the Blasta system'
|
||||
payload = Xml.create_setting_entry(enroll)
|
||||
payload = Xml.create_setting_entry(xmpp_instance, 'enroll', enroll)
|
||||
iq = await XmppPubsub.publish_node_item(
|
||||
xmpp_instance, jabber_id, 'xmpp:blasta:settings:0', 'enrollment', payload)
|
||||
xmpp_instance, jabber_id, 'xmpp:blasta:configuration:0', 'enrollment', payload)
|
||||
description = 'Setting has been saved'
|
||||
template_file = 'result.xhtml'
|
||||
template_dict = {
|
||||
|
@ -1442,7 +1536,7 @@ class HttpInstance:
|
|||
'request' : request,
|
||||
'routine' : routine}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
description = 'You are not connected'
|
||||
|
@ -1574,10 +1668,13 @@ class HttpInstance:
|
|||
if (isinstance(iq, slixmpp.stanza.iq.Iq) and
|
||||
url_hash == iq['pubsub']['items']['item']['id']):
|
||||
return RedirectResponse(url='/url/' + url_hash + '/edit')
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:settings:0', 'routine')
|
||||
iq = await XmppPubsub.get_node_item(xmpp_instance, jabber_id, 'xmpp:blasta:configuration:0', 'routine')
|
||||
if isinstance(iq, slixmpp.stanza.iq.Iq):
|
||||
payload = iq['pubsub']['items']['item']['payload']
|
||||
routine = payload.text if payload else None
|
||||
if payload:
|
||||
xmlns = '{jabber:x:data}'
|
||||
element_value = payload.find('.//' + xmlns + 'field[@var="routine"]/' + xmlns + 'value')
|
||||
if isinstance(element_value, ET.Element): routine = element_value.text
|
||||
else:
|
||||
routine = None
|
||||
# NOTE Is "message" missing?
|
||||
|
@ -1606,7 +1703,7 @@ class HttpInstance:
|
|||
'title' : param_title,
|
||||
'url' : param_url}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
description = 'You are not connected'
|
||||
|
@ -1651,7 +1748,7 @@ class HttpInstance:
|
|||
'url' : url,
|
||||
'url_hash' : url_hash}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
|
@ -1693,7 +1790,7 @@ class HttpInstance:
|
|||
'path' : path,
|
||||
'request' : request}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/register')
|
||||
|
@ -1705,7 +1802,7 @@ class HttpInstance:
|
|||
'jabber_id' : jabber_id,
|
||||
'journal' : journal}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/rss')
|
||||
|
@ -1744,7 +1841,7 @@ class HttpInstance:
|
|||
'message' : message,
|
||||
'path' : path}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/search/jid/{jid}')
|
||||
|
@ -1780,7 +1877,7 @@ class HttpInstance:
|
|||
'message' : message,
|
||||
'path' : path}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
response = RedirectResponse(url='/search/all')
|
||||
return response
|
||||
|
@ -1812,7 +1909,7 @@ class HttpInstance:
|
|||
'message' : message,
|
||||
'path' : path}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/tag')
|
||||
|
@ -1831,7 +1928,7 @@ class HttpInstance:
|
|||
'message' : message,
|
||||
'tag_list' : tag_list}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/tag/{jid}')
|
||||
|
@ -1854,7 +1951,7 @@ class HttpInstance:
|
|||
'message' : message,
|
||||
'tag_list' : tag_list}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
|
||||
@self.app.get('/url')
|
||||
|
@ -2016,7 +2113,7 @@ class HttpInstance:
|
|||
'syndicate' : syndicate,
|
||||
'tags' : tags_list}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
message = 'Blasta system message » Error: MD5 message-digest algorithm.'
|
||||
description = 'The argument for URL does not appear to be a valid MD5 Checksum'
|
||||
|
@ -2176,7 +2273,7 @@ class HttpInstance:
|
|||
'syndicate': syndicate,
|
||||
'tags' : tags_new}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
return response
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
|
@ -2242,7 +2339,7 @@ class HttpInstance:
|
|||
'pubsub_jid' : jabber_id_pubsub,
|
||||
'syndicate' : syndicate}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
response = RedirectResponse(url='/jid/' + jabber_id)
|
||||
else:
|
||||
|
@ -2337,7 +2434,7 @@ class HttpInstance:
|
|||
'restore' : True,
|
||||
'syndicate' : syndicate}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
response = RedirectResponse(url='/jid/' + jabber_id)
|
||||
else:
|
||||
|
@ -2439,7 +2536,7 @@ class HttpInstance:
|
|||
'url' : entry['link'],
|
||||
'url_hash' : url_hash}
|
||||
response = templates.TemplateResponse(template_file, template_dict)
|
||||
response.headers["Content-Type"] = "application/xhtml+xml"
|
||||
response.headers['Content-Type'] = 'application/xhtml+xml'
|
||||
else:
|
||||
message = 'Blasta system message » Error: No active session.'
|
||||
description = 'You are not connected'
|
||||
|
@ -3985,7 +4082,7 @@ class SQLite:
|
|||
# .format(function_name, db_file, tag))
|
||||
sql = (
|
||||
"""
|
||||
SELECT COUNT(entries.id)
|
||||
SELECT COUNT(DISTINCT entries.id)
|
||||
FROM main_entries AS entries
|
||||
INNER JOIN combination_entries_tags_jids AS co ON entries.id = co.entry_id
|
||||
INNER JOIN main_tags AS tags ON tags.id = co.tag_id
|
||||
|
@ -5022,10 +5119,17 @@ class Utilities:
|
|||
|
||||
class Xml:
|
||||
|
||||
def create_setting_entry(value : str):
|
||||
element = ET.Element('value')
|
||||
element.text = value
|
||||
return element
|
||||
def create_setting_entry(xmpp_instance, key : str, value : str):
|
||||
form = xmpp_instance['xep_0004'].make_form('form', 'Settings')
|
||||
form['type'] = 'result'
|
||||
form.add_field(var=key,
|
||||
value=value)
|
||||
return form
|
||||
|
||||
# def create_setting_entry(value : str):
|
||||
# element = ET.Element('value')
|
||||
# element.text = value
|
||||
# return element
|
||||
|
||||
class Configuration:
|
||||
|
||||
|
@ -5133,7 +5237,7 @@ class XmppPubsub:
|
|||
iq = xmpp_instance.Iq(stype='set',
|
||||
sto=jid,
|
||||
sfrom=jid_from)
|
||||
iq['pubsub']['create']['node'] = 'xmpp:blasta:settings:0'
|
||||
iq['pubsub']['create']['node'] = 'xmpp:blasta:configuration:0'
|
||||
form = iq['pubsub']['configure']['form']
|
||||
form['type'] = 'submit'
|
||||
form.addField('pubsub#access_model',
|
||||
|
@ -5320,11 +5424,22 @@ def main():
|
|||
return http_instance.app
|
||||
|
||||
app = main()
|
||||
webbrowser.open('http://localhost:8000/help/about')
|
||||
# TODO Check first time
|
||||
webbrowser.open_new_tab('http://localhost:8000')
|
||||
|
||||
# FIXME
|
||||
if __name__ == '__main__':
|
||||
uvicorn.run(app, host='localhost', port=8000, reload=True)
|
||||
parser = argparse.ArgumentParser(
|
||||
prog='blasta',
|
||||
description='Blasta - A collaborative annotation system.',
|
||||
usage='%(prog)s [OPTION]...')
|
||||
parser.add_argument('-v', '--version', help='print version',
|
||||
action='version', version='0.1')
|
||||
parser.add_argument('-p', '--port', help='port number', dest='port')
|
||||
parser.add_argument('-o', '--open', help='open an html browser', action='store_const', const=True, dest='open')
|
||||
args = parser.parse_args()
|
||||
port = args.port if args.port else 8000
|
||||
uvicorn.run(app, host='localhost', port=port, reload=True)
|
||||
if args.open:
|
||||
# TODO Check first time
|
||||
webbrowser.open('http://localhost:{}/help/about'.format(port))
|
||||
webbrowser.open_new_tab('http://localhost:{}'.format(port))
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import webview
|
||||
import subprocess
|
||||
import sys
|
||||
|
@ -13,7 +16,7 @@ class HtmlView:
|
|||
# Open the link using xdg-open
|
||||
subprocess.run(['xdg-open', uri], check=True)
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"Failed to open URL: {uri}. Error: {e}")
|
||||
print('Failed to open URL: {}. Error: {}'.format(uri, e))
|
||||
else:
|
||||
# If it is from url_instance, just load it in the webview
|
||||
#webview.load_url(uri)
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
map $http_upgrade $connection_upgrade { default upgrade; '' close; } server {
|
||||
server_name blasta.example.tld;
|
||||
|
||||
access_log /var/log/nginx/blasta/access.log;
|
||||
error_log /var/log/nginx/blasta/error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:11112;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 3600;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl http2;
|
||||
listen 443 ssl http2;
|
||||
ssl_certificate /etc/letsencrypt/live/blasta.example.tld/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/blasta.example.tld/privkey.pem;
|
||||
}
|
||||
|
||||
server {
|
||||
listen [::]:80;
|
||||
listen 80;
|
||||
server_name blasta.example.tld;
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
# /etc/systemd/system/blasta.service
|
||||
[Unit]
|
||||
Description=Blasta Bookmarks Service
|
||||
After=network.target
|
||||
Requisite=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/uvicorn blasta:app --port 11112
|
||||
User=blasta
|
||||
Restart=always
|
||||
RestartSec=20s
|
||||
Type=simple
|
||||
WorkingDirectory=/home/blasta/Blasta
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
|
@ -64,14 +64,20 @@
|
|||
|
||||
PubSub bookmarks
|
||||
</h2>
|
||||
<p>» Information of your Jabber ID.</p>
|
||||
<h3>Your Profile</h3>
|
||||
<p>
|
||||
» Information of your Jabber ID.
|
||||
</p>
|
||||
<h3>
|
||||
Your profile
|
||||
</h3>
|
||||
<p>
|
||||
This page provides a general survey of your XMPP account and
|
||||
stored bookmarks.
|
||||
</p>
|
||||
<!--
|
||||
<h4 id="enrollment">Enrollment</h4>
|
||||
<h4 id="enrollment">
|
||||
Enrollment
|
||||
</h4>
|
||||
<p>
|
||||
Blasta does not automatically include your public bookmarks
|
||||
to its database.
|
||||
|
@ -120,7 +126,9 @@
|
|||
therefore.
|
||||
</p>
|
||||
-->
|
||||
<h4 id="export">Export</h4>
|
||||
<h4 id="export">
|
||||
Export
|
||||
</h4>
|
||||
<p>
|
||||
Export bookmarks to a file.
|
||||
</p>
|
||||
|
@ -128,7 +136,9 @@
|
|||
<!-- TODO Add XBEL, XHTML and XML -->
|
||||
<dl>
|
||||
<dt>
|
||||
<strong>Private</strong>
|
||||
<strong>
|
||||
Private
|
||||
</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
<a download="{{jabber_id}}_private.json"
|
||||
|
@ -139,7 +149,9 @@
|
|||
TOML</a>.
|
||||
</dd>
|
||||
<dt>
|
||||
<strong>Public</strong>
|
||||
<strong>
|
||||
Public
|
||||
</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
<a download="{{jabber_id}}_public.json"
|
||||
|
@ -150,7 +162,9 @@
|
|||
TOML</a>.
|
||||
</dd>
|
||||
<dt>
|
||||
<strong>Read</strong>
|
||||
<strong>
|
||||
Read
|
||||
</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
<a download="{{jabber_id}}_read.json"
|
||||
|
@ -162,7 +176,9 @@
|
|||
</dd>
|
||||
</dl>
|
||||
</p>
|
||||
<h4 id="import">Import</h4>
|
||||
<h4 id="import">
|
||||
Import
|
||||
</h4>
|
||||
<p>
|
||||
Import bookmarks from a file, and choose a node to import
|
||||
your bookmarks to.
|
||||
|
@ -175,7 +191,9 @@
|
|||
<tr>
|
||||
<td>
|
||||
<strong>
|
||||
<label for="file">File</label>
|
||||
<label for="file">
|
||||
File
|
||||
</label>
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -189,7 +207,9 @@
|
|||
<tr>
|
||||
<td>
|
||||
<strong>
|
||||
<label for="node">Node</label>
|
||||
<label for="node">
|
||||
Node
|
||||
</label>
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -214,7 +234,9 @@
|
|||
<tr>
|
||||
<td>
|
||||
<strong>
|
||||
<label for="node">Action</label>
|
||||
<label for="node">
|
||||
Action
|
||||
</label>
|
||||
</strong>
|
||||
</td>
|
||||
<td>
|
||||
|
@ -422,7 +444,9 @@ retrieve items only if on a whitelist managed by the node owner.">
|
|||
proceeding.
|
||||
</p>
|
||||
<hr/>
|
||||
<h4 id="termination">Termination</h4>
|
||||
<h4 id="termination">
|
||||
Termination
|
||||
</h4>
|
||||
<p>
|
||||
Due to security concerns, Blasta does not have a built-in
|
||||
mechanism to delete nodes.
|
||||
|
@ -438,7 +462,9 @@ retrieve items only if on a whitelist managed by the node owner.">
|
|||
<a href="https://psi-im.org">Psi</a>, or
|
||||
<a href="https://psi-plus.com">Psi+</a>.
|
||||
</p>
|
||||
<h4>Delete your public bookmarks</h4>
|
||||
<h4>
|
||||
Delete your public bookmarks
|
||||
</h4>
|
||||
<pre>
|
||||
<iq type='set'
|
||||
from='{{jabber_id}}'
|
||||
|
@ -449,7 +475,9 @@ retrieve items only if on a whitelist managed by the node owner.">
|
|||
</pubsub>
|
||||
</iq>
|
||||
</pre>
|
||||
<h4>Delete your private bookmarks</h4>
|
||||
<h4>
|
||||
Delete your private bookmarks
|
||||
</h4>
|
||||
<pre>
|
||||
<iq type='set'
|
||||
from='{{jabber_id}}'
|
||||
|
@ -460,7 +488,9 @@ retrieve items only if on a whitelist managed by the node owner.">
|
|||
</pubsub>
|
||||
</iq>
|
||||
</pre>
|
||||
<h4>Delete your reading list</h4>
|
||||
<h4>
|
||||
Delete your reading list
|
||||
</h4>
|
||||
<pre>
|
||||
<iq type='set'
|
||||
from='{{jabber_id}}'
|
||||
|
|
Loading…
Reference in a new issue