From fc75e469c0adcd2fae332dd6bdcadc11b5b35382 Mon Sep 17 00:00:00 2001
From: Flancian <0@flancia.org>
Date: Tue, 10 Nov 2020 22:48:20 +0100
Subject: [PATCH] Some good progress, but also lightly broken code :)
---
app/agora.py | 31 ++++--
app/config.py | 4 +
app/db.py | 99 +++++++++++++++++--
app/templates/base.html | 5 +-
app/templates/index.html | 5 +-
...nodes_rendered.html => node_rendered.html} | 18 ++--
app/templates/nodes.html | 5 +-
app/templates/subnode_rendered.html | 35 +++++++
app/templates/subnodes.html | 23 +++++
app/templates/users.html | 23 +++++
10 files changed, 219 insertions(+), 29 deletions(-)
rename app/templates/{nodes_rendered.html => node_rendered.html} (62%)
create mode 100644 app/templates/subnode_rendered.html
create mode 100644 app/templates/subnodes.html
create mode 100644 app/templates/users.html
diff --git a/app/agora.py b/app/agora.py
index 299635c..948ddb1 100644
--- a/app/agora.py
+++ b/app/agora.py
@@ -22,33 +22,40 @@ bp = Blueprint('agora', __name__)
@bp.route('/')
def index():
- return render_template('index.html', help=url_for('agora.help'), nodes=url_for('agora.nodes'), journals=url_for('agora.journals'))
+ return render_template('index.html', help=url_for('agora.help'), nodes=url_for('agora.nodes'), subnodes=url_for('agora.subnodes'), users=url_for('agora.users'), journals=url_for('agora.journals'))
@bp.route('/help')
def help():
current_app.logger.warning('Not implemented.')
return 'If I had implemented help already, here you\'d see documentation on all URL endpoints. For now, please refer to the code.'
-@bp.route('/notes') # alias for now
@bp.route('/nodes')
def nodes():
- current_app.logger.warning('Config: %s' % config.AGORA_PATH)
+ # current_app.logger.warning('Config: %s' % config.AGORA_PATH)
return render_template('nodes.html', nodes=db.all_nodes())
+@bp.route('/notes') # alias
+@bp.route('/subnodes')
+def subnodes():
+ return render_template('subnodes.html', subnodes=db.all_subnodes())
+
+@bp.route('/users')
+def users():
+ return render_template('users.html', users=db.all_users())
+
@bp.route('/journals')
def journals():
- return render_template('nodes.html', nodes=db.all_journals())
+ return render_template('subnodes.html', nodes=db.all_journals())
@bp.route('/today')
def today():
today = datetime.datetime.now().date()
return redirect("https://anagora.org/node/%s" % today.strftime("%Y-%m-%d"))
-@bp.route('/u/')
-@bp.route('/user/')
-def user(username):
- current_app.logger.warning('Not implemented.')
- return 'If I had implemented reading user profiles already, here you would see user named "%s".' % escape(username)
+@bp.route('/u/')
+@bp.route('/user/')
+def user(user):
+ return render_template('subnodes.html', nodes=db.subnodes_by_user(user))
@bp.route('/garden/')
def garden(garden):
@@ -58,7 +65,11 @@ def garden(garden):
@bp.route('/node/')
@bp.route('/wikilink/') # alias for now
def wikilink(node):
- return render_template('nodes_rendered.html', wikilink=node, nodes=db.nodes_by_wikilink(node), backlinks=db.nodes_by_outlink(node))
+ return render_template('node_rendered.html', wikilink=node, subnodes=db.subnodes_by_wikilink(node), backlinks=db.subnodes_by_outlink(node))
+
+@bp.route('/subnode/')
+def subnode(subnode):
+ return render_template('subnode_rendered.html', subnode=db.subnode_by_uri(subnode), backlinks=db.subnodes_by_outlink(subnode))
@bp.route('/asset//')
def asset(user, asset):
diff --git a/app/config.py b/app/config.py
index ce4bbae..257c0c9 100644
--- a/app/config.py
+++ b/app/config.py
@@ -1,3 +1,7 @@
import os
import getpass
+
AGORA_PATH = os.path.join('/home', getpass.getuser(), 'agora')
+
+# With trailing slash.
+URL_BASE = "https://anagora.org/"
diff --git a/app/db.py b/app/db.py
index 9153fdf..ce07ca0 100644
--- a/app/db.py
+++ b/app/db.py
@@ -20,18 +20,76 @@ from operator import attrgetter
RE_WIKILINKS = re.compile('\[\[(.*?)\]\]')
+# URIs are ids.
+# - In the case of nodes, their [[wikilink]].
+# - Example: 'foo', meaning the node that is rendered when you click on [[foo]] somewhere.
+# - In the case of subnodes, a relative path within the Agora.
+# - Example: 'garden/flancian/README.md', meaning an actual file called README.md.
+# - Note the example subnode above gets rendered in node [[README]], so fetching node with uri README would yield it (and others).
+
+# TODO: implement.
+class Graph:
+ def __init__(self):
+ # [[wikilink]] -> Node
+ self.nodes = {}
+ # node -> [n0, ..., nn] such that node has outlinks to the target list.
+ self.edges = {}
+ def addsubnode(self, subnode):
+ if subnode.wikilink in self.nodes:
+ G.nodes[subnode.wikilink].subnodes.append(subnode)
+ else:
+ G.nodes[subnode.wikilink] = Node(subnode.wikilink)
+
+G = Graph()
+
class Node:
+ """Nodes map 1:1 to wikilinks.
+ They resolve to a series of subnodes when being rendered (see below).
+ It maps to a particular file in the Agora repository, stored (relative to
+ the Agora root) in the attribute 'uri'."""
+ def __init__(self, wikilink):
+ # Use a node's URI as its identifier.
+ # Subnodes are attached to the node matching their wikilink.
+ # i.e. if two users contribute subnodes titled [[foo]], they both show up when querying node [[foo]].
+ self.wikilink = wikilink
+ self.uri = wikilink
+ self.url = '/node/' + self.uri
+ self.subnodes = []
+
+class Subnode:
+ """A subnode is a note or media resource volunteered by a user of the Agora.
+ It maps to a particular file in the Agora repository, stored (relative to
+ the Agora root) in the attribute 'uri'."""
def __init__(self, path):
- self.dir = path_to_url(path)
+ # Use a subnode's URI as its identifier.
+ self.uri = path_to_uri(path)
+ self.url = '/subnode/' + path_to_uri(path)
+ # Subnodes are attached to the node matching their wikilink.
+ # i.e. if two users contribute subnodes titled [[foo]], they both show up when querying node [[foo]].
self.wikilink = path_to_wikilink(path)
- self.url = '/node/' + self.wikilink
+ self.user = path_to_user(path)
with open(path) as f:
self.content = f.read()
self.outlinks = content_to_outlinks(self.content)
+ self.node = self.wikilink
+ # Initiate node for wikilink if this is the first subnode, append otherwise.
+ G.addsubnode(self)
-def path_to_url(path):
+class User:
+ def __init__(self, user):
+ self.uri = user
+ self.url = '/user/' + self.uri
+
+def path_to_uri(path):
return path.replace(config.AGORA_PATH + '/', '')
+def path_to_user(path):
+ m = re.search('garden/(.+?)/', path)
+ if m:
+ return m.group(1)
+ else:
+ return 'agora'
+
def path_to_wikilink(path):
return os.path.splitext(os.path.basename(path))[0]
@@ -43,19 +101,46 @@ def content_to_outlinks(content):
else:
return []
-def all_nodes():
+def all_subnodes():
l = sorted([f for f in glob.glob(os.path.join(config.AGORA_PATH, '**/*.md'), recursive=True)])
- return [Node(f) for f in l]
+ return [Subnode(f) for f in l]
+
+def all_nodes():
+ # hack hack.
+ l = all_subnodes()
+ return sorted([Node(sn.wikilink) for sn in l], key=attrgetter('wikilink'))
+
+def all_users():
+ # hack hack.
+ users = os.listdir(os.path.join(config.AGORA_PATH, 'garden'))
+ return sorted([User(u) for u in users], key=attrgetter('uri'))
def all_journals():
# hack hack.
- l = sorted([f for f in glob.glob(os.path.join(config.AGORA_PATH, '**/????-??-??.md'), recursive=True)])
- return sorted([Node(f) for f in l], key=attrgetter('wikilink'), reverse=True)
+ l = all_subnodes()
+ # return sorted([sn for sn in l], key=attrgetter('wikilink'), reverse=True)
+ return sorted([f for f in glob.glob(os.path.join(config.AGORA_PATH, '**/????-??-??.md'), recursive=True)])
def nodes_by_wikilink(wikilink):
nodes = [node for node in all_nodes() if node.wikilink == wikilink]
return nodes
+def subnodes_by_wikilink(wikilink):
+ subnodes = [subnode for subnode in all_subnodes() if subnode.wikilink == wikilink]
+ return subnodes
+
+def subnodes_by_user(user):
+ subnodes = [subnode for subnode in all_subnodes() if subnode.user == user]
+ return subnodes
+
+def subnode_by_uri(uri):
+ subnode = [subnode for subnode in all_subnodes() if subnode.uri == uri][0]
+ return subnode
+
def nodes_by_outlink(wikilink):
nodes = [node for node in all_nodes() if wikilink in node.outlinks]
return nodes
+
+def subnodes_by_outlink(wikilink):
+ subnodes = [subnode for subnode in all_subnodes() if wikilink in subnode.outlinks]
+ return subnodes
diff --git a/app/templates/base.html b/app/templates/base.html
index 4dc373f..e2252df 100644
--- a/app/templates/base.html
+++ b/app/templates/base.html
@@ -29,7 +29,10 @@
|
- /nodes | /journals
+ /nodes
+ | /subnodes
+ | /journals
+ | /users
help
diff --git a/app/templates/index.html b/app/templates/index.html
index bc4a903..2f7e861 100644
--- a/app/templates/index.html
+++ b/app/templates/index.html
@@ -18,12 +18,13 @@
{% block content %}
Ahoy, matey!
-This is the Agora v0.5a.
+This is the Agora v0.5b.
This site is very much under construction, but feel free to look around:
- - {{nodes}} lists all nodes in this Agora; currently these are mostly notes as volunteered by users.
+ - {{nodes}} lists all nodes in this Agora, created out of aggregating subnodes (mostly notes currently) volunteered by users.
- {{journals}} displays all journal entries.
+ - {{users}} displays all users.
The [[wikilink]] is the heart of the Agora. /node/foo and /wikilink/foo will both render every node that responds to wikilink [[foo]]. For example: [[agora-help]].
diff --git a/app/templates/nodes_rendered.html b/app/templates/node_rendered.html
similarity index 62%
rename from app/templates/nodes_rendered.html
rename to app/templates/node_rendered.html
index 23c0049..8560f2d 100644
--- a/app/templates/nodes_rendered.html
+++ b/app/templates/node_rendered.html
@@ -16,22 +16,24 @@
{% extends "base.html" %}
{% block content %}
-{% if not nodes %}
-No nodes found for '{{wikilink}}'.
+{% if not subnodes %}
+No node found for '{{wikilink}}'.
-If you contributed a node named '{{wikilink}}' to the Agora, here is where your node would be :)
+If you contributed a subnode named '{{wikilink}}' to the Agora, this node would not be empty :)
Go back to /nodes?
{% endif %}
-{% for node in nodes %}
-{{ node.dir }}: {{node.wikilink}}
-{{ node.content|markdown|linkify|safe }}
+{% for subnode in subnodes %}
+{{ subnode.uri }}: {{subnode.wikilink}}
+{{ subnode.content|markdown|linkify|safe }}
{% endfor %}
+
+
Backlinks:
-{% for node in backlinks %}
-{{ node.dir }}: {{node.wikilink}}
+{% for subnode in backlinks %}
+{{ subnode.uri }}: {{subnode.wikilink}}
{% endfor %}
{% endblock %}
diff --git a/app/templates/nodes.html b/app/templates/nodes.html
index a457811..ae2a98c 100644
--- a/app/templates/nodes.html
+++ b/app/templates/nodes.html
@@ -18,6 +18,9 @@
Nodes
{% block content %}
{% for node in nodes %}
-{{ node.dir }}: {{node.wikilink}}
+{% for subnode in node.subnodes %}}
+{% subnode.user %}
+{% endfor %}
+{{node.wikilink}}
{% endfor %}
{% endblock %}
diff --git a/app/templates/subnode_rendered.html b/app/templates/subnode_rendered.html
new file mode 100644
index 0000000..634ed34
--- /dev/null
+++ b/app/templates/subnode_rendered.html
@@ -0,0 +1,35 @@
+
+
+{% extends "base.html" %}
+{% block content %}
+{% if not subnode %}
+No subnode found matching '{{subnode}}'.
+
+Go back to /nodes?
+{% endif %}
+
+{{ subnode.uri }}: {{subnode.wikilink}}
+{{ subnode.content|markdown|linkify|safe }}
+
+
+
+Backlinks:
+{% for subnode in backlinks %}
+{{ subnode.uri }}: {{subnode.wikilink}}
+{% endfor %}
+
+{% endblock %}
diff --git a/app/templates/subnodes.html b/app/templates/subnodes.html
new file mode 100644
index 0000000..f639ef5
--- /dev/null
+++ b/app/templates/subnodes.html
@@ -0,0 +1,23 @@
+
+
+{% extends "base.html" %}
+ Subnodes
+{% block content %}
+{% for subnode in subnodes %}
+(user: {{subnode.user}}) {{ subnode.uri }}: {{subnode.wikilink}}
+{% endfor %}
+{% endblock %}
diff --git a/app/templates/users.html b/app/templates/users.html
new file mode 100644
index 0000000..9f758a5
--- /dev/null
+++ b/app/templates/users.html
@@ -0,0 +1,23 @@
+
+
+{% extends "base.html" %}
+ Users
+{% block content %}
+{% for user in users %}
+{{user.uri}}
+{% endfor %}
+{% endblock %}