Generate project_navigation_links

This function generates a list of selected links for important nodes such
as Pages and Blog. This list of links is used in the templates to provide
high level navigation of a Project.
This commit is contained in:
Francesco Siddi 2018-09-13 16:20:47 +02:00
parent c795015a3c
commit 9a9d15ce47
3 changed files with 169 additions and 12 deletions

View File

@ -94,6 +94,16 @@ def find_for_post(project, node):
url=node.properties.url)
@register_node_finder('page')
def find_for_page(project, node):
"""Returns the URL for a page."""
project_id = project['_id']
the_project = project_url(project_id, project=project)
return url_for('projects.view_node', project_url=the_project.url, node_id=node.properties.url)
def find_for_other(project, node):
"""Fallback: Assets, textures, and other node types.

View File

@ -24,6 +24,7 @@ from pillar import current_app
from pillar.api.utils import utcnow
from pillar.web import system_util
from pillar.web import utils
from pillar.web.nodes import finders
from pillar.web.utils.jstree import jstree_get_children
import pillar.extension
@ -302,6 +303,52 @@ def view(project_url):
'header_video_node': header_video_node})
def project_navigation_links(project, api) -> list:
"""Returns a list of nodes for the project, for top navigation display.
Args:
project: A Project object.
api: the api client credential.
Returns:
A list of links for the Project.
For example we display a link to the project blog if present, as well
as pages. The list is structured as follows:
[{'url': '/p/spring/about', 'label': 'About'},
{'url': '/p/spring/blog', 'label': 'Blog'}]
"""
links = []
# Fetch the blog
blog = Node.find_first({
'where': {'project': project._id, 'node_type': 'blog', '_deleted': {'$ne': True}},
'projection': {
'name': 1,
}
}, api=api)
if blog:
links.append({'url': finders.find_url_for_node(blog), 'label': blog.name})
# Fetch pages
pages = Node.all({
'where': {'project': project._id, 'node_type': 'page', '_deleted': {'$ne': True}},
'projection': {
'name': 1,
'properties.url': 1
}
}, api=api)
# Process the results and append the links to the list
for p in pages._items:
links.append({'url': finders.find_url_for_node(p), 'label': p.name})
return links
def render_project(project, api, extra_context=None, template_name=None):
project.picture_square = utils.get_file(project.picture_square, api=api)
project.picture_header = utils.get_file(project.picture_header, api=api)
@ -370,13 +417,7 @@ def render_project(project, api, extra_context=None, template_name=None):
extension_sidebar_links = current_app.extension_sidebar_links(project)
pages = Node.all({
'where': {'project': project._id, 'node_type': 'page', '_deleted': False},
'projection': {
'name': 1,
'url': 1
}
}, api=api)
navigation_links = project_navigation_links(project, api)
return render_template(template_name,
api=api,
@ -386,7 +427,7 @@ def render_project(project, api, extra_context=None, template_name=None):
show_project=True,
og_picture=project.picture_header,
activity_stream=activity_stream,
pages=pages._items,
navigation_links=navigation_links,
extension_sidebar_links=extension_sidebar_links,
**extra_context)
@ -456,16 +497,14 @@ def view_node(project_url, node_id):
# Append _theatre to load the proper template
theatre = '_theatre' if theatre_mode else ''
navigation_links = project_navigation_links(project, api)
if node.node_type == 'page':
pages = Node.all({
'where': {'project': project._id, 'node_type': 'page'},
'projection': {'name': 1}}, api=api)
return render_template('nodes/custom/page/view_embed.html',
api=api,
node=node,
project=project,
pages=pages._items,
navigation_links=navigation_links,
og_picture=og_picture,)
extension_sidebar_links = current_app.extension_sidebar_links(project)
@ -477,6 +516,7 @@ def view_node(project_url, node_id):
show_node=True,
show_project=False,
og_picture=og_picture,
navigation_links=navigation_links,
extension_sidebar_links=extension_sidebar_links)

View File

@ -0,0 +1,107 @@
from bson import ObjectId
from pillar.tests import AbstractPillarTest
from pillar.tests import common_test_data as ctd
from pillar.web import system_util
from pillar.web.projects.routes import project_navigation_links, find_project_or_404
class ProjectTest(AbstractPillarTest):
def setUp(self, **kwargs):
super().setUp(**kwargs)
self.pid, self.project = self.ensure_project_exists()
self.owner_uid = self.create_user(24 * 'a',
groups=[ctd.EXAMPLE_ADMIN_GROUP_ID],
token='admin-token')
# Create a Node of type page.
self.node_id = self.create_node({
'_id': ObjectId('572761099837730efe8e120d'),
'description': 'This the about page',
'node_type': 'page',
'user': self.owner_uid,
'properties': {
'status': 'published',
'url': 'about',
},
'name': 'About',
'project': self.pid,
})
self.user_uid = self.create_user(24 * 'b', groups=[ctd.EXAMPLE_ADMIN_GROUP_ID],
token='user-token')
def test_project_navigation_links_one_page(self):
"""Test link generation for project navigation."""
with self.app.test_request_context():
api = system_util.pillar_api()
project = find_project_or_404(self.project['url'], api=api)
navigation_links = project_navigation_links(project, api=api)
# We expect only one link to be in the list
links = [{'url': '/p/default-project/about', 'label': 'About'}]
self.assertListEqual(links, navigation_links)
def test_project_navigation_links_pages_and_blog(self):
"""Test link generation for a project with two Pages and one Blog."""
# Add one more page to the project
self.create_node({
'_id': ObjectId(),
'description': 'This the awards page',
'node_type': 'page',
'user': self.owner_uid,
'properties': {
'status': 'published',
'url': 'awards',
},
'name': 'Awards',
'project': self.pid,
})
# Create a Node of type blog.
self.create_node({
'_id': ObjectId(),
'description': 'This the blog page',
'node_type': 'blog',
'user': self.owner_uid,
'properties': {
'status': 'published',
},
'name': 'Blog',
'project': self.pid,
})
# Create a Node of type asset
self.create_node({
'_id': ObjectId(),
'description': 'This is an asset without file',
'node_type': 'asset',
'user': self.owner_uid,
'properties': {
'status': 'published',
'content_type': 'image',
},
'name': 'Image test',
'project': self.pid,
})
with self.app.test_request_context():
api = system_util.pillar_api()
project = find_project_or_404(self.project['url'], api=api)
navigation_links = project_navigation_links(project, api=api)
expected_list = [
{'url': '/blog/', 'label': 'Blog'}, # Blog is the first element of the list (since it's added first)
{'url': '/p/default-project/about', 'label': 'About'},
{'url': '/p/default-project/awards', 'label': 'Awards'}]
self.assertListEqual(expected_list, navigation_links)
def test_project_no_navigation_links(self):
"""Test link generation in a project with no Pages or Blog."""
with self.app.test_request_context():
# Delete the existing page from the database
self.app.db('nodes').delete_one({'_id': ObjectId('572761099837730efe8e120d')})
api = system_util.pillar_api()
project = find_project_or_404(self.project['url'], api=api)
navigation_links = project_navigation_links(project, api=api)
# This should result in an empty list
self.assertListEqual([], navigation_links)