示例#1
0
def _homepage_context() -> dict:
    """Returns homepage template context variables."""

    # Get latest blog posts
    api = system_util.pillar_api()

    # Get latest comments to any node
    latest_comments = Node.latest('comments', api=api)

    # Get a list of random featured assets
    random_featured = get_random_featured_nodes()

    # Parse results for replies
    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,
                'parent': 1,
                'properties.url': 1,
            }
        },
                         api=api)

    for idx, comment in enumerate(latest_comments._items):
        if comment.properties.is_reply:
            try:
                comment.attached_to = _find_parent(comment.parent.parent)
            except ResourceNotFound:
                # Remove this comment
                to_remove.append(idx)
        else:
            comment.attached_to = comment.parent

    for idx in reversed(to_remove):
        del latest_comments._items[idx]

    for comment in latest_comments._items:
        if not comment.attached_to:
            continue
        comment.attached_to.url = url_for_node(node=comment.attached_to)
        comment.url = url_for_node(node=comment)

    main_project = Project.find(current_app.config['MAIN_PROJECT_ID'], api=api)
    main_project.picture_header = get_file(main_project.picture_header,
                                           api=api)

    return dict(main_project=main_project,
                latest_comments=latest_comments._items,
                random_featured=random_featured)
示例#2
0
def index(community_url):
    api = system_util.pillar_api()

    project = Project.find_first({'where': {'url': community_url}}, api=api)

    if project is None:
        return abort(404)

    attach_project_pictures(project, api)

    # Fetch all activities for the main project
    activities = Activity.all({
        'where': {
            'project': project['_id'],
        },
        'sort': [('_created', -1)],
        'max_results': 15,
    }, api=api)

    # Fetch more info for each activity.
    for act in activities['_items']:
        act.actor_user = subquery.get_user_info(act.actor_user)
        try:
            act.link = url_for_node(node_id=act.object)
        except ValueError:
            # If the node was delete, we get ValueError exception.
            # By setting act.link to '', it does not get displayed in the list.
            act.link = ''

    return render_template(
        'dillo/index.html',
        col_right={'activities': activities},
        project=project,
        submit_menu=project_submit_menu(project))
示例#3
0
def jstree_parse_node(node, children=None):
    """Generate JStree node from node object"""
    from pillar.web.nodes.routes import url_for_node

    node_type = node.node_type
    # Define better the node type
    if node_type == 'asset':
        if not node.properties or not node.properties.content_type:
            log.warning(
                'Asset node %s has no node.properties.content_type: %s',
                node._id, node)
        else:
            node_type = node.properties.content_type

    parsed_node = dict(id="n_{0}".format(node._id),
                       a_attr={"href": url_for_node(node=node)},
                       li_attr={"data-node-type": node.node_type},
                       custom_view=node_type in CUSTOM_VIEW_NODE_TYPES,
                       text=Markup.escape(node.name),
                       type=node_type,
                       children=False)

    # Append children property only if it is a directory type
    if node_type in GROUP_NODES:
        parsed_node['children'] = True

    if node.permissions and node.permissions.world:
        parsed_node['li_attr']['is_free'] = True

    return parsed_node
示例#4
0
    def link_for_activity(self, act):
        """Returns the URL for the activity.

        :type act: pillarsdk.Activity
        """

        from .node_types.job import node_type_job
        from .node_types.manager import node_type_manager
        from .node_types.task import node_type_task

        if act.node_type == node_type_task['name']:
            return flask.url_for('flamenco.tasks.perproject.view_task',
                                 project_url=act.project.url,
                                 task_id=act.object)

        elif act.node_type == node_type_job['name']:
            return flask.url_for('flamenco.jobs.perproject.view_job',
                                 project_url=act.project.url,
                                 job_id=act.object)

        elif act.node_type == node_type_manager['name']:
            return flask.url_for('flamenco.managers.perproject.view_manager',
                                 project_url=act.project.url,
                                 manager_id=act.object)

        return url_for_node(node_id=act.object)
示例#5
0
def do_url_for_node(node_id=None, node=None):
    try:
        return url_for_node(node_id=node_id, node=node)
    except wz_exceptions.NotFound:
        log.info(
            '%s: do_url_for_node(node_id=%r, ...) called for non-existing node.',
            flask.request.url, node_id)
        return None
示例#6
0
    def render_page():
        feed = AtomFeed('Blender Cloud - Latest updates',
                        feed_url=ensure_schema(request.url),
                        url=ensure_schema(request.url_root))
        # Get latest blog posts
        api = system_util.pillar_api()
        latest_posts = Node.all(
            {
                'where': {
                    'node_type': 'post',
                    'properties.status': 'published'
                },
                'embedded': {
                    'user': 1
                },
                'sort': '-_created',
                'max_results': '15'
            },
            api=api)

        newest = None

        # Populate the feed
        for post in latest_posts._items:
            author = post.user.fullname or post.user.username
            updated = post._updated if post._updated else post._created
            url = ensure_schema(
                urllib.parse.urljoin(request.host_url,
                                     url_for_node(node=post)))
            content = post.properties.content[:500]
            content = '<p>{0}... <a href="{1}">Read more</a></p>'.format(
                content, url)

            if newest is None:
                newest = updated
            else:
                newest = max(newest, updated)

            feed.add(post.name,
                     str(content),
                     content_type='html',
                     author=author,
                     url=url,
                     updated=updated,
                     published=post._created)
        resp = feed.get_response()
        if newest is not None:
            resp.headers['Last-Modified'] = newest.strftime(
                current_app.config['RFC1123_DATE_FORMAT'])
        return resp
示例#7
0
def posts_create(project_id):
    api = system_util.pillar_api()
    try:
        project = Project.find(project_id, api=api)
    except ResourceNotFound:
        return abort(404)
    attach_project_pictures(project, api)

    blog = Node.find_one(
        {'where': {
            'node_type': 'blog',
            'project': project_id
        }}, api=api)
    node_type = project.get_node_type('post')
    # Check if user is allowed to create a post in the blog
    if not project.node_type_has_method('post', 'POST', api=api):
        return abort(403)
    form = get_node_form(node_type)
    if form.validate_on_submit():
        # Create new post object from scratch
        post_props = dict(node_type='post',
                          name=form.name.data,
                          picture=form.picture.data,
                          user=current_user.objectid,
                          parent=blog._id,
                          project=project._id,
                          properties=dict(content=form.content.data,
                                          status=form.status.data,
                                          url=form.url.data))
        if form.picture.data == '':
            post_props['picture'] = None
        post = Node(post_props)
        post.create(api=api)
        # Only if the node is set as published, push it to the list
        if post.properties.status == 'published':
            project_update_nodes_list(post,
                                      project_id=project._id,
                                      list_name='blog')
        return redirect(url_for_node(node=post))
    form.parent.data = blog._id
    return render_template('nodes/custom/post/create.html',
                           node_type=node_type,
                           form=form,
                           project=project,
                           api=api)
示例#8
0
    def test_random_feature_node_returns_6_nodes(self):
        from pillar.web.nodes.routes import url_for_node

        base_node = {
            'name': 'Just a node name',
            'project': self.pid,
            'description': '',
            'node_type': 'asset',
            'user': self.uid,
        }
        base_props = {
            'status': 'published',
            'file': self.file_id,
            'content_type': 'video',
            'order': 0
        }

        def create_asset(weeks):
            return self.create_node({
                **base_node,
                '_created':
                self.fake_now - timedelta(weeks=weeks),
                'properties':
                base_props,
            })

        all_asset_ids = [create_asset(i) for i in range(20)]

        with self.app.app_context():
            proj_col = self.app.db('projects')
            proj_col.update_one({'_id': self.pid},
                                {'$set': {
                                    'nodes_featured': all_asset_ids,
                                }})

        with self.app.test_request_context():
            random_assets = get_random_featured_nodes()

            self.assertIs(len(random_assets), 6)
            for asset in random_assets:
                aid = asset['_id']
                self.assertIn(ObjectId(asset['_id']), all_asset_ids)
                self.assertEqual(f'/p/default-project/{aid}',
                                 url_for_node(node=asset))
示例#9
0
def redirect_with_short_code(short_code):
    if any(c not in short_code_chars for c in short_code):
        # Can't be a short code
        return

    log.debug('Path %s may be a short-code', short_code)

    api = system_util.pillar_api()
    try:
        node = pillarsdk.Node.find_one({'where': {'short_code': short_code},
                                        'projection': {'_id': 1}},
                                       api=api)
    except pillarsdk.ResourceNotFound:
        log.debug("Nope, it isn't.")
        return

    # Redirect to 'theatre' view for the node.
    url = url_for_node(node=node)
    url = urllib.parse.urljoin(url, '?t')

    log.debug('Found short code %s, redirecting to %s', short_code, url)
    return redirect(url, code=307)
示例#10
0
    def render_page():
        feed = AtomFeed('Blender Cloud - Latest updates',
                        feed_url=request.url,
                        url=request.url_root)
        # Get latest blog posts
        api = system_util.pillar_api()
        latest_posts = Node.all(
            {
                'where': {
                    'node_type': 'post',
                    'properties.status': 'published'
                },
                'embedded': {
                    'user': 1
                },
                'sort': '-_created',
                'max_results': '15'
            },
            api=api)

        # Populate the feed
        for post in latest_posts._items:
            author = post.user.fullname
            updated = post._updated if post._updated else post._created
            url = url_for_node(node=post)
            content = post.properties.content[:500]
            content = '<p>{0}... <a href="{1}">Read more</a></p>'.format(
                content, url)
            feed.add(post.name,
                     str(content),
                     content_type='html',
                     author=author,
                     url=url,
                     updated=updated,
                     published=post._created)
        return feed.get_response()
示例#11
0
def posts_view(project_id=None,
               project_url=None,
               url=None,
               *,
               archive=False,
               page=1):
    """View individual blogpost"""

    if bool(project_id) == bool(project_url):
        raise ValueError('posts_view(): pass either project_id or project_url')

    if url and archive:
        raise ValueError('posts_view(): cannot pass both url and archive')

    api = system_util.pillar_api()

    # Fetch project (for background images and links generation)
    if project_id:
        project = Project.find(project_id, api=api)
    else:
        project = Project.find_one({'where': {'url': project_url}}, api=api)
        project_id = project['_id']

    attach_project_pictures(project, api)

    blog = Node.find_one(
        {
            'where': {
                'node_type': 'blog',
                'project': project_id
            },
        }, api=api)

    status_query = {} if blog.has_method('PUT') else {
        'properties.status': 'published'
    }
    posts = Node.all(
        {
            'where': {
                'parent': blog._id,
                **status_query
            },
            'embedded': {
                'user': 1
            },
            'sort': '-_created',
            'max_results': 20 if archive else 5,
            'page': page,
        },
        api=api)

    for post in posts._items:
        post.picture = get_file(post.picture, api=api)
        post.url = url_for_node(node=post)

    # Use the *_main_project.html template for the main blog
    is_main_project = project_id == current_app.config['MAIN_PROJECT_ID']
    main_project_template = '_main_project' if is_main_project else ''
    main_project_template = '_main_project'
    index_arch = 'archive' if archive else 'index'
    template_path = f'nodes/custom/blog/{index_arch}{main_project_template}.html',

    if url:
        template_path = f'nodes/custom/post/view{main_project_template}.html',

        post = Node.find_one(
            {
                'where': {
                    'parent': blog._id,
                    'properties.url': url
                },
                'embedded': {
                    'node_type': 1,
                    'user': 1
                },
            },
            api=api)

        if post.picture:
            post.picture = get_file(post.picture, api=api)

        post.url = url_for_node(node=post)
    elif posts._items:
        post = posts._items[0]
    else:
        post = None

    if post is not None:
        # If post is not published, check that the user is also the author of
        # the post. If not, return an error.
        if post.properties.status != "published":
            if not (current_user.is_authenticated and post.has_method('PUT')):
                abort(403)

    can_create_blog_posts = project.node_type_has_method('post',
                                                         'POST',
                                                         api=api)

    # Use functools.partial so we can later pass page=X.
    if is_main_project:
        url_func = functools.partial(url_for, 'main.main_blog_archive')
    else:
        url_func = functools.partial(url_for,
                                     'main.project_blog_archive',
                                     project_url=project.url)

    project.blog_archive_url = url_func()
    pmeta = posts._meta
    seen_now = pmeta['max_results'] * pmeta['page']
    if pmeta['total'] > seen_now:
        project.blog_archive_next = url_func(page=pmeta['page'] + 1)
    else:
        project.blog_archive_next = None
    if pmeta['page'] > 1:
        project.blog_archive_prev = url_func(page=pmeta['page'] - 1)
    else:
        project.blog_archive_prev = None

    title = 'blog_main' if is_main_project else 'blog'

    pages = Node.all(
        {
            'where': {
                'project': project._id,
                'node_type': 'page'
            },
            'projection': {
                'name': 1
            }
        },
        api=api)

    return render_template(
        template_path,
        blog=blog,
        node=post,
        posts=posts._items,
        posts_meta=pmeta,
        more_posts_available=pmeta['total'] > pmeta['max_results'],
        project=project,
        title=title,
        node_type_post=project.get_node_type('post'),
        can_create_blog_posts=can_create_blog_posts,
        pages=pages._items,
        api=api)
示例#12
0
文件: routes.py 项目: jonike/dillo
def users_view(username):
    """View public user page.

    Use direct db call to retrieve the user and then use the api to query the paginated list of all
    published dillo_posts from the user.

    """
    users_coll = current_app.db('users')
    user = users_coll.find_one({'username': username},
                               projection={
                                   'username': 1,
                                   'full_name': 1,
                                   'email': 1,
                                   'extension_props_public': 1,
                                   '_updated': 1,
                                   '_created': 1,
                               })
    if user is None:
        return abort(404)
    api = system_util.pillar_api()
    nodes_coll = current_app.db('nodes')

    pipeline = [{
        '$match': {
            'user': ObjectId(user['_id']),
            'node_type': 'dillo_post',
            'properties.status': 'published',
            '_deleted': False
        }
    }, {
        '$lookup': {
            'from': 'projects',
            'localField': 'project',
            'foreignField': '_id',
            'as': 'project'
        }
    }, {
        '$project': {
            'name': 1,
            'properties': 1,
            'user': 1,
            'picture': 1,
            '_created': 1,
            'project': {
                '$arrayElemAt': ['$project', 0]
            }
        }
    }, {
        '$sort': {
            '_created': -1
        }
    }]

    posts = list(nodes_coll.aggregate(pipeline=pipeline))

    for post in posts:
        if post.get('picture'):
            post['picture'] = get_file(post['picture'], api=api)

    main_project_url = current_app.config['DEFAULT_COMMUNITY']
    project = Project.find_by_url(main_project_url, api=api)
    attach_project_pictures(project, api)

    # Fetch all comments activity for the user
    activities = Activity.all(
        {
            'where': {
                'actor_user': str(user['_id']),
                'node_type': 'comment'
            },
            'sort': [('_created', -1)],
            'max_results': 15,
        },
        api=api)

    # Fetch more info for each activity.
    for act in activities['_items']:
        act.actor_user = subquery.get_user_info(act.actor_user)
        try:
            act.link = url_for_node(node_id=act.object)
        except ValueError:
            # TODO: properly handle the case when the activity object has been deleted
            continue

    return render_template('dillo/user.html',
                           col_right={'activities': activities},
                           user=user,
                           posts=posts,
                           project=project)