From a53c3a3436fc59b074d1d0f3a19843853d6eca6b Mon Sep 17 00:00:00 2001 From: "Schimon Jehudah, Adv." Date: Wed, 28 Aug 2024 15:03:19 +0300 Subject: [PATCH] CSS : Modify stylesheet due to modifying XHTML; Python : Improve editing of tags; Python : Fix error upon no results on Atom; SQLite : Add triggers to count instances of entries; SQLite : Add triggers to delete entries SQLite : Add triggers to delete tags; XSLT : Remove control characters in favour of nbsp entity; XSLT : Improve links and design; XHTML : Add a new document about folksonomy; XHTML : Add a new template for URL; XHTML : Add indicators. --- blasta.py | 288 +++++++++++++++++++++++++++++++++---- configuration.toml | 4 +- stylesheet/stylesheet.css | 6 +- stylesheet/stylesheet.xsl | 99 +++++++------ template/about.xhtml | 10 +- template/ask.xhtml | 3 + template/atomsub.xhtml | 3 + template/browse.atom | 2 +- template/browse.xhtml | 60 +++++--- template/connect.xhtml | 2 +- template/contact.xhtml | 3 + template/edit.xhtml | 14 ++ template/feeds.xhtml | 3 + template/folksonomy.xhtml | 209 +++++++++++++++++++++++++++ template/help.xhtml | 4 + template/ideas.xhtml | 3 + template/libervia.xhtml | 3 + template/movim.xhtml | 3 + template/now.xhtml | 3 + template/people.xhtml | 256 +++++++++++++++++++++++++++++++++ template/philosophy.xhtml | 3 + template/profile.xhtml | 3 + template/projects.xhtml | 3 + template/pubsub.xhtml | 3 + template/questions.xhtml | 7 +- template/register.xhtml | 3 + template/result.xhtml | 3 + template/search.xhtml | 5 +- template/software.xhtml | 3 + template/syndication.xhtml | 3 + template/tag.xhtml | 3 + template/thanks.xhtml | 3 + template/utilities.xhtml | 3 + template/xmpp.xhtml | 3 + 34 files changed, 926 insertions(+), 100 deletions(-) create mode 100644 template/folksonomy.xhtml create mode 100644 template/people.xhtml diff --git a/blasta.py b/blasta.py index 710c9d0..ba0faec 100644 --- a/blasta.py +++ b/blasta.py @@ -491,6 +491,18 @@ class HttpInstance: response.headers["Content-Type"] = "application/xhtml+xml" return response + @self.app.get('/help/about/folksonomy') + def help_about_folksonomies_get(request: Request): + jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request) + template_file = 'folksonomy.xhtml' + template_dict = { + 'request' : request, + 'jabber_id' : jabber_id, + 'journal' : journal} + response = templates.TemplateResponse(template_file, template_dict) + response.headers["Content-Type"] = "application/xhtml+xml" + return response + @self.app.get('/help/about/ideas') def help_about_ideas_get(request: Request): jabber_id = Utilities.is_jid_matches_to_session(accounts, sessions, request) @@ -849,6 +861,11 @@ class HttpInstance: entries_count = SQLite.get_entries_count_by_jid(db_file, jid) 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) if entries_count: entries = [] for entry in entries_database: @@ -856,6 +873,8 @@ class HttpInstance: for tag in SQLite.get_tags_by_entry_id(db_file, entry[0]): tags_sorted.append(tag[0]) entry_jid = SQLite.get_jid_by_jid_id(db_file, entry[5]) + url_hash = Utilities.hash_url_to_md5(entry[2]) + instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash) entries.append( {'title' : entry[3], 'link' : entry[2], @@ -863,10 +882,10 @@ class HttpInstance: 'published' : entry[6], 'updated' : entry[7], 'tags' : tags_sorted, - 'url_hash' : Utilities.hash_url_to_md5(entry[2]), #entry[1] + 'url_hash' : url_hash, 'jid' : entry_jid, 'name' : entry_jid, # jid.split('@')[0] if '@' in jid else jid, - 'instances' : entry[8]}) + 'instances' : instances}) for entry in entries: try: date_iso = entry['published'] @@ -985,6 +1004,7 @@ class HttpInstance: 'jid': jid, 'journal': journal, 'message': message, + 'node_type': node_type, 'page_next': page_next, 'page_prev': page_prev, 'pager' : True, @@ -1095,6 +1115,11 @@ class HttpInstance: entries_database = SQLite.get_entries_recent(db_file, index_first) 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) tags_dict = {} #for tag, instances in SQLite.get_tags_30(db_file): for tag, instances in tags_of_entries: @@ -1105,6 +1130,8 @@ class HttpInstance: for tag in SQLite.get_tags_by_entry_id(db_file, entry[0]): tags_sorted.append(tag[0]) jid = SQLite.get_jid_by_jid_id(db_file, entry[5]) + url_hash = Utilities.hash_url_to_md5(entry[2]) + instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash) entries.append( {'title' : entry[3], 'link' : entry[2], @@ -1112,10 +1139,10 @@ class HttpInstance: 'published' : entry[6], 'updated' : entry[7], 'tags' : tags_sorted, - 'url_hash' : Utilities.hash_url_to_md5(entry[2]), #entry[1] + 'url_hash' : url_hash, #entry[1] 'jid' : jid, 'name' : jid, # jid.split('@')[0] if '@' in jid else jid, - 'instances' : entry[8]}) + 'instances' : instances}) for entry in entries: try: date_iso = entry['published'] @@ -1139,7 +1166,6 @@ class HttpInstance: message = ('Welcome to Blasta, an XMPP PubSub oriented social ' 'bookmarks manager for organizing online content.') message_link = {'href' : '/help/about', 'text' : 'Learn more'} - template_file = 'browse.xhtml' template_dict = { 'request' : request, 'description' : description, @@ -1151,6 +1177,7 @@ class HttpInstance: 'node_id' : node_id, 'page_next' : page_next, 'page_prev' : page_prev, + 'page_type' : page_type, 'pager' : True, 'param_query' : param_query, 'param_tags' : param_tags, @@ -1159,6 +1186,8 @@ class HttpInstance: 'syndicate' : syndicate, 'tags' : tags_dict} if param_mode == 'feed': + # NOTE Consider scheme "feed" in order to prompt news + # reader 'feed://' + request.url.netloc + request.url.path template_file = 'browse.atom' response = templates.TemplateResponse(template_file, template_dict) response.headers["Content-Type"] = "application/xml" @@ -1507,7 +1536,6 @@ class HttpInstance: 'jid' : jabber_id, 'name' : name, 'instances' : instances} - #message = 'Discover new links and see who shares them' xmpp_instance = accounts[jabber_id] payload = Syndication.create_rfc4287_entry(entry_new) iq = await XmppPubsub.publish_node_item( @@ -1556,12 +1584,19 @@ class HttpInstance: param_tags = request.query_params.get('tags', '') param_summary = request.query_params.get('summary', '') path = 'save' + if request.query_params: + message = message_link = None + else: + message = 'For greater ease, you migh want to try our' + message_link = {'href' : '/help/utilities#buttons', 'text' : 'bookmarklets'} template_file = 'edit.xhtml' template_dict = { 'request' : request, 'description' : description, 'jabber_id' : jabber_id, 'journal' : journal, + 'message' : message, + 'message_link' : message_link, 'path' : path, 'routine' : routine, 'summary' : param_summary, @@ -1873,7 +1908,7 @@ class HttpInstance: entries.append(entry) tags_list = {} tags_and_instances = SQLite.get_tags_and_instances_by_url_hash(db_file, url_hash) - for tag, instances in tags_and_instances: tags_list[tag] = instances + for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances else: # NOTE Is it possible to activate this else statement? Consider removal. # https://fastapi.tiangolo.com/tutorial/handling-errors/ #raise HTTPException(status_code=404, detail="Item not found") @@ -1890,8 +1925,9 @@ class HttpInstance: tags_sorted.append(tag[0]) tags_list = {} tags_and_instances = SQLite.get_tags_and_instances_by_entry_id(db_file, entry[0]) - for tag, instances in tags_and_instances: tags_list[tag] = instances + for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances jid = SQLite.get_jid_by_jid_id(db_file, entry[5]) + instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash) entries.append( {'title' : entry[3], 'link' : entry[2], @@ -1900,10 +1936,10 @@ class HttpInstance: 'published_mod' : Utilities.convert_iso8601_to_readable(entry[6]), 'updated' : entry[7], 'tags' : tags_sorted, - 'url_hash' : entry[1], # Utilities.hash_url_to_md5(entry[2]) + 'url_hash' : url_hash, 'jid' : jid, 'name' : jid, # jid.split('@')[0] if '@' in jid else jid, - 'instances' : entry[8]}) + 'instances' : instances}) # message = 'XMPP system message » {}.'.format(iq) # if iq == 'Node not found': # description = 'An error has occurred' @@ -1925,8 +1961,9 @@ class HttpInstance: tags_sorted.append(tag[0]) tags_list = {} tags_and_instances = SQLite.get_tags_and_instances_by_entry_id(db_file, entry[0]) - for tag, instances in tags_and_instances: tags_list[tag] = instances + for tag, tag_instances in tags_and_instances: tags_list[tag] = tag_instances jid = SQLite.get_jid_by_jid_id(db_file, entry[5]) + instances = SQLite.get_entry_instances_by_url_hash(db_file, url_hash) entries.append( {'title' : entry[3], 'link' : entry[2], @@ -1935,10 +1972,10 @@ class HttpInstance: 'published_mod' : Utilities.convert_iso8601_to_readable(entry[6]), 'updated' : entry[7], 'tags' : tags_sorted, - 'url_hash' : entry[1], # Utilities.hash_url_to_md5(entry[2]) + 'url_hash' : url_hash, 'jid' : jid, 'name' : jid, # jid.split('@')[0] if '@' in jid else jid, - 'instances' : entry[8]}) + 'instances' : instances}) else: # https://fastapi.tiangolo.com/tutorial/handling-errors/ #raise HTTPException(status_code=404, detail="Item not found") @@ -1946,9 +1983,21 @@ class HttpInstance: description = 'The requested bookmark does not exist' path = 'error' return result_post(request, jabber_id, description, message, path) - message = 'Information for URL {}'.format(entries[0]['link']) # entry[2] - description = 'Discover new links and see who shares them' - template_file = 'browse.xhtml' + message = 'Information for URI {}'.format(entries[0]['link']) # entry[2] + if instances > 1: + description = 'Discover new resources and see who shares them' + template_file = 'people.xhtml' + people_list = {} + jids_and_tags = SQLite.get_jids_and_tags_by_url_hash(db_file, url_hash) + for jid, tag in jids_and_tags: + if jid in people_list and isinstance(people_list[jid], list): + people_list[jid].append(tag) + else: + people_list[jid] = [tag] + else: + people_list = None + description = 'Resource properties' + template_file = 'browse.xhtml' template_dict = { 'request' : request, 'description' : description, @@ -1960,6 +2009,7 @@ class HttpInstance: 'node_id' : node_id, 'param_hash' : param_hash, 'path' : path, + 'people' : people_list, 'pubsub_jid' : jabber_id_pubsub, 'syndicate' : syndicate, 'tags' : tags_list} @@ -2069,16 +2119,19 @@ class HttpInstance: tags_invalid = [] #tags_list_new = tags.split(',') tags_list_new = tags_new - tags_list_old = tags_old.split(',') + tags_list_old = tags_old.split(', ') for tag in tags_list_old: + tag_trim = tag.strip() if tag not in tags_list_new: - tags_invalid.append(tag) + tags_invalid.append(tag_trim) for tag in tags_list_new: - if tag not in tags_list_old: - tags_valid.append(tag) - # FIXME Variable tags_valid is not in use. - # NOTE Variable tags_valid might not be needed. See function associate_entries_tags_jids. - await SQLite.delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, tags_invalid, jabber_id) + if tag: + tag_trim = tag.strip() + if tag_trim not in tags_list_old: + tags_valid.append(tag_trim) + # FIXME Variable tags_valid is not in use. + # NOTE Variable tags_valid might not be needed. See function associate_entries_tags_jids. + entry['tags'] = tags_valid await SQLite.add_tags(db_file, [entry]) # Slow (high I/O) entry_id = SQLite.get_entry_id_by_url_hash(db_file, url_hash) @@ -2089,6 +2142,17 @@ class HttpInstance: # await SQLite.associate_entries_tags_jids(db_file, entry) else: await SQLite.associate_entries_tags_jids(db_file, entry) + print('tags_new') + print(tags_new) + print('tags_old') + print(tags_old) + print('tags_valid') + print(tags_valid) + print('tags_invalid') + print(tags_invalid) + print(url_hash) + print(jabber_id) + await SQLite.delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, tags_invalid, jabber_id) # Entry for HTML entry['published_mod'] = Utilities.convert_iso8601_to_readable(published) entry['updated_mod'] = Utilities.convert_iso8601_to_readable(timestamp) @@ -2250,7 +2314,7 @@ class HttpInstance: # Remove the item association from database await SQLite.delete_combination_row_by_jid_and_url_hash(db_file, url_hash, jabber_id) - #await SQLite.delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, entry['tags'], jabber_id) + #await SQLite.delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, entry['tags'], jabber_id) # Remove the item from cache Data.remove_item_from_cache(jabber_id, node_type, url_hash) @@ -2323,6 +2387,8 @@ class HttpInstance: description = 'Edit an existing bookmark' entry = Syndication.extract_items(item_payload) entry['instances'] = SQLite.get_entry_instances_by_url_hash(db_file, url_hash) + print(jabber_id) + print(entry['tags']) else: # TODO Consider redirect to path /save (function save_get) # NOTE This seems to be the best to do, albeit, perhaps the pathname should be /save instead of /url/hash/edit. @@ -2338,8 +2404,8 @@ class HttpInstance: 'summary' : result[4], 'published' : result[6], 'updated' : result[7], - 'tags' : tags_sorted, - 'instances' : result[8]} + 'tags' : tags_sorted} + #'instances' : result[8], #'jid' = jabber_id, #'name' : name, #'url_hash' : url_hash @@ -2347,6 +2413,14 @@ class HttpInstance: entry['jid'] = jabber_id entry['name'] = name entry['url_hash'] = url_hash + else: + message = 'XMPP system message » {}.'.format(iq) + if iq == 'Node not found': + description = 'An error has occurred' + else: + description = 'An unknown error has occurred' + path = 'error' + return result_post(request, jabber_id, description, message, path) template_file = 'edit.xhtml' template_dict = { 'request' : request, @@ -2543,6 +2617,64 @@ class SQLite: ); """ ) + sql_trigger_instances_entry_decrease = ( + """ + CREATE TRIGGER instances_entry_decrease + AFTER DELETE ON combination_entries_tags_jids + FOR EACH ROW + BEGIN + UPDATE main_entries + SET instances = ( + SELECT COUNT(DISTINCT jid_id) + FROM combination_entries_tags_jids + WHERE entry_id = OLD.entry_id + ) + WHERE id = OLD.entry_id; + END; + """ + ) + sql_trigger_instances_entry_increase = ( + """ + CREATE TRIGGER instances_entry_increase + AFTER INSERT ON combination_entries_tags_jids + FOR EACH ROW + BEGIN + UPDATE main_entries + SET instances = ( + SELECT COUNT(DISTINCT jid_id) + FROM combination_entries_tags_jids + WHERE entry_id = NEW.entry_id + ) + WHERE id = NEW.entry_id; + END; + """ + ) + sql_trigger_instances_entry_update = ( + """ + CREATE TRIGGER instances_entry_update + AFTER UPDATE ON combination_entries_tags_jids + FOR EACH ROW + BEGIN + -- Decrease instances for the old tag_id + UPDATE main_entries + SET instances = ( + SELECT COUNT(DISTINCT jid_id) + FROM combination_entries_tags_jids + WHERE entry_id = OLD.entry_id + ) + WHERE id = OLD.entry_id; + + -- Increase instances for the new tag_id + UPDATE main_entries + SET instances = ( + SELECT COUNT(DISTINCT jid_id) + FROM combination_entries_tags_jids + WHERE entry_id = NEW.entry_id + ) + WHERE id = NEW.entry_id; + END; + """ + ) sql_trigger_instances_tag_decrease = ( """ CREATE TRIGGER instances_tag_decrease @@ -2643,6 +2775,17 @@ class SQLite: END; """ ) + sql_trigger_entry_remove = ( + """ + CREATE TRIGGER entry_remove + AFTER UPDATE ON main_entries + FOR EACH ROW + WHEN NEW.instances < 1 + BEGIN + DELETE FROM main_entries WHERE id = OLD.id; + END; + """ + ) sql_trigger_jid_count_increase = ( """ CREATE TRIGGER jid_count_increase @@ -2727,6 +2870,17 @@ class SQLite: END; """ ) + sql_trigger_tag_remove = ( + """ + CREATE TRIGGER tag_remove + AFTER UPDATE ON main_tags + FOR EACH ROW + WHEN NEW.instances < 1 + BEGIN + DELETE FROM main_tags WHERE id = OLD.id; + END; + """ + ) cur = conn.cursor() cur.execute(sql_table_main_entries) cur.execute(sql_table_main_jids) @@ -2736,18 +2890,23 @@ class SQLite: cur.execute(sql_table_authorization_entries_jids) cur.execute(sql_table_report_entries) cur.execute(sql_table_report_jids) + cur.execute(sql_trigger_instances_entry_decrease) + cur.execute(sql_trigger_instances_entry_increase) + cur.execute(sql_trigger_instances_entry_update) cur.execute(sql_trigger_instances_tag_decrease) cur.execute(sql_trigger_instances_tag_increase) cur.execute(sql_trigger_instances_tag_update) cur.execute(sql_trigger_entry_count_increase) cur.execute(sql_trigger_entry_count_decrease) cur.execute(sql_trigger_entry_count_update) + cur.execute(sql_trigger_entry_remove) cur.execute(sql_trigger_jid_count_increase) cur.execute(sql_trigger_jid_count_decrease) cur.execute(sql_trigger_jid_count_update) cur.execute(sql_trigger_tag_count_increase) cur.execute(sql_trigger_tag_count_decrease) cur.execute(sql_trigger_tag_count_update) + cur.execute(sql_trigger_tag_remove) def add_statistics(db_file): """ @@ -3022,7 +3181,7 @@ class SQLite: result = cur.execute(sql, par).fetchone() return result[0] if result and len(result) == 1 else result - async def delete_combination_row_by_entry_id_and_tag_id_and_jid_id(db_file, url_hash, tags, jid): + async def delete_combination_row_by_url_hash_and_tag_and_jid(db_file, url_hash, tags, jid): """ Delete a row by a given entry ID and a given Jabber ID and given tags. @@ -3042,8 +3201,8 @@ class SQLite: None. """ function_name = sys._getframe().f_code.co_name -# logger.debug('{}: db_file: {} entry_id: {} tag_id: {} jid_id: {}' -# .format(function_name, db_file, entry_id, tag_id, jid_id)) +# logger.debug('{}: db_file: {} url_hash: {} tag_id: {} jid_id: {}' +# .format(function_name, db_file, url_hash, tag_id, jid_id)) sql = ( """ DELETE @@ -3168,6 +3327,77 @@ class SQLite: result = cur.execute(sql, par).fetchall() return result + def get_jids_and_tags_by_entry_id(db_file, entry_id): + """ + Get JIDs and tags by a given ID entry. + + Parameters + ---------- + db_file : str + Path to database file. + entry_id : str + An ID of an entry. + + Returns + ------- + result : tuple + JIDs and tags. + """ + function_name = sys._getframe().f_code.co_name +# logger.debug('{}: db_file: {} index_first: {}' +# .format(function_name, db_file, index_first)) + sql = ( + """ + SELECT main_jids.jid, main_tags.tag + FROM main_tags + INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id + INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id + WHERE combination_entries_tags_jids.entry_id = ? + ORDER BY main_tags.instances DESC; + """ + ) + par = (entry_id,) + with SQLite.create_connection(db_file) as conn: + cur = conn.cursor() + result = cur.execute(sql, par).fetchall() + return result + + def get_jids_and_tags_by_url_hash(db_file, url_hash): + """ + Get JIDs and tags by a given URI hash. + + Parameters + ---------- + db_file : str + Path to database file. + url_hash : str + A URL hash of an entry. + + Returns + ------- + result : tuple + JIDs and tags. + """ + function_name = sys._getframe().f_code.co_name +# logger.debug('{}: db_file: {} index_first: {}' +# .format(function_name, db_file, index_first)) + sql = ( + """ + SELECT main_jids.jid, main_tags.tag + FROM main_tags + INNER JOIN combination_entries_tags_jids ON main_tags.id = combination_entries_tags_jids.tag_id + INNER JOIN main_jids ON main_jids.id = combination_entries_tags_jids.jid_id + INNER JOIN main_entries ON main_entries.id = combination_entries_tags_jids.entry_id + WHERE main_entries.url_hash = ? + ORDER BY main_tags.instances DESC; + """ + ) + par = (url_hash,) + with SQLite.create_connection(db_file) as conn: + cur = conn.cursor() + result = cur.execute(sql, par).fetchall() + return result + def get_tag_id_by_tag(db_file, tag): """ Get a tag ID by a given tag. diff --git a/configuration.toml b/configuration.toml index b0cf4a8..cdf86ba 100644 --- a/configuration.toml +++ b/configuration.toml @@ -1,9 +1,9 @@ # Contact [contacts] email = "" -xmpp = "" +xmpp = "sch@pimux.de" mix = "" -muc = "" +muc = "syndication@conference.movim.eu" irc_channel = "#blasta" irc_server = "" diff --git a/stylesheet/stylesheet.css b/stylesheet/stylesheet.css index f66c9a4..5892e78 100644 --- a/stylesheet/stylesheet.css +++ b/stylesheet/stylesheet.css @@ -115,15 +115,15 @@ h3, h4, h5 { padding: 0 0.4em; } -.title:first-child { +#posts > dd:first-child { margin-block-start: 2.22em; } -.title { +#posts > dd { margin-block-start: 1.33em; } -.title > h4 { +article > h4 { display: inline; } /* diff --git a/stylesheet/stylesheet.xsl b/stylesheet/stylesheet.xsl index 2b04756..998662c 100644 --- a/stylesheet/stylesheet.xsl +++ b/stylesheet/stylesheet.xsl @@ -11,8 +11,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'> + indent = 'yes' /> @@ -67,7 +66,7 @@ xmlns:atom='http://www.w3.org/2005/Atom'>

-   +  

diff --git a/template/contact.xhtml b/template/contact.xhtml index 9e5cb35..fe755b1 100644 --- a/template/contact.xhtml +++ b/template/contact.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/edit.xhtml b/template/edit.xhtml index 837c25b..a8a99e1 100644 --- a/template/edit.xhtml +++ b/template/edit.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
@@ -201,6 +204,17 @@ to view details.">   + {% if message %} +

+ + {{message}} + {% if message_link %} + + {{message_link['text']}}. + {% endif %} + +

+ {% endif %}

Fields that are marked with an asterisk diff --git a/template/feeds.xhtml b/template/feeds.xhtml index 2b14ed2..3ff3206 100644 --- a/template/feeds.xhtml +++ b/template/feeds.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +

+ Add +
Public
diff --git a/template/folksonomy.xhtml b/template/folksonomy.xhtml new file mode 100644 index 0000000..990262f --- /dev/null +++ b/template/folksonomy.xhtml @@ -0,0 +1,209 @@ + + + + + + + + Blasta / questions + + + + + +
+ +
+
+

  PubSub Bookmarks

+

+ » A practice for people to organize and share information in + a collaborative and decentralized manner. +

+

+ Folksonomy +

+

+ Folksonomy is a system of classification that is created by + individual people, rather than by professionals (who + sometimes refer themselves as experts) such as archivers or + librarians. It is a fashion for people to collaboratively + tag and categorize information, often using keywords or + labels. +

+

+ Characteristics +

+

+ Among the characteristics of folksonomy are: independency, + collaborativeness, and being dynamic; +

+

+ Tags are self-generated by individual people, not by a + centralized authority; +

+

+ Tags can be added by multiple people to the same item, + and thereby they create a collective understanding; +

+

+ Tags can be added, removed, and updated over time, + reflecting evolving usage, accuracy and interests; +

+

+ There is no single source of truth or control over the + tagging process. +

+

+ Benefits +

+

+ Because people can easily find relevant content by searching + for specific tags; and shared tagging promotes collective + understanding and knowledge creation; and people feel more + involved and empowered by contributing their own insights. +

+

+ The benefits of folksonomies spans from improved + discoverability of contents to enhanced collaboration and + increased engagement of people by contributing and + benefiting to the overhaul system. +

+

+ It was written in Adam Mathes' recent paper on folksonomies that: +

+

+ “There is a fundamental difference in the activities of + browsing to find interesting content, as opposed to direct + searching to find relevant documents in a query. It is + similar to the difference between exploring a problem space + to formulate questions, as opposed to actually looking for + answers to specifically formulated questions. Information + seeking behavior varies based on context.” +

+

+ Conclusion +

+

+ By practicing and engaging in folksonomy systems, people + find many interesting resources that are related to their + special and specific needs, that they could not have found + using search engines. Blasta has some interesting advantages + over search engines, and one of them is being folksonomy + driven. +

+

+ The power of the people cannot be more evident than the + awesome resource that is Wikipedia, albeit is has been + gradually controlled by + + special interests. Imagine what might happen if a search + engine (e.g. YaCy) can be engineered by people! +

+

+ Resources +

+

+

+

+
+

+ “I think the lack of hierarchy, synonym control and semantic + precision are precisely why it works. Free typing loose + associations is just a lot easier than making a decision + about the degree of match to a pre-defined category + (especially hierarchical ones).” + ― Stewart Butterfield +

+
+
+ +
+ + diff --git a/template/help.xhtml b/template/help.xhtml index 078dbac..f297099 100644 --- a/template/help.xhtml +++ b/template/help.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
@@ -64,6 +67,7 @@

About

Blasta

+

Folksonomy

Ideas

Philosophy

Projects

diff --git a/template/ideas.xhtml b/template/ideas.xhtml index 5a5f884..b7a928b 100644 --- a/template/ideas.xhtml +++ b/template/ideas.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/libervia.xhtml b/template/libervia.xhtml index 4f11224..61d2c9d 100644 --- a/template/libervia.xhtml +++ b/template/libervia.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/movim.xhtml b/template/movim.xhtml index 171fe56..18a05fa 100644 --- a/template/movim.xhtml +++ b/template/movim.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/now.xhtml b/template/now.xhtml index b0fdeb8..2b02fbe 100644 --- a/template/now.xhtml +++ b/template/now.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/people.xhtml b/template/people.xhtml new file mode 100644 index 0000000..449f01b --- /dev/null +++ b/template/people.xhtml @@ -0,0 +1,256 @@ + + + + + + + + Blasta / {{path}} + + + + + + + +
+ +
+
+

  PubSub Bookmarks

+ {% if pager %} + {% if page_next or page_prev %} + + {% endif %} + {% endif %} +

» {{message}}

+

{{description}}

+ {% if entries %} +
+ {% for entry in entries %} +
+
+

+ + {{entry['title']}} +

+ + + {% if jabber_id %} + {% if restore %} + restore + {% elif delete %} + confirm deletion + {% elif jabber_id == jid or exist or path in ('private', 'read') %} + + edit + / + + delete + {% else %} + + add + {% endif %} + {% endif %} +

{{entry['summary']}}

+
+ {% if entry['tags'] | length > 0 %} + to + {% for tag in entry['tags'] %} + + {{tag}} + + {% endfor %} + {% endif %} + at + + {{entry['published_mod']}} + +
+
+
+ {% endfor %} +
+ {% endif %} +
+
+ {% if people %} +

+ This resource is shared amongst {{entries[0]['instances']}} people +

+

+

+ {% for jid in people %} +
+
+
+ by {{jid}} +
+
+
+ to + {% if people[jid] | length > 0 %} + {% for tag in people[jid] %} + + {{tag}} + + {% endfor %} + {% endif %} +
+ + {% endfor %} +
+

+ {% endif %} +
+ +
+ {% if pager %} + {% if page_next or page_prev %} + + {% endif %} + {% endif %} +
+

+ 💡 + + PubSub + + and + ⚛ + + RSS + + + syndication feeds for this page are available. +

+
+ +
+ + diff --git a/template/philosophy.xhtml b/template/philosophy.xhtml index 7c0146c..5e6612f 100644 --- a/template/philosophy.xhtml +++ b/template/philosophy.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/profile.xhtml b/template/profile.xhtml index 0e47604..ecbcdd7 100644 --- a/template/profile.xhtml +++ b/template/profile.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/projects.xhtml b/template/projects.xhtml index 50d0cc0..0628ade 100644 --- a/template/projects.xhtml +++ b/template/projects.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/pubsub.xhtml b/template/pubsub.xhtml index b458e8f..946bdea 100644 --- a/template/pubsub.xhtml +++ b/template/pubsub.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/questions.xhtml b/template/questions.xhtml index b7abc01..0fd533f 100644 --- a/template/questions.xhtml +++ b/template/questions.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
@@ -79,7 +82,9 @@

The method instance:keyword is a practice which improves bookmarks organizing, archiving, filtering and searching, as - it narrows the context of a given bookmark. + it narrows the context of a given bookmark, and therefore + improves Folksonomy + practices.

Suppose you have two bookmarks; one is related to diff --git a/template/register.xhtml b/template/register.xhtml index 02e2a71..9b848e4 100644 --- a/template/register.xhtml +++ b/template/register.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +

+ Add +
Public
diff --git a/template/result.xhtml b/template/result.xhtml index f36a3bf..c26f3e6 100644 --- a/template/result.xhtml +++ b/template/result.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/search.xhtml b/template/search.xhtml index f97da89..c2d057a 100644 --- a/template/search.xhtml +++ b/template/search.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
@@ -33,7 +36,7 @@ {% endif %}
- Search + Search
Popular diff --git a/template/software.xhtml b/template/software.xhtml index effdb33..4647a2b 100644 --- a/template/software.xhtml +++ b/template/software.xhtml @@ -22,6 +22,9 @@
{% if jabber_id %} +
+ Add +
Public
diff --git a/template/syndication.xhtml b/template/syndication.xhtml index d37a8f2..3792f00 100644 --- a/template/syndication.xhtml +++ b/template/syndication.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/tag.xhtml b/template/tag.xhtml index 67adf39..56bf5ee 100644 --- a/template/tag.xhtml +++ b/template/tag.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/thanks.xhtml b/template/thanks.xhtml index b86f8c9..33bb5fe 100644 --- a/template/thanks.xhtml +++ b/template/thanks.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/utilities.xhtml b/template/utilities.xhtml index 5630f6f..2351446 100644 --- a/template/utilities.xhtml +++ b/template/utilities.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public
diff --git a/template/xmpp.xhtml b/template/xmpp.xhtml index 2f56cc6..3ab7463 100644 --- a/template/xmpp.xhtml +++ b/template/xmpp.xhtml @@ -22,6 +22,9 @@ {% if jabber_id %} +
+ Add +
Public