Performance improvements for the homepage (activity, blog, random featured)

This commit is contained in:
2017-09-15 15:25:27 +02:00
parent a7889214cf
commit e103a712b3
2 changed files with 85 additions and 50 deletions

View File

@@ -1,17 +1,22 @@
import functools
import itertools import itertools
import json import json
import logging import logging
import typing
import pillar.api from flask_login import current_user, login_required
from pillar.web.users import forms from flask import Blueprint, render_template, redirect, session, url_for, abort, flash
from pillarsdk import Node, Project, User, exceptions as sdk_exceptions, Group from pillarsdk import Node, Project, User, exceptions as sdk_exceptions, Group
from pillarsdk.exceptions import ResourceNotFound from pillarsdk.exceptions import ResourceNotFound
from flask_login import current_user, login_required
from flask import Blueprint, current_app, render_template, redirect, session, url_for, abort, flash from pillar import current_app
import pillar.api
from pillar.web.users import forms
from pillar.web.utils import system_util, get_file, current_user_is_authenticated from pillar.web.utils import system_util, get_file, current_user_is_authenticated
from pillar.web.utils import attach_project_pictures from pillar.web.utils import attach_project_pictures
from pillar.web.settings import blueprint as blueprint_settings from pillar.web.settings import blueprint as blueprint_settings
from pillar.web.nodes.routes import url_for_node
blueprint = Blueprint('cloud', __name__) blueprint = Blueprint('cloud', __name__)
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -37,6 +42,7 @@ def homepage():
# Append picture Files to last_posts # Append picture Files to last_posts
for post in latest_posts._items: for post in latest_posts._items:
post.picture = get_file(post.picture, api=api) post.picture = get_file(post.picture, api=api)
post.url = url_for_node(node=post)
# Get latest assets added to any project # Get latest assets added to any project
latest_assets = Node.latest('assets', api=api) latest_assets = Node.latest('assets', api=api)
@@ -44,6 +50,7 @@ def homepage():
# Append picture Files to latest_assets # Append picture Files to latest_assets
for asset in latest_assets._items: for asset in latest_assets._items:
asset.picture = get_file(asset.picture, api=api) asset.picture = get_file(asset.picture, api=api)
asset.url = url_for_node(node=asset)
# Get latest comments to any node # Get latest comments to any node
latest_comments = Node.latest('comments', api=api) latest_comments = Node.latest('comments', api=api)
@@ -53,18 +60,27 @@ def homepage():
# Parse results for replies # Parse results for replies
to_remove = [] to_remove = []
@functools.lru_cache()
def _find_parent(parent_node_id) -> Node:
return Node.find(parent_node_id,
{'projection': {
'_id': 1,
'name': 1,
'node_type': 1,
'project': 1,
}},
api=api)
for idx, comment in enumerate(latest_comments._items): for idx, comment in enumerate(latest_comments._items):
if comment.properties.is_reply: if comment.properties.is_reply:
try: try:
comment.attached_to = Node.find(comment.parent.parent, comment.attached_to = _find_parent(comment.parent.parent)
{'projection': {
'_id': 1,
'name': 1,
}},
api=api)
except ResourceNotFound: except ResourceNotFound:
# Remove this comment # Remove this comment
to_remove.append(idx) to_remove.append(idx)
else:
comment.attached_to.url = url_for_node(node=comment.attached_to)
else: else:
comment.attached_to = comment.parent comment.attached_to = comment.parent
@@ -82,6 +98,9 @@ def homepage():
latest_comments._items) latest_comments._items)
activity_stream = sorted(activities, key=sort_key, reverse=True) activity_stream = sorted(activities, key=sort_key, reverse=True)
for node in activity_stream:
node.url = url_for_node(node=node)
return render_template( return render_template(
'homepage.html', 'homepage.html',
main_project=main_project, main_project=main_project,
@@ -192,33 +211,49 @@ def workshops():
return render_page() return render_page()
def get_random_featured_nodes(): def get_random_featured_nodes() -> typing.List[dict]:
"""Returns a list of project/node combinations for featured nodes.
import random A random subset of 3 featured nodes from all public projects is returned.
Assumes that the user actually has access to the public projects' nodes.
api = system_util.pillar_api() The dict is a node, with a 'project' key that contains a projected project.
projects = Project.all({ """
'projection': {'nodes_featured': 1},
'where': {'is_private': False},
'max_results': '15'
}, api=api)
featured_nodes = (p.nodes_featured for p in projects._items if p.nodes_featured) proj_coll = current_app.db('projects')
featured_nodes = [item for sublist in featured_nodes for item in sublist] featured_nodes = proj_coll.aggregate([
if len(featured_nodes) > 3: {'$match': {'is_private': False}},
featured_nodes = random.sample(featured_nodes, 3) {'$project': {'nodes_featured': True,
'url': True,
'name': True}},
{'$unwind': {'path': '$nodes_featured'}},
{'$sample': {'size': 3}},
{'$lookup': {'from': 'nodes',
'localField': 'nodes_featured',
'foreignField': '_id',
'as': 'node'}},
{'$unwind': {'path': '$node'}},
{'$project': {'url': True,
'name': True,
'node._id': True,
'node.name': True,
'node.permissions': True,
'node.picture': True,
'node.properties.content_type': True,
'node.properties.url': True}},
])
featured_node_documents = [] featured_node_documents = []
api = system_util.pillar_api()
for node_info in featured_nodes:
# Turn the project-with-node doc into a node-with-project doc.
node_document = node_info.pop('node')
node_document['project'] = node_info
for node in featured_nodes: node = Node(node_document)
node_document = Node.find(node, { node.picture = get_file(node.picture, api=api)
'projection': {'name': 1, 'project': 1, 'picture': 1, node.url = url_for_node(node=node)
'properties.content_type': 1, 'properties.url': 1}, featured_node_documents.append(node)
'embedded': {'project': 1}
}, api=api)
node_document.picture = get_file(node_document.picture, api=api)
featured_node_documents.append(node_document)
return featured_node_documents return featured_node_documents

View File

@@ -50,10 +50,10 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
| {% for n in activity_stream %} | {% for n in activity_stream %}
li.activity-stream__list-item( li.activity-stream__list-item(
class="{{ n.node_type }} {{ n.properties.content_type }} {% if n.picture %}with-picture{% endif %}", class="{{ n.node_type }} {{ n.properties.content_type }} {% if n.picture %}with-picture{% endif %}",
data-url="{{ url_for_node(node=n) }}") data-url="{{ n.url }}")
a.activity-stream__list-thumbnail( a.activity-stream__list-thumbnail(
class="{{ n.properties.content_type }}", class="{{ n.properties.content_type }}",
href="{{ url_for_node(node=n) }}") href="{{ n.url }}")
| {% if n.picture %} | {% if n.picture %}
img(src="{{ n.picture.thumbnail('m', api=api) }}") img(src="{{ n.picture.thumbnail('m', api=api) }}")
| {% endif %} | {% endif %}
@@ -75,7 +75,7 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
.activity-stream__list-details .activity-stream__list-details
a.title(href="{{ url_for_node(node=n) }}") a.title(href="{{ n.url }}")
| {% if n.node_type == 'comment' %} | {% if n.node_type == 'comment' %}
| {{ n.properties.content | striptags | truncate(200) }} | {{ n.properties.content | striptags | truncate(200) }}
| {% else %} | {% else %}
@@ -88,13 +88,13 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
ul.meta ul.meta
| {% if n.node_type == 'comment' or not n.picture %} | {% if n.node_type == 'comment' or not n.picture %}
li.when li.when
a(href="{{ url_for_node(node=n) }}", title="{{ n._created }}") {{ n._created | pretty_date_time }} a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }} li.who {{ n.user.full_name }}
| {% endif %} | {% endif %}
| {% if n.attached_to %} | {% if n.attached_to %}
li.where-parent li.where-parent
a(href="{{ url_for_node(node_id=n.attached_to._id) }}") {{ n.attached_to.name }} a(href="{{ n.attached_to.url }}") {{ n.attached_to.name }}
| {% endif %} | {% endif %}
li.where-project li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }} a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
@@ -108,7 +108,7 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
| {% if n.picture %} | {% if n.picture %}
ul.meta.extra ul.meta.extra
li.when li.when
a(href="{{ url_for_node(node=n) }}", title="{{ n._created }}") {{ n._created | pretty_date_time }} a(href="{{ n.url }}", title="{{ n._created }}") {{ n._created | pretty_date_time }}
li.who {{ n.user.full_name }} li.who {{ n.user.full_name }}
| {% endif %} | {% endif %}
| {% endfor %} | {% endfor %}
@@ -159,31 +159,31 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
| {% if n.picture and loop.first %} | {% if n.picture and loop.first %}
li.blog-stream__list-item.featured li.blog-stream__list-item.featured
a.blog-stream__thumbnail( a.blog-stream__thumbnail(
href="{{ url_for_node(node=n) }}") href="{{ n.url }}")
img(src="{{ n.picture.thumbnail('l', api=api) }}") img(src="{{ n.picture.thumbnail('l', api=api) }}")
a.title(href="{{ url_for_node(node=n) }}") a.title(href="{{ n.url }}")
| {{ n.name }} | {{ n.name }}
ul.meta ul.meta
li.when li.when
a(href="{{ url_for_node(node=n) }}", a(href="{{ n.url }}",
title="Updated {{ n._updated | pretty_date }}") title="Updated {{ n._updated | pretty_date }}")
| {{ n._created | pretty_date }} | {{ n._created | pretty_date }}
li.where-project li.where-project
a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }} a.project(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}
| {% else %} | {% else %}
li.blog-stream__list-item li.blog-stream__list-item
a.blog-stream__list-thumbnail(href="{{ url_for_node(node=n) }}") a.blog-stream__list-thumbnail(href="{{ n.url }}")
| {% if n.picture %} | {% if n.picture %}
img.image(src="{{ n.picture.thumbnail('s', api=api) }}") img.image(src="{{ n.picture.thumbnail('s', api=api) }}")
| {% else %} | {% else %}
i.pi-newspaper i.pi-newspaper
| {% endif %} | {% endif %}
.blog-stream__list-details .blog-stream__list-details
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }} a.title(href="{{ n.url }}") {{ n.name }}
ul.meta ul.meta
li.when li.when
a(href="{{ url_for_node(node=n) }}", a(href="{{ n.url }}",
title="Updated {{ n._updated | pretty_date }}") title="Updated {{ n._updated | pretty_date }}")
| {{ n._created | pretty_date }} | {{ n._created | pretty_date }}
li.where-project li.where-project
@@ -214,7 +214,7 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
span free span free
| {% endif %} | {% endif %}
a.random-asset__thumbnail( a.random-asset__thumbnail(
href="{{ url_for_node(node=n) }}", href="{{ n.url }}",
class="{{ n.properties.content_type }}") class="{{ n.properties.content_type }}")
| {% if n.picture %} | {% if n.picture %}
img(src="{{ n.picture.thumbnail('l', api=api) }}") img(src="{{ n.picture.thumbnail('l', api=api) }}")
@@ -225,11 +225,11 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
| {% endif %} | {% endif %}
a.title(href="{{ url_for_node(node=n) }}") a.title(href="{{ n.url }}")
| {{ n.name }} | {{ n.name }}
ul.meta ul.meta
li.what li.what
a(href="{{ url_for_node(node=n) }}") a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %} | {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where li.where
a(href="{{ url_for('projects.view', project_url=n.project.url) }}") a(href="{{ url_for('projects.view', project_url=n.project.url) }}")
@@ -242,7 +242,7 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
span free span free
| {% endif %} | {% endif %}
a.random-asset__list-thumbnail( a.random-asset__list-thumbnail(
href="{{ url_for_node(node=n) }}", href="{{ n.url }}",
class="{{ n.properties.content_type }}") class="{{ n.properties.content_type }}")
| {% if n.picture %} | {% if n.picture %}
img.image(src="{{ n.picture.thumbnail('s', api=api) }}") img.image(src="{{ n.picture.thumbnail('s', api=api) }}")
@@ -258,10 +258,10 @@ meta(name="twitter:image", content="{% if main_project.picture_header %}{{ main_
| {% endif %} | {% endif %}
| {% endif %} | {% endif %}
.random-asset__list-details .random-asset__list-details
a.title(href="{{ url_for_node(node=n) }}") {{ n.name }} a.title(href="{{ n.url }}") {{ n.name }}
ul.meta ul.meta
li.what li.what
a(href="{{ url_for_node(node=n) }}") a(href="{{ n.url }}")
| {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %} | {% if n.properties.content_type %}{{ n.properties.content_type }}{% else %}Folder{% endif %}
li.where li.where
a(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }} a(href="{{ url_for('projects.view', project_url=n.project.url) }}") {{ n.project.name }}