def index(): api = system_util.pillar_api() projects_user = Project.all({ 'where': {'user': current_user.objectid}, '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']: attach_project_pictures(project, api) for project in projects_shared['_items']: attach_project_pictures(project, api) return render_template( 'projects/index_dashboard.html', gravatar=gravatar(current_user.email, size=128), title='dashboard', projects_user=projects_user['_items'], projects_shared=projects_shared['_items'], api=system_util.pillar_api())
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) 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=u'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 = [u'GET'] project.update(api=api) # Reattach the pictures 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, title="edit", api=api)
def is_flamenco_project(self, project: pillarsdk.Project): """Returns whether the project is set up for Flamenco. Requires Flamenco extension properties. """ if not project.extension_props: return False try: pprops = project.extension_props[EXTENSION_NAME] except AttributeError: self._log.warning("is_flamenco_project: Project url=%r doesn't have" " any extension properties.", project['url']) if self._log.isEnabledFor(logging.DEBUG): import pprint self._log.debug('Project: %s', pprint.pformat(project.to_dict())) return False except KeyError: return False if pprops is None: self._log.warning("is_flamenco_project: Project url=%r doesn't have" " Flamenco extension properties.", project['url']) return False return True
def create(): """Create a new project. This is a multi step operation that involves: - initialize basic node types - initialize basic permissions - create and connect storage space """ api = system_util.pillar_api() project_properties = dict(name='My project', user=current_user.objectid, category='assets', status='pending') project = Project(project_properties) project.create(api=api) return redirect( url_for('projects.edit', project_url="p-{}".format(project['_id'])))
def linked_projects(self, *, page=1, max_results=250, api) -> Resource: """Returns the projects linked to this Manager.""" if not self.projects: return Resource({ '_items': [], '_meta': { 'total': 0, 'page': 1, 'max_results': 250, } }) fetched = Project.all( { 'where': { '_id': {'$in': self.projects} }, 'projection': { '_id': 1, 'name': 1, 'url': 1, }, 'page': page, 'max_results': max_results, }, api=api) return fetched
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 comments_index(): parent_id = request.args.get('parent_id') # Get data only if we format it api = system_util.pillar_api() if request.args.get('format'): nodes = Node.all({ 'where': '{"node_type" : "comment", "parent": "%s"}' % (parent_id), 'embedded': '{"user":1}'}, api=api) comments = [] for comment in nodes._items: # Query for first level children (comment replies) replies = Node.all({ 'where': '{"node_type" : "comment", "parent": "%s"}' % (comment._id), 'embedded': '{"user":1}'}, api=api) replies = replies._items if replies._items else None if replies: replies = [format_comment(reply, is_reply=True) for reply in replies] comments.append( format_comment(comment, is_reply=False, replies=replies)) if request.args.get('format') == 'json': return_content = jsonify(items=[c for c in comments if c is not None]) else: parent_node = Node.find(parent_id, api=api) project = Project.find(parent_node.project, api=api) has_method_POST = project.node_type_has_method('comment', 'POST', api=api) # Data will be requested via javascript return_content = render_template('nodes/custom/_comments.html', parent_id=parent_id, has_method_POST=has_method_POST) return return_content
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'] = gravatar(user['email']) if request.method == 'POST': user_id = request.form['user_id'] action = request.form['action'] if action == 'add': user = project.add_user(user_id, api=api) elif action == 'remove': user = project.remove_user(user_id, api=api) # Add gravatar to user user['avatar'] = gravatar(user['email']) return jsonify(user) attach_project_pictures(project, api) return render_template('projects/sharing.html', api=api, title="sharing", project=project, users=users['_items'])
def delete(): """Unapologetically deletes a project""" api = system_util.pillar_api() project_id = request.form['project_id'] project = Project.find(project_id, api=api) project.delete(api=api) return jsonify(dict(staus='success', data=dict( message='Project deleted {}'.format(project['_id']))))
def _home_project(api): try: project = Project.find_from_endpoint('/bcloud/home-project', api=api) except ResourceNotFound: log.warning('Home project for user %s not found', current_user.objectid) raise wz_exceptions.NotFound('No such project') return project
def project_blog(project_url, url=None): """View project blog""" api = system_util.pillar_api() try: project = Project.find_one({ 'where': '{"url" : "%s"}' % (project_url)}, api=api) return posts_view(project._id, url=url) except ResourceNotFound: return abort(404)
def get_main_project(): api = system_util.pillar_api() try: main_project = Project.find(app.config['MAIN_PROJECT_ID'], api=api) except ResourceNotFound: raise ConfigError('MAIN_PROJECT_ID was not found. Check config.py.') except KeyError: raise ConfigError('MAIN_PROJECT_ID missing from config.py') return main_project
def create(): """Create a new project. This is a multi step operation that involves: - initialize basic node types - initialize basic permissions - create and connect storage space """ api = system_util.pillar_api() project_properties = dict( name='My project', user=current_user.objectid, category='assets', status='pending' ) project = Project(project_properties) project.create(api=api) return redirect(url_for('projects.edit', project_url="p-{}".format(project['_id'])))
def project_blog(project_url, url=None): """View project blog""" api = system_util.pillar_api() try: project = Project.find_one({'where': '{"url" : "%s"}' % (project_url)}, api=api) return posts_view(project._id, url=url) except ResourceNotFound: return abort(404)
def commentform_for_node(node_id): """Shows only the comment for for comments attached to the given node. i.e. does not show the comments themselves, just the form to post a new comment. """ api = system_util.pillar_api() node = Node.find(node_id, api=api) project = Project({'_id': node.project}) can_post_comments = project.node_type_has_method('comment', 'POST', api=api) return render_template('nodes/custom/comment/list_embed.html', node_id=node_id, show_comments=False, can_post_comments=can_post_comments)
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(): 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) show_deleted_projects = request.args.get('deleted') is not None if show_deleted_projects: timeframe = utcnow() - datetime.timedelta(days=31) projects_deleted = Project.all({ 'where': {'user': current_user.objectid, 'category': {'$ne': 'home'}, '_deleted': True, '_updated': {'$gt': timeframe}}, 'sort': '-_created' }, api=api) else: projects_deleted = {'_items': []} 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_list in (projects_user, projects_deleted, projects_shared): utils.mass_attach_project_pictures(project_list['_items'], api=api, header=False) return render_template( 'projects/index_dashboard.html', gravatar=utils.gravatar(current_user.email, size=128), projects_user=projects_user['_items'], projects_deleted=projects_deleted['_items'], projects_shared=projects_shared['_items'], show_deleted_projects=show_deleted_projects, api=api)
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)
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) 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: # In theatre mode, we don't need access to the project at all. if theatre_mode: project = None else: raise wz_exceptions.NotFound('No such project') og_picture = node.picture = utils.get_file(node.picture, api=api) if project: if not node.picture: og_picture = utils.get_file(project.picture_header, api=api) project.picture_square = utils.get_file(project.picture_square, api=api) # Append _theatre to load the proper template theatre = '_theatre' if theatre_mode else '' extension_sidebar_links = current_app.extension_sidebar_links(project) return render_template('projects/view{}.html'.format(theatre), api=api, project=project, node=node, show_node=True, show_project=False, og_picture=og_picture, extension_sidebar_links=extension_sidebar_links)
def index(): api = system_util.pillar_api() projects_user = Project.all( { 'where': { 'user': current_user.objectid }, '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']: attach_project_pictures(project, api) for project in projects_shared['_items']: attach_project_pictures(project, api) return render_template('projects/index_dashboard.html', gravatar=gravatar(current_user.email, size=128), title='dashboard', projects_user=projects_user['_items'], projects_shared=projects_shared['_items'], api=system_util.pillar_api())
def homepage(): """Homepage""" if not current_user.is_authenticated(): return render_template( 'join.html', title="join") # Get latest blog posts api = system_util.pillar_api() latest_posts = Node.all({ 'projection': {'name': 1, 'project': 1, 'user': 1, 'node_type': 1, 'picture': 1, 'properties.status': 1, 'properties.url': 1}, 'where': {'node_type': 'post', 'properties.status': 'published'}, 'embedded': {'user': 1, 'project': 1}, 'sort': '-_created', 'max_results': '3' }, api=api) # Append picture Files to last_posts for post in latest_posts._items: if post.picture: post.picture = get_file(post.picture, api=api) # Get latest assets added to any project latest_assets = Node.latest('assets', api=api) # Append picture Files to latest_assets for asset in latest_assets._items: if asset.picture: asset.picture = get_file(asset.picture, api=api) # Get latest comments to any node latest_comments = Node.latest('comments', api=api) # Parse results for replies for comment in latest_comments._items: if comment.properties.is_reply: comment.parent = Node.find(comment.parent.parent, api=api) else: comment.parent = comment.parent main_project = Project.find(app.config['MAIN_PROJECT_ID'], api=api) main_project.picture_square = get_file(main_project.picture_square, api=api) main_project.picture_header = get_file(main_project.picture_header, api=api) return render_template( 'homepage.html', main_project=main_project, latest_posts=latest_posts._items, latest_assets=latest_assets._items, latest_comments=latest_comments._items, api=api)
def project_or_error(): """Returns the project, raising a ValueError if it can't be found.""" if project is not None: return project try: return Project.find(project_id, {'projection': {'url': 1}}, api=api) except ResourceNotFound: log.warning('url_for_node(node_id=%r): Unable to find project %r', node_id, project_id) raise ValueError('Unable to find node project %r' % project_id)
def create_repo(self, project: pillarsdk.Project, creator: str) -> str: """Creates a SVN repository with a random ID attached to the project. Saves the repository ID in the project. Is a no-op if the project already has a Subversion repository. """ from . import remote, exceptions eprops, proj = self._get_prop_props(project) project_id = project['_id'] repo_id = eprops.get('repo_id') if repo_id: self._log.warning('project %s already has a Subversion repository %r', project_id, repo_id) return repo_id repo_info = remote.CreateRepo( repo_id='', project_id=str(project_id), creator=creator, ) for _ in range(100): repo_info.repo_id = _random_id() self._log.info('creating new repository, trying out %s', repo_info) try: actual_repo_id = self.remote.create_repo(repo_info) except exceptions.RepoAlreadyExists: self._log.info('repo_id=%r already exists, trying random other one', repo_info.repo_id) else: break else: self._log.error('unable to find unique random repository ID, giving up') raise ValueError('unable to find unique random repository ID, giving up') self._log.info('created new Subversion repository: %s', repo_info) # Update the project to include the repository ID. eprops['repo_id'] = actual_repo_id web_utils.unattach_project_pictures(proj) proj_utils.put_project(proj) # Make sure that the project object is updated as well. if project.extension_props is None: project.extension_props = {EXTENSION_NAME: pillarsdk.Resource()} project.extension_props[EXTENSION_NAME].repo_id = actual_repo_id return actual_repo_id
def find_project_or_404(project_url, embedded=None, api=None): """Aborts with a NotFound exception when the project cannot be found.""" params = {'where': {"url": project_url}} if embedded: params['embedded'] = embedded try: project = Project.find_one(params, api=api) except ResourceNotFound: raise wz_exceptions.NotFound('No such project') return project
def jstree(project_url): """Entry point to view a project as JSTree""" api = system_util.pillar_api() try: project = Project.find_one({ 'projection': {'_id': 1}, 'where': {'url': project_url} }, api=api) except ResourceNotFound: raise wz_exceptions.NotFound('No such project') return jsonify(items=jstree_get_children(None, project._id))
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 project_or_error(): """Returns the project, raising a ValueError if it can't be found.""" if project is not None: return project try: return Project.find(project_id, {'projection': { 'url': 1 }}, api=api) except ResourceNotFound: log.warning('url_for_node(node_id=%r): Unable to find project %r', node_id, project_id) raise ValueError('Unable to find node project %r' % project_id)
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) attach_project_pictures(project, api) return render_template('projects/edit_node_types.html', api=api, title="edit_node_types", 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 comments_index(): parent_id = request.args.get('parent_id') # Get data only if we format it api = system_util.pillar_api() if request.args.get('format'): nodes = Node.all( { 'where': '{"node_type" : "comment", "parent": "%s"}' % (parent_id), 'embedded': '{"user":1}' }, api=api) comments = [] for comment in nodes._items: # Query for first level children (comment replies) replies = Node.all( { 'where': '{"node_type" : "comment", "parent": "%s"}' % (comment._id), 'embedded': '{"user":1}' }, api=api) replies = replies._items if replies._items else None if replies: replies = [ format_comment(reply, is_reply=True) for reply in replies ] comments.append( format_comment(comment, is_reply=False, replies=replies)) if request.args.get('format') == 'json': return_content = jsonify( items=[c for c in comments if c is not None]) else: parent_node = Node.find(parent_id, api=api) project = Project.find(parent_node.project, api=api) has_method_POST = project.node_type_has_method('comment', 'POST', api=api) # Data will be requested via javascript return_content = render_template('nodes/custom/_comments.html', parent_id=parent_id, has_method_POST=has_method_POST) return return_content
def setup_for_flamenco(project: pillarsdk.Project): from pillar.api.utils import str2id import flamenco.setup project_id = project._id if not project.has_method('PUT'): log.warning( 'User %s tries to set up project %s for Flamenco, but has no PUT rights.', current_user, project_id) raise wz_exceptions.Forbidden() if not current_flamenco.auth.current_user_is_flamenco_user(): log.warning( 'User %s tries to set up project %s for Flamenco, but is not flamenco-user.', current_user, project_id) raise wz_exceptions.Forbidden() log.info('User %s sets up project %s for Flamenco', current_user, project_id) flamenco.setup.setup_for_flamenco(project.url) # Find the Managers available to this user, so we can auto-assign if there is exactly one. man_man = current_flamenco.manager_manager managers = man_man.owned_managers( [bson.ObjectId(gid) for gid in current_user.groups]) manager_count = managers.count() project_oid = str2id(project_id) user_id = current_user_id() if manager_count == 0: _, mngr_doc, _ = man_man.create_new_manager('My Manager', '', user_id) assign_man_oid = mngr_doc['_id'] log.info( 'Created and auto-assigning Manager %s to project %s upon setup for Flamenco.', assign_man_oid, project_oid) man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign') elif manager_count == 1: assign_manager = managers.next() assign_man_oid = str2id(assign_manager['_id']) log.info( 'Auto-assigning Manager %s to project %s upon setup for Flamenco.', assign_man_oid, project_oid) man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign') return '', 204
def home_jstree(): """Entry point to view the home project as JSTree""" api = system_util.pillar_api() try: project = Project.find_from_endpoint('/bcloud/home-project', params={'projection': { '_id': 1, 'permissions': 1, 'category': 1, 'user': 1}}, api=api) except ResourceNotFound: raise wz_exceptions.NotFound('No such project') return jsonify(items=jstree_get_children(None, project._id))
def setup_for_film(project: pillarsdk.Project): import cloud.setup project_id = project._id if not project.has_method('PUT'): log.warning( 'User %s tries to set up project %s for Blender Cloud, but has no PUT rights.', current_user, project_id) raise wz_exceptions.Forbidden() log.info('User %s sets up project %s for Blender Cloud', current_user, project_id) cloud.setup.setup_for_film(project.url) return '', 204
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 populate_feed(feed: AtomFeed, latest_posts): """Populate the feed with the provided data.""" for post in latest_posts._items: api = system_util.pillar_api() author = post.user.full_name updated = post._updated if post._updated else post._created project_projection = {'project': {'url': 1}} project = Project.find(post.project, project_projection, api=api) url = url_for('posts.view', post_shortcode=post.properties.shortcode, community_url=project.url) content = post.properties.content[:500] feed.add(post.name, str(content), content_type='html', author=author, url=url, updated=updated, published=post._created)
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 posts_edit(post_id): api = system_util.pillar_api() try: post = Node.find(post_id, {'embedded': '{"user": 1}'}, api=api) except ResourceNotFound: return abort(404) # Check if user is allowed to edit the post if not post.has_method('PUT'): return abort(403) project = Project.find(post.project, api=api) attach_project_pictures(project, api) node_type = project.get_node_type(post.node_type) form = get_node_form(node_type) if form.validate_on_submit(): if process_node_form(form, node_id=post_id, node_type=node_type, user=current_user.objectid): # The the post is published, add it to the list if form.status.data == 'published': project_update_nodes_list(post, project_id=project._id, list_name='blog') return redirect(url_for_node(node=post)) form.parent.data = post.parent form.name.data = post.name form.content.data = post.properties.content form.status.data = post.properties.status form.url.data = post.properties.url if post.picture: form.picture.data = post.picture # Embed picture file post.picture = get_file(post.picture, api=api) if post.properties.picture_square: form.picture_square.data = post.properties.picture_square return render_template('nodes/custom/post/edit.html', node_type=node_type, post=post, 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 create(): """Create a node. Requires a number of params: - project id - node_type - parent node (optional) """ if request.method != 'POST': return abort(403) project_id = request.form['project_id'] parent_id = request.form.get('parent_id') node_type_name = request.form['node_type_name'] api = system_util.pillar_api() # Fetch the Project or 404 try: project = Project.find(project_id, api=api) except ResourceNotFound: return abort(404) node_type = project.get_node_type(node_type_name) node_type_name = 'folder' if node_type['name'] == 'group' else \ node_type['name'] node_props = dict( name='New {}'.format(node_type_name), project=project['_id'], user=current_user.objectid, node_type=node_type['name'], properties={} ) if parent_id: node_props['parent'] = parent_id ensure_lists_exist_as_empty(node_props, node_type) node = Node(node_props) node.create(api=api) return jsonify(status='success', data=dict(asset_id=node['_id']))
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) 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 # Update permissions permissions = json.loads(form.permissions.data) node_type.permissions = permissions project.update(api=api) else: form.project_id.data = project._id form.name.data = node_type.name form.description.data = node_type.description form.parent.data = node_type.parent form.dyn_schema.data = json.dumps( node_type.dyn_schema.to_dict(), indent=4) form.form_schema.data = json.dumps( node_type.form_schema.to_dict(), indent=4) if 'permissions' in node_type: permissions = node_type.permissions.to_dict() else: permissions = {} form.permissions.data = json.dumps(permissions, indent=4) return render_template('projects/edit_node_type.html', form=form, project=project, api=api, node_type=node_type)
def setup_for_flamenco(project: pillarsdk.Project): from pillar.api.utils import str2id import flamenco.setup project_id = project._id if not project.has_method('PUT'): log.warning('User %s tries to set up project %s for Flamenco, but has no PUT rights.', current_user, project_id) raise wz_exceptions.Forbidden() if not current_flamenco.auth.current_user_is_flamenco_user(): log.warning('User %s tries to set up project %s for Flamenco, but is not flamenco-user.', current_user, project_id) raise wz_exceptions.Forbidden() log.info('User %s sets up project %s for Flamenco', current_user, project_id) flamenco.setup.setup_for_flamenco(project.url) # Find the Managers available to this user, so we can auto-assign if there is exactly one. man_man = current_flamenco.manager_manager managers = man_man.owned_managers([bson.ObjectId(gid) for gid in current_user.groups]) manager_count = managers.count() project_oid = str2id(project_id) user_id = current_user_id() if manager_count == 0: _, mngr_doc, _ = man_man.create_new_manager('My Manager', '', user_id) assign_man_oid = mngr_doc['_id'] log.info('Created and auto-assigning Manager %s to project %s upon setup for Flamenco.', assign_man_oid, project_oid) man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign') elif manager_count == 1: assign_manager = managers.next() assign_man_oid = str2id(assign_manager['_id']) log.info('Auto-assigning Manager %s to project %s upon setup for Flamenco.', assign_man_oid, project_oid) man_man.api_assign_to_project(assign_man_oid, project_oid, 'assign') return '', 204
def redir_job_id(job_id): """Redirects to the job view. This saves the client from performing another request to find the project URL; we do it for them. """ from flask import redirect, url_for from .sdk import Job from pillarsdk import Project # FIXME Sybren: add permission check. api = pillar_api() j = Job.find(job_id, {'projection': {'project': 1, 'status': 1}}, api=api) p = Project.find(j.project, {'projection': {'url': 1}}, api=api) target_blueprint = blueprint_for_archived[j.status == 'archived'] return redirect(url_for(f'{target_blueprint.name}.view_job', project_url=p.url, job_id=j._id))
def render_page(): # Get latest posts api = system_util.pillar_api() project = Project.find_first({'where': {'url': community_url}}, api=api) if not project: abort(404) feed = AtomFeed(project.name + ' - ' + _('Latest updates'), feed_url=request.url, url=request.url_root) latest_posts = Node.all({ 'where': {'node_type': 'dillo_post', 'properties.status': 'published', 'project': project['_id']}, 'embedded': {'user': 1}, 'sort': '-_created', 'max_results': '15' }, api=api) populate_feed(feed, latest_posts) return feed.get_response()
def redirect_to_task(task_id): """Allows creation of task links without knowing the job or project ID.""" from flamenco.tasks.sdk import Task from pillarsdk import Project from flask import url_for, redirect api = pillar_api() task = Task.find(task_id, {'projection': {'project': 1}}, api=api) project = Project.find(task['project'], {'projection': { 'url': 1 }}, api=api) # FIXME Sybren: add permission check. url = url_for('flamenco.jobs.perproject.for_project_with_task', project_url=project['url'], task_id=task_id) return redirect(url, code=301)
def project_update_nodes_list(node, project_id=None, list_name='latest'): """Update the project node with the latest edited or favorited node. The list value can be 'latest' or 'featured' and it will determined where the node reference will be placed in. """ if node.properties.status and node.properties.status == 'published': if not project_id and 'current_project_id' in session: project_id = session['current_project_id'] elif not project_id: return None project_id = node.project if type(project_id) is not unicode: project_id = node.project._id api = system_util.pillar_api() project = Project.find(project_id, api=api) if list_name == 'latest': nodes_list = project.nodes_latest elif list_name == 'blog': nodes_list = project.nodes_blog else: nodes_list = project.nodes_featured if not nodes_list: node_list_name = 'nodes_' + list_name project[node_list_name] = [] nodes_list = project[node_list_name] elif len(nodes_list) > 5: nodes_list.pop(0) if node._id in nodes_list: # Pop to put this back on top of the list nodes_list.remove(node._id) if list_name == 'featured': # We treat the action as a toggle and do not att the item back project.update(api=api) return "removed" nodes_list.append(node._id) project.update(api=api) return "added"
def edit(node_id): """Generic node editing form """ def set_properties(dyn_schema, form_schema, node_properties, form, prefix="", set_data=True): """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. """ for prop in dyn_schema: schema_prop = dyn_schema[prop] form_prop = form_schema[prop] prop_name = "{0}{1}".format(prefix, prop) if schema_prop['type'] == 'dict': set_properties( schema_prop['schema'], form_prop['schema'], node_properties[prop_name], form, "{0}__".format(prop_name)) continue 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, 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 # Assign data to the field if set_data: if prop_name == 'attachments': for attachment_collection in db_prop_value: for a in attachment_collection['files']: attachment_form = ProceduralFileSelectForm() attachment_form.file = a['file'] attachment_form.slug = a['slug'] attachment_form.size = 'm' form[prop_name].append_entry(attachment_form) elif prop_name == 'files': schema = 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) > 0: while len(field_list): field_list.pop_entry() for file_data in db_prop_value: file_form_class = build_file_select_form(schema) subform = file_form_class() for key, value in file_data.iteritems(): 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 else: # Default population of multiple file form list (only if # we are getting the form) if request.method == 'POST': continue if prop_name == 'attachments': if not db_prop_value: attachment_form = ProceduralFileSelectForm() attachment_form.file = 'file' attachment_form.slug = '' attachment_form.size = '' form[prop_name].append_entry(attachment_form) api = system_util.pillar_api() node = Node.find(node_id, api=api) 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, list_name='blog') else: project_update_nodes_list(node) # Emergency hardcore cache flush # cache.clear() return redirect(url_for('nodes.view', node_id=node_id, embed=1, _external=True, _scheme=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) # 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'): if request.args.get('embed') == '1': # Define the prefix for the embedded template embed_string = '_embed' template = '{0}/edit{1}.html'.format(node_type['name'], embed_string) # We should more simply check if the template file actually exsists on # the filesystem level try: return render_template( template, node=node, parent=parent, form=form, errors=form.errors, error=error, api=api) except TemplateNotFound: template = 'nodes/edit{1}.html'.format(node_type['name'], embed_string) return render_template( template, node=node, parent=parent, form=form, errors=form.errors, error=error, api=api)
def view(project_url): """Entry point to view a project""" api = system_util.pillar_api() # Fetch the Node or 404 try: project = Project.find_one({'where': {"url": project_url}}, api=api) except ResourceNotFound: abort(404) # Set up variables for processing user_id = 'ANONYMOUS' if current_user.is_anonymous() else str(current_user.objectid) rewrite_url = None embedded_node_id = None if request.args.get('redir') and request.args.get('redir') == '1': # Handle special cases (will be mainly used for items that are part # of the blog, or attract) if g.get('embedded_node')['node_type'] == 'post': # Very special case of the post belonging to the main project, # which is read from the configuration. if project._id == app.config['MAIN_PROJECT_ID']: return redirect(url_for('main_blog', url=g.get('embedded_node')['properties']['url'])) else: return redirect(url_for('project_blog', project_url=project.url, url=g.get('embedded_node')['properties']['url'])) rewrite_url = "/p/{0}/#{1}".format(project.url, g.get('embedded_node')['_id']) embedded_node_id = g.get('embedded_node')['_id'] if request.args.get('format') == 'jstree': return jsonify(items=jstree_get_children(None, project._id)) project.picture_square = project.picture_square and get_file(project.picture_square, api=api) project.picture_header = project.picture_header and get_file(project.picture_header, api=api) embed_string = '' if request.args.get('embed'): embed_string = '_embed' list_latest = [] if project.nodes_latest: for node_id in project.nodes_latest: try: node_item = Node.find(node_id, { 'projection': '{"name":1, "user":1, "node_type":1, \ "project": 1}', 'embedded': '{"user":1}', }, api=api) list_latest.append(node_item) except ForbiddenAccess: pass project.nodes_latest = list(reversed(list_latest)) list_featured = [] if project.nodes_featured: for node_id in project.nodes_featured: try: node_item = Node.find(node_id, { 'projection': '{"name":1, "user":1, "picture":1, \ "node_type":1, "project": 1}', 'embedded': '{"user":1}', }, api=api) if node_item.picture: picture = get_file(node_item.picture, api=api) # picture = File.find(node_item.picture, api=api) node_item.picture = picture list_featured.append(node_item) except ForbiddenAccess: pass project.nodes_featured = list(reversed(list_featured)) list_blog = [] if project.nodes_blog: for node_id in project.nodes_blog: try: node_item = Node.find(node_id, { # 'projection': '{"name":1, "user":1, "node_type":1}', 'embedded': '{"user":1}', }, api=api) list_blog.append(node_item) except ForbiddenAccess: pass project.nodes_blog = list(reversed(list_blog)) return render_template("projects/view{0}.html".format(embed_string), embedded_node_id=embedded_node_id, rewrite_url=rewrite_url, user_string_id=user_id, project=project, api=api)