def index(): api = pillar_api() # FIXME Sybren: add permission check. # TODO: add projections. projects = current_flamenco.flamenco_projects() for project in projects['_items']: attach_project_pictures(project, api) projs_with_summaries = [ (proj, current_flamenco.job_manager.job_status_summary(proj['_id'])) for proj in projects['_items'] ] last_project = session.get('flamenco_last_project') if last_project: project = Project(last_project) navigation_links = project_navigation_links(project, pillar_api()) extension_sidebar_links = current_app.extension_sidebar_links(project) else: project = None navigation_links = [] extension_sidebar_links = [] return render_template('flamenco/index.html', projs_with_summaries=projs_with_summaries, project=project, navigation_links=navigation_links, extension_sidebar_links=extension_sidebar_links)
def edit(project_url): api = system_util.pillar_api() # Fetch the Node or 404 try: project = Project.find_one({'where': {'url': project_url}}, api=api) # project = Project.find(project_url, api=api) except ResourceNotFound: abort(404) utils.attach_project_pictures(project, api) form = ProjectForm( project_id=project._id, name=project.name, url=project.url, summary=project.summary, description=project.description, is_private='GET' not in project.permissions.world, category=project.category, status=project.status, ) if form.validate_on_submit(): project = Project.find(project._id, api=api) project.name = form.name.data project.url = form.url.data project.summary = form.summary.data project.description = form.description.data project.category = form.category.data project.status = form.status.data if form.picture_square.data: project.picture_square = form.picture_square.data if form.picture_header.data: project.picture_header = form.picture_header.data # Update world permissions from is_private checkbox if form.is_private.data: project.permissions.world = [] else: project.permissions.world = ['GET'] project.update(api=api) # Reattach the pictures utils.attach_project_pictures(project, api) else: if project.picture_square: form.picture_square.data = project.picture_square._id if project.picture_header: form.picture_header.data = project.picture_header._id # List of fields from the form that should be hidden to regular users if current_user.has_role('admin'): hidden_fields = [] else: hidden_fields = ['url', 'status', 'is_private', 'category'] return render_template('projects/edit.html', form=form, hidden_fields=hidden_fields, project=project, ext_pages=find_extension_pages(), api=api)
def index(): api = system_util.pillar_api() # Get all projects, except the home project. projects_user = Project.all({ 'where': {'user': current_user.objectid, 'category': {'$ne': 'home'}}, 'sort': '-_created' }, api=api) projects_shared = Project.all({ 'where': {'user': {'$ne': current_user.objectid}, 'permissions.groups.group': {'$in': current_user.groups}, 'is_private': True}, 'sort': '-_created', 'embedded': {'user': 1}, }, api=api) # Attach project images for project in projects_user['_items']: utils.attach_project_pictures(project, api) for project in projects_shared['_items']: utils.attach_project_pictures(project, api) return render_template( 'projects/index_dashboard.html', gravatar=utils.gravatar(current_user.email, size=128), projects_user=projects_user['_items'], projects_shared=projects_shared['_items'], api=api)
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))
def search(project_url): """Search into a project""" api = system_util.pillar_api() project = find_project_or_404(project_url, api=api) utils.attach_project_pictures(project, api) return render_template('nodes/search.html', project=project, og_picture=project.picture_header)
def edit_node_type(project_url, node_type_name): api = system_util.pillar_api() # Fetch the Node or 404 try: project = Project.find_one({'where': {'url': project_url}}, api=api) except ResourceNotFound: return abort(404) utils.attach_project_pictures(project, api) node_type = project.get_node_type(node_type_name) form = NodeTypeForm() if form.validate_on_submit(): # Update dynamic & form schemas dyn_schema = json.loads(form.dyn_schema.data) node_type.dyn_schema = dyn_schema form_schema = json.loads(form.form_schema.data) node_type.form_schema = form_schema node_type.description = form.description.data # Update permissions permissions = json.loads(form.permissions.data) node_type.permissions = permissions project.update(api=api) elif request.method == 'GET': form.project_id.data = project._id if node_type: form.name.data = node_type.name form.description.data = node_type.description form.parent.data = node_type.parent dyn_schema = node_type.dyn_schema.to_dict() form_schema = node_type.form_schema.to_dict() if 'permissions' in node_type: permissions = node_type.permissions.to_dict() else: permissions = {} form.form_schema.data = json.dumps(form_schema, indent=4) form.dyn_schema.data = json.dumps(dyn_schema, indent=4) form.permissions.data = json.dumps(permissions, indent=4) if request.method == 'POST': # Send back a JSON response, as this is actually called # from JS instead of rendered as page. if form.errors: resp = jsonify({'_message': str(form.errors)}) resp.status_code = 400 return resp return jsonify({'_message': 'ok'}) return render_template('projects/edit_node_type_embed.html', form=form, project=project, api=api, node_type=node_type)
def index_all(): """Landing page. Posts are loaded asynchronously.""" api = system_util.pillar_api() project = get_main_project() attach_project_pictures(project, api) return render_template( 'dillo/index.html', col_right={'activities': {'_meta': {'total': 0}}}, project=project)
def main_project(): """Fetch the current project, including images. Because this is a cached function, using a storage solution with expiring links is not supported. """ # TODO: switch to get_main_project() from Pillar project = pillarsdk.Project.find_by_url('default-project', api=api) attach_project_pictures(project, api) return project
def index(): api = pillar_api() # FIXME Sybren: add permission check. # TODO: add projections. projects = current_svnman.svnman_projects() for project in projects['_items']: attach_project_pictures(project, api) return render_template('svnman/index.html', projects=projects)
def index_all(): """Aggregated view of all posts for the public communities. If a user has a set of favourite communites in its settings, use those instead. """ api = system_util.pillar_api() project = get_main_project() attach_project_pictures(project, api) return render_template( 'dillo/index.html', col_right={'activities': {'_meta': {'total': 0}}}, project=project)
def edit_node_types(project_url): api = system_util.pillar_api() # Fetch the project or 404 try: project = Project.find_one({ 'where': '{"url" : "%s"}' % (project_url)}, api=api) except ResourceNotFound: return abort(404) utils.attach_project_pictures(project, api) return render_template('projects/edit_node_types.html', api=api, ext_pages=find_extension_pages(), project=project)
def index(): api = pillar_api() user = flask_login.current_user if user.is_authenticated: tasks = current_flamenco.task_manager.tasks_for_user(user.objectid) else: tasks = None # TODO: add projections. projects = current_flamenco.flamenco_projects() for project in projects['_items']: attach_project_pictures(project, api) projs_with_summaries = [ (proj, current_flamenco.job_manager.job_status_summary(proj['_id'])) for proj in projects['_items'] ] # Fetch all activities for all Flamenco projects. id_to_proj = {p['_id']: p for p in projects['_items']} activities = pillarsdk.Activity.all( { 'where': { 'project': { '$in': list(id_to_proj.keys()) }, }, 'sort': [('_created', -1)], 'max_results': 20, }, api=api) # Fetch more info for each activity. for act in activities['_items']: act.actor_user = pillar.web.subquery.get_user_info(act.actor_user) act.project = id_to_proj[act.project] try: act.link = current_flamenco.link_for_activity(act) except ValueError: act.link = None return render_template('flamenco/index.html', tasks=tasks, projs_with_summaries=projs_with_summaries, activities=activities)
def wrapper(project_url, *args, **kwargs): if isinstance(project_url, pillarsdk.Resource): # This is already a resource, so this call probably is from one # view to another. Assume the caller knows what he's doing and # just pass everything along. return wrapped(project_url, *args, **kwargs) api = system_util.pillar_api() project = pillarsdk.Project.find_by_url( project_url, {'projection': projections} if projections else None, api=api) utils.attach_project_pictures(project, api) return wrapped(project, *args, **kwargs)
def edit_node_type(project_url, node_type_name): api = system_util.pillar_api() # Fetch the Node or 404 try: project = Project.find_one({ 'where': '{"url" : "%s"}' % (project_url)}, api=api) except ResourceNotFound: return abort(404) utils.attach_project_pictures(project, api) node_type = project.get_node_type(node_type_name) form = NodeTypeForm() if form.validate_on_submit(): # Update dynamic & form schemas dyn_schema = json.loads(form.dyn_schema.data) node_type.dyn_schema = dyn_schema form_schema = json.loads(form.form_schema.data) node_type.form_schema = form_schema node_type.description = form.description.data # Update permissions permissions = json.loads(form.permissions.data) node_type.permissions = permissions project.update(api=api) elif request.method == 'GET': form.project_id.data = project._id if node_type: form.name.data = node_type.name form.description.data = node_type.description form.parent.data = node_type.parent dyn_schema = node_type.dyn_schema.to_dict() form_schema = node_type.form_schema.to_dict() if 'permissions' in node_type: permissions = node_type.permissions.to_dict() else: permissions = {} form.form_schema.data = json.dumps(form_schema, indent=4) form.dyn_schema.data = json.dumps(dyn_schema, indent=4) form.permissions.data = json.dumps(permissions, indent=4) return render_template('projects/edit_node_type_embed.html', form=form, project=project, api=api, node_type=node_type)
def index(): api = pillar_api() # FIXME Sybren: add permission check. # TODO: add projections. projects = current_flamenco.flamenco_projects() for project in projects['_items']: attach_project_pictures(project, api) projs_with_summaries = [ (proj, current_flamenco.job_manager.job_status_summary(proj['_id'])) for proj in projects['_items'] ] return render_template('flamenco/index.html', projs_with_summaries=projs_with_summaries)
def get_projects(category): """Utility to get projects based on category. Should be moved on the API and improved with more extensive filtering capabilities. """ api = system_util.pillar_api() projects = Project.all( { 'where': { 'category': category, 'is_private': False }, 'sort': '-_created', }, api=api) for project in projects._items: attach_project_pictures(project, api) return projects
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)
def view(community_url, post_shortcode, slug=None): api = system_util.pillar_api() project = Project.find_by_url(community_url, api=api) attach_project_pictures(project, api) post = Node.find_one({ 'where': { 'project': project['_id'], 'properties.shortcode': post_shortcode}, 'embedded': {'user': 1}}, api=api) if post.picture: post.picture = get_file(post.picture, api=api) return render_template( 'dillo/index.html', project=project, submit_menu=project_submit_menu(project), col_right={'post': post})
def sharing(project_url): api = system_util.pillar_api() # Fetch the project or 404 try: project = Project.find_one({'where': {'url': project_url}}, api=api) except ResourceNotFound: return abort(404) # Fetch users that are part of the admin group users = project.get_users(api=api) if request.method == 'POST': user_id = request.form['user_id'] action = request.form['action'] try: if action == 'add': user = project.add_user(user_id, api=api) elif action == 'remove': user = project.remove_user(user_id, api=api) else: raise wz_exceptions.BadRequest(f'invalid action {action}') except ResourceNotFound: log.info('/p/%s/edit/sharing: User %s not found', project_url, user_id) return jsonify({ '_status': 'ERROR', 'message': 'User %s not found' % user_id }), 404 user['avatar'] = pillar.api.users.avatar.url(user) return jsonify(user) utils.attach_project_pictures(project, api) return render_template('projects/sharing.html', api=api, project=project, ext_pages=find_extension_pages(), users=users['_items'])
def sharing(project_url): api = system_util.pillar_api() # Fetch the project or 404 try: project = Project.find_one({ 'where': '{"url" : "%s"}' % (project_url)}, api=api) except ResourceNotFound: return abort(404) # Fetch users that are part of the admin group users = project.get_users(api=api) for user in users['_items']: user['avatar'] = utils.gravatar(user['email']) if request.method == 'POST': user_id = request.form['user_id'] action = request.form['action'] try: if action == 'add': user = project.add_user(user_id, api=api) elif action == 'remove': user = project.remove_user(user_id, api=api) except ResourceNotFound: log.info('/p/%s/edit/sharing: User %s not found', project_url, user_id) return jsonify({'_status': 'ERROR', 'message': 'User %s not found' % user_id}), 404 # Add gravatar to user user['avatar'] = utils.gravatar(user['email']) return jsonify(user) utils.attach_project_pictures(project, api) return render_template('projects/sharing.html', api=api, project=project, ext_pages=find_extension_pages(), users=users['_items'])
def communities(): """Fetch all public communities.""" params = { 'where': { 'extension_props.dillo': { '$exists': 1 }, 'is_private': False, }, 'projection': { 'picture_square': 1, 'url': 1, 'name': 1, 'summary': 1, 'extension_props': 1, } } projects = pillarsdk.Project.all(params, api=api) for project in projects['_items']: attach_project_pictures(project, api) return projects['_items']
def edit(node_id): """Generic node editing form, displayed only if the user is allowed. """ def set_properties(dyn_schema, form_schema, node_properties, form, set_data, prefix=""): """Initialize custom properties for the form. We run this function once before validating the function with set_data=False, so that we can set any multiselect field that was originally specified empty and fill it with the current choices. """ log.debug('set_properties(..., prefix=%r, set_data=%r) called', prefix, set_data) for prop, schema_prop in dyn_schema.items(): prop_name = "{0}{1}".format(prefix, prop) if prop_name not in form: continue try: db_prop_value = node_properties[prop] except KeyError: log.debug('%s not found in form for node %s', prop_name, node_id) continue if schema_prop['type'] == 'datetime': db_prop_value = datetime.strptime( db_prop_value, current_app.config['RFC1123_DATE_FORMAT']) if isinstance(form[prop_name], SelectMultipleField): # If we are dealing with a multiselect field, check if # it's empty (usually because we can't query the whole # database to pick all the choices). If it's empty we # populate the choices with the actual data. if not form[prop_name].choices: form[prop_name].choices = [(d, d) for d in db_prop_value] # Choices should be a tuple with value and name if not set_data: continue # Assign data to the field if prop_name == 'attachments': # If attachments is an empty list, do not append data if not db_prop_value: continue attachments.attachment_form_group_set_data( db_prop_value, schema_prop, form[prop_name]) elif prop_name == 'files': subschema = schema_prop['schema']['schema'] # Extra entries are caused by min_entries=1 in the form # creation. field_list = form[prop_name] if len(db_prop_value): while len(field_list): field_list.pop_entry() for file_data in db_prop_value: file_form_class = build_file_select_form(subschema) subform = file_form_class() for key, value in file_data.items(): setattr(subform, key, value) field_list.append_entry(subform) # elif prop_name == 'tags': # form[prop_name].data = ', '.join(data) else: form[prop_name].data = db_prop_value api = system_util.pillar_api() node = Node.find(node_id, api=api) # We do not want to display the page to users who can't PUT if 'PUT' not in node.allowed_methods: raise wz_exceptions.Forbidden() project = Project.find(node.project, api=api) node_type = project.get_node_type(node.node_type) form = get_node_form(node_type) user_id = current_user.objectid dyn_schema = node_type['dyn_schema'].to_dict() form_schema = node_type['form_schema'].to_dict() error = "" node_properties = node.properties.to_dict() ensure_lists_exist_as_empty(node.to_dict(), node_type) set_properties(dyn_schema, form_schema, node_properties, form, set_data=False) if form.validate_on_submit(): if process_node_form(form, node_id=node_id, node_type=node_type, user=user_id): # Handle the specific case of a blog post if node_type.name == 'post': project_update_nodes_list(node, project_id=project._id, list_name='blog') else: try: project_update_nodes_list(node, project_id=project._id) except ForbiddenAccess: # TODO (fsiddi): Implement this as a blender-cloud-only hook log.debug( 'User %s not allowed to update latest_nodes in %s' % (user_id, project._id)) return redirect( url_for('nodes.view', node_id=node_id, embed=1, _external=True, _scheme=current_app.config['SCHEME'])) else: log.debug('Error sending data to Pillar, see Pillar logs.') error = 'Server error' else: if form.errors: log.debug('Form errors: %s', form.errors) # Populate Form form.name.data = node.name form.description.data = node.description if 'picture' in form: form.picture.data = node.picture if node.parent: form.parent.data = node.parent set_properties(dyn_schema, form_schema, node_properties, form, set_data=True) # Get previews node.picture = get_file(node.picture, api=api) if node.picture else None # Get Parent try: parent = Node.find(node['parent'], api=api) except KeyError: parent = None except ResourceNotFound: parent = None embed_string = '' # Check if we want to embed the content via an AJAX call if request.args.get('embed') == '1': # Define the prefix for the embedded template embed_string = '_embed' else: attach_project_pictures(project, api) template = 'nodes/custom/{0}/edit{1}.html'.format(node_type['name'], embed_string) # We should more simply check if the template file actually exists on the filesystem try: return render_template( template, node=node, parent=parent, form=form, errors=form.errors, error=error, api=api, project=project, ) except TemplateNotFound: template = 'nodes/edit{1}.html'.format(node_type['name'], embed_string) is_embedded_edit = True if embed_string else False return render_template( template, node=node, parent=parent, form=form, errors=form.errors, error=error, api=api, project=project, is_embedded_edit=is_embedded_edit, )
def view_node(project_url, node_id): """Entry point to view a node in the context of a project""" # Some browsers mangle URLs and URL-encode /p/{p-url}/#node-id if node_id.startswith('#'): return redirect(url_for('projects.view_node', project_url=project_url, node_id=node_id[1:]), code=301) # permanent redirect theatre_mode = 't' in request.args api = system_util.pillar_api() # First we check if it's a simple string, in which case we are looking for # a static page. Maybe we could use bson.objectid.ObjectId.is_valid(node_id) project: typing.Optional[Project] = None if not utils.is_valid_id(node_id): # raise wz_exceptions.NotFound('No such node') project, node = render_node_page(project_url, node_id, api) else: # Fetch the node before the project. If this user has access to the # node, we should be able to get the project URL too. try: node = Node.find(node_id, api=api) except ForbiddenAccess: return render_template('errors/403.html'), 403 except ResourceNotFound: raise wz_exceptions.NotFound('No such node') try: project = Project.find_one( {'where': { "url": project_url, '_id': node.project }}, api=api) except ResourceNotFound: if theatre_mode: pass # In theatre mode, we don't need access to the project at all. else: raise wz_exceptions.NotFound('No such project') navigation_links = [] extension_sidebar_links = '' og_picture = node.picture = utils.get_file(node.picture, api=api) if project: utils.attach_project_pictures(project, api) if not node.picture: og_picture = project.picture_16_9 navigation_links = project_navigation_links(project, api) extension_sidebar_links = current_app.extension_sidebar_links(project) # Append _theatre to load the proper template theatre = '_theatre' if theatre_mode else '' if node.node_type == 'page': return render_template( 'nodes/custom/page/view_embed.html', api=api, node=node, project=project, navigation_links=navigation_links, extension_sidebar_links=extension_sidebar_links, og_picture=og_picture, ) return render_template( 'projects/view{}.html'.format(theatre), api=api, project=project, node=node, show_node=True, show_project=False, og_picture=og_picture, navigation_links=navigation_links, extension_sidebar_links=extension_sidebar_links, )
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)
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)
def posts_view(project_id=None, project_url=None, url=None): """View individual blogpost""" if bool(project_id) == bool(project_url): raise ValueError('posts_view(): pass either project_id or project_url') api = system_util.pillar_api() # Fetch project (for backgroud 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": "%s" %s}' % (blog._id, status_query), 'embedded': '{"user": 1}', 'sort': '-_created' }, api=api) for post in posts._items: post.picture = get_file(post.picture, api=api) post['properties'][ 'content'] = pillar.web.nodes.attachments.render_attachments( post, post['properties']['content']) # Use the *_main_project.html template for the main blog main_project_template = '_main_project' if project_id == current_app.config[ 'MAIN_PROJECT_ID'] else '' if url: 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) # If post is not published, check that the user is also the author of # the post. If not, return 404. if post.properties.status != "published": if not (current_user.is_authenticated and post.has_method('PUT')): abort(403) post['properties'][ 'content'] = pillar.web.nodes.attachments.render_attachments( post, post['properties']['content']) return render_template( 'nodes/custom/post/view{0}.html'.format(main_project_template), blog=blog, node=post, posts=posts._items, project=project, title='blog', api=api) else: node_type_post = project.get_node_type('post') template_path = 'nodes/custom/blog/index.html' return render_template( 'nodes/custom/blog/index{0}.html'.format(main_project_template), node_type_post=node_type_post, posts=posts._items, project=project, title='blog', api=api)
def render_project(project, api, extra_context=None, template_name=None): utils.attach_project_pictures(project, api) def load_latest(list_of_ids, node_type=None): """Loads a list of IDs in reversed order.""" if not list_of_ids: return [] # Construct query parameters outside the loop. projection = { 'name': 1, 'user': 1, 'node_type': 1, 'project': 1, 'properties.url': 1, 'properties.content_type': 1, 'properties.duration_seconds': 1, 'picture': 1 } params = {'projection': projection, 'embedded': {'user': 1}} if node_type == 'post': projection['properties.content'] = 1 elif node_type == 'asset': projection['description'] = 1 list_latest = [] for node_id in reversed(list_of_ids or ()): try: node_item = Node.find(node_id, params, api=api) node_item.picture = utils.get_file(node_item.picture, api=api) list_latest.append(node_item) except ForbiddenAccess: pass except ResourceNotFound: log.warning('Project %s refers to removed node %s!', project._id, node_id) return list_latest project.nodes_featured = load_latest(project.nodes_featured, node_type='asset') project.nodes_blog = load_latest(project.nodes_blog, node_type='post') # Merge featured assets and blog posts into one activity stream def sort_key(item): return item._created activities = itertools.chain(project.nodes_featured, project.nodes_blog) activity_stream = sorted(activities, key=sort_key, reverse=True) if extra_context is None: extra_context = {} if project.category == 'home' and not current_app.config[ 'RENDER_HOME_AS_REGULAR_PROJECT']: template_name = template_name or 'projects/home_index.html' return render_template(template_name, project=project, api=system_util.pillar_api(), **extra_context) if template_name is None: if request.args.get('embed'): embed_string = '_embed' else: embed_string = '' template_name = "projects/view{0}.html".format(embed_string) navigation_links = project_navigation_links(project, api) extension_sidebar_links = current_app.extension_sidebar_links(project) return render_template(template_name, api=api, project=project, node=None, show_node=False, show_project=True, og_picture=project.picture_16_9, activity_stream=activity_stream, navigation_links=navigation_links, extension_sidebar_links=extension_sidebar_links, **extra_context)