2020-11-07 14:34:48 +00:00
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import datetime
2021-01-02 16:48:04 +00:00
from flask import Blueprint , url_for , render_template , current_app , Response , redirect , request
2020-11-07 14:34:48 +00:00
from markupsafe import escape
2021-01-02 16:48:04 +00:00
from slugify import slugify , SLUG_OK
2020-11-07 18:38:01 +00:00
from . import config
2020-11-16 15:39:30 +00:00
from . import db
from . import forms
2020-12-04 21:11:44 +00:00
from . import util
2020-11-07 14:34:48 +00:00
bp = Blueprint ( ' agora ' , __name__ )
2020-12-27 19:19:52 +00:00
G = db . G
2020-12-12 19:44:00 +00:00
# Special
2020-11-23 13:45:26 +00:00
@bp.route ( ' /index ' )
2020-11-07 14:34:48 +00:00
@bp.route ( ' / ' )
def index ( ) :
2021-01-09 16:38:01 +00:00
return redirect ( url_for ( ' .node ' , node = ' index ' ) )
2020-11-07 14:34:48 +00:00
@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 <a href= " https://flancia.org/go/agora " >code</a>. '
2020-11-17 09:49:21 +00:00
@bp.route ( ' /latest ' )
def latest ( ) :
return render_template ( ' subnodes.html ' , header = " Latest " , subnodes = db . latest ( ) )
2020-11-07 14:34:48 +00:00
@bp.route ( ' /today ' )
def today ( ) :
today = datetime . datetime . now ( ) . date ( )
return redirect ( " https://anagora.org/node/ %s " % today . strftime ( " % Y- % m- %d " ) )
2020-12-12 19:44:00 +00:00
@bp.route ( ' /search ' , methods = ( ' GET ' , ' POST ' ) )
def search ( ) :
form = forms . SearchForm ( )
if form . validate_on_submit ( ) :
return render_template ( ' search.html ' , form = form , subnodes = db . search_subnodes ( form . query . data ) )
return render_template ( ' search.html ' , form = form )
# Actions
2020-11-22 17:54:08 +00:00
@bp.route ( ' /go/<node> ' )
def go ( node ) :
""" Redirects to the URL in the given node in a block that starts with [[go]], if there is one. """
# TODO(flancian): all node-scoped stuff should move to actually use node objects.
try :
n = db . nodes_by_wikilink ( node )
except KeyError :
return redirect ( " https://anagora.org/node/ %s " % node )
if len ( n ) > 1 :
current_app . logger . warning ( ' nodes_by_wikilink returned more than one node, should not happen. ' )
if len ( n ) == 0 :
# No nodes with this name -- redirect to node 404.
return redirect ( " https://anagora.org/node/ %s " % node )
links = n [ 0 ] . go ( )
if len ( links ) == 0 :
# No go links detected in this node -- just redirect to the node.
# TODO(flancian): flash an explanation :)
return redirect ( " https://anagora.org/node/ %s " % node )
if len ( links ) > 1 :
# TODO(flancian): to be implemented.
# Likely default to one of the links, show all of them but redirect to default within n seconds.
current_app . logger . warning ( ' Code to manage nodes with more than one go link is not Not implemented. ' )
return redirect ( links [ 0 ] )
2020-12-12 19:44:00 +00:00
@bp.route ( ' /pull/<node> ' )
def pull ( node ) :
""" In the context of a node, " pulls attention " from the parameter node to the current subnode.
Here it " broadcasts " : it renders all nodes that pull from a given node .
Unclear at this point if this should exist at all , or whether it should do something else .
2021-01-02 16:48:04 +00:00
TODO : probably remove this , [ [ pull ] ] changed .
2020-12-12 19:44:00 +00:00
"""
return redirect ( ' /node/ {} ' . format ( node ) )
2021-01-02 16:48:04 +00:00
@bp.route ( ' /jump ' )
def jump ( ) :
2021-01-02 16:52:13 +00:00
""" Redirects to a context; in " jump " mode, a node *always* exists (nodes map one to one to all possible queries). """
q = request . args . get ( ' q ' )
return redirect ( url_for ( ' .node ' , node = slugify ( q ) ) )
2020-12-23 21:36:31 +00:00
2020-12-12 19:44:00 +00:00
# Entities
2021-01-02 16:48:04 +00:00
@bp.route ( ' /wikilink/<node> ' )
2020-12-21 11:32:00 +00:00
@bp.route ( ' /node/<node> ' )
2021-01-02 16:48:04 +00:00
def node ( node ) :
2020-12-22 00:08:47 +00:00
2020-12-27 19:41:59 +00:00
n = G . node ( node )
2021-01-09 16:38:01 +00:00
# earlier in the list means more highly ranked.
n . subnodes = util . uprank ( n . subnodes , users = [ ' agora ' , ' flancian ' ] )
2020-12-29 19:22:49 +00:00
2021-01-02 19:29:07 +00:00
search_subnodes = db . search_subnodes ( node )
2020-12-21 11:32:00 +00:00
return render_template (
' node_rendered.html ' ,
2020-12-27 19:41:59 +00:00
node = n ,
2021-01-04 18:20:44 +00:00
backlinks = n . back_links ( ) ,
2020-12-27 19:41:59 +00:00
pull_nodes = n . pull_nodes ( ) if n else [ ] ,
2020-12-22 00:08:47 +00:00
forwardlinks = n . forward_links ( ) if n else [ ] ,
2021-01-03 01:12:27 +00:00
search = search_subnodes ,
2021-01-04 18:20:44 +00:00
pulling_nodes = n . pulling_nodes ( ) ,
2021-01-05 00:58:53 +00:00
pushing_nodes = n . pushing_nodes ( ) ,
2021-01-03 01:12:27 +00:00
query = n . wikilink . replace ( ' - ' , ' % 20 ' )
2020-12-21 11:32:00 +00:00
)
2021-01-09 16:38:01 +00:00
@bp.route ( ' /node/<node>@<user> ' )
@bp.route ( ' /@<user>/<node> ' )
def subnode ( node , user ) :
n = G . node ( node )
n . subnodes = util . filter ( n . subnodes , user )
search_subnodes = db . search_subnodes_by_user ( node , user )
return render_template (
' subnode_rendered.html ' ,
node = n ,
#backlinks=n.back_links(),
#pull_nodes=n.pull_nodes() if n else [],
#forwardlinks=n.forward_links() if n else [],
#search=search_subnodes,
#pulling_nodes=n.pulling_nodes(),
#pushing_nodes=n.pushing_nodes(),
#query=n.wikilink.replace('-', '%20')
)
2020-12-21 11:32:00 +00:00
@bp.route ( ' /subnode/<path:subnode> ' )
2021-01-09 16:38:01 +00:00
def old_subnode ( subnode ) :
2020-12-21 11:32:00 +00:00
return render_template ( ' subnode_rendered.html ' , subnode = db . subnode_by_uri ( subnode ) , backlinks = db . subnodes_by_outlink ( subnode ) )
2020-11-10 21:48:20 +00:00
@bp.route ( ' /u/<user> ' )
@bp.route ( ' /user/<user> ' )
2020-11-14 18:11:05 +00:00
@bp.route ( ' /@<user> ' )
2020-11-10 21:48:20 +00:00
def user ( user ) :
2020-11-16 20:29:37 +00:00
return render_template ( ' user.html ' , user = user , readmes = db . user_readmes ( user ) , subnodes = db . subnodes_by_user ( user ) )
2020-11-07 14:34:48 +00:00
@bp.route ( ' /garden/<garden> ' )
def garden ( garden ) :
current_app . logger . warning ( ' Not implemented. ' )
return ' If I had implemented rendering gardens already, here you would see garden named " %s " . ' % escape ( garden )
2020-12-12 19:44:00 +00:00
# Lists
@bp.route ( ' /nodes ' )
def nodes ( ) :
2020-12-27 19:19:52 +00:00
return render_template ( ' nodes.html ' , nodes = G . nodes ( include_journals = False ) )
2020-12-12 19:44:00 +00:00
@bp.route ( ' /notes ' ) # alias
@bp.route ( ' /subnodes ' )
def subnodes ( ) :
2020-12-27 19:19:52 +00:00
return render_template ( ' subnodes.html ' , subnodes = G . subnodes ( ) )
2020-12-12 19:44:00 +00:00
@bp.route ( ' /users ' )
def users ( ) :
return render_template ( ' users.html ' , users = db . all_users ( ) )
@bp.route ( ' /journals ' )
def journals ( ) :
return render_template ( ' nodes.html ' , header = " Journals " , nodes = db . all_journals ( ) )
# Searching with GET: potentially useful but probably not a good idea.
2020-11-16 15:39:30 +00:00
# @bp.route('/search/<query>')
# def search(query):
# return render_template('subnodes.html', subnodes=db.search_subnodes(query))
2020-11-16 14:51:34 +00:00
2020-11-07 18:38:01 +00:00
@bp.route ( ' /asset/<user>/<asset> ' )
def asset ( user , asset ) :
# An asset is a binary in someone's garden/<user>/assets directory.
2020-11-16 14:51:34 +00:00
# Currently unused.
2020-11-07 18:38:01 +00:00
path = ' / ' . join ( [ " garden " , user , ' assets ' , asset ] )
return current_app . send_static_file ( path )
2020-11-07 14:34:48 +00:00
@bp.route ( ' /raw/<node> ' )
def raw ( node ) :
2020-11-16 14:51:34 +00:00
# Currently unused.
2020-11-07 14:34:48 +00:00
# hack hack
# outlinks
return Response ( " \n \n " . join ( [ str ( n . outlinks ) for n in db . nodes_by_wikilink ( node ) ] ) , mimetype = " text/plain " )
# content
# return Response("\n\n".join([n.content for n in db.nodes_by_wikilink(node)]), mimetype="text/plain")
@bp.route ( ' /backlinks/<node> ' )
def backlinks ( node ) :
2020-11-16 14:51:34 +00:00
# Currently unused.
2020-11-07 14:34:48 +00:00
return render_template ( ' nodes.html ' , nodes = db . nodes_by_outlink ( node ) )