def posts_create(project_id): api = SystemUtility.attract_api() node_type = NodeType.find_first( { 'where': '{"name" : "blog"}', 'projection': '{"name": 1}' }, api=api) blog = Node.find_first( { 'where': '{"node_type" : "%s", \ "parent": "%s"}' % (node_type._id, project_id), }, api=api) node_type = NodeType.find_first({ 'where': '{"name" : "post"}', }, api=api) form = get_node_form(node_type) if form.validate_on_submit(): user_id = current_user.objectid if process_node_form(form, node_type=node_type, user=user_id): return redirect(url_for('main_blog')) form.parent.data = blog._id return render_template('nodes/custom/post/create.html', node_type=node_type, form=form, project_id=project_id)
def task_add(): api = SystemUtility.attract_api() shot_id = request.form["shot_id"] task_name = request.form["task_name"] node_type_list = NodeType.all({"where": "name=='task'"}, api=api) node_type = node_type_list["_items"][0] node_type_id = node_type._id import datetime RFC1123_DATE_FORMAT = "%a, %d %b %Y %H:%M:%S GMT" node = Node() prop = {} prop["node_type"] = node_type_id prop["name"] = task_name prop["description"] = "" prop["user"] = current_user.objectid prop["parent"] = shot_id prop["properties"] = { "status": "todo", "owners": {"users": [], "groups": []}, "time": { "duration": 10, "start": datetime.datetime.strftime(datetime.datetime.now(), "%a, %d %b %Y %H:%M:%S GMT"), }, } post = node.post(prop, api=api) return jsonify(node.to_dict())
def task_add(): api = system_util.pillar_api() shot_id = request.form['shot_id'] task_name = request.form['task_name'] node_type_list = NodeType.all({ 'where': "name=='task'", }, api=api) node_type = node_type_list['_items'][0] node_type_id = node_type._id import datetime RFC1123_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' node = Node() prop = {} prop['node_type'] = node_type_id prop['name'] = task_name prop['description'] = '' prop['user'] = current_user.objectid prop['parent'] = shot_id prop['properties'] = { 'status': 'todo', 'owners': { 'users': [], 'groups': []}, 'time': { 'duration': 10, 'start': datetime.datetime.strftime(datetime.datetime.now(), '%a, %d %b %Y %H:%M:%S GMT')} } post = node.post(prop, api=api) return jsonify(node.to_dict())
def projects(self): """Get list of project for the user""" # Find node_type project id (this could become static) node_type = NodeType.find_first({ 'where': '{"name" : "project"}', }, api=self.api) if not node_type: return abort(404) # Define key for querying for the project if self.is_organization: user_path = 'properties.organization' else: user_path = 'user' # Query for the project # TODO currently, this system is weak since we rely on the user property # of a node when searching for a project using the user it. This allows # us to find a project that belongs to an organization also by requesting # the user that originally created the node. This can be fixed by # introducing a 'user' property in the project node type. projects = Node.all({ 'where': '{"node_type" : "%s", "%s": "%s"}'\ % (node_type._id, user_path, self._id), }, api=self.api) for project in projects._items: attach_project_pictures(project, self.api) return projects
def posts_view(project_id, url=None): """View individual blogpost""" api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "blog"}', 'projection': '{"name": 1}' }, api=api) blog = Node.find_one({ 'where': '{"node_type" : "%s", \ "parent": "%s"}' % (node_type._id, project_id), }, api=api) if url: try: post = Node.find_one({ 'where': '{"parent": "%s", "properties.url": "%s"}' % (blog._id, url), 'embedded': '{"picture":1, "node_type": 1}', }, api=api) except ResourceNotFound: return abort(404) return render_template( 'nodes/custom/post/view.html', blog=blog, node=post) else: # Render all posts posts = Node.all({ 'where': '{"parent": "%s"}' % (blog._id), 'embedded': '{"picture":1}', 'sort': '-_created' }, api=api) return render_template( 'nodes/custom/blog/index.html', blog=blog, posts=posts._items)
def comments_create(): content = request.form['content'] parent_id = request.form.get('parent_id') api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "comment"}', }, api=api) node_asset_props = dict( name='Comment', #description=a.description, #picture=picture, user=current_user.objectid, node_type=node_type._id, #parent=node_parent, properties=dict( content=content, status='published', confidence=0, rating_positive=0, rating_negative=0)) if parent_id: node_asset_props['parent'] = parent_id node_asset = Node(node_asset_props) node_asset.create(api=api) return jsonify( asset_id=node_asset._id, content=node_asset.properties.content)
def index(): """Display the node types """ node_types = NodeType.all() node_types = node_types['_items'] return render_template('node_types/index.html', title='node_types', node_types=node_types)
def type_names(): api = SystemUtility.attract_api() types = NodeType.all(api=api)['_items'] type_names = [] for names in types: type_names.append(str(names['name'])) return type_names
def add(): form = NodeTypeForm() if form.validate_on_submit(): NodeType(name=form.name.data, description=form.description.data, url=form.url.data) return redirect(url_for('node_types.index')) return render_template('node_types/add.html', form=form)
def index(): """Display the node types """ api = system_util.pillar_api() node_types = NodeType.all(api=api) node_types = node_types['_items'] return render_template('node_types/index.html', title='node_types', node_types=node_types)
def edit(node_type_id): node_type = NodeType.find(node_type_id) form = NodeTypeForm(obj=node_type) if form.validate_on_submit(): node_type.name = form.name.data node_type.description = form.description.data node_type.url = form.url.data # Processing custom fields for field in form.properties: print field.data["id"] else: print form.errors return render_template("node_types/edit.html", node_type=node_type, form=form)
def posts_create(project_id): api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "blog"}', 'projection': '{"name": 1}' }, api=api) blog = Node.find_first({ 'where': '{"node_type" : "%s", \ "parent": "%s"}' % (node_type._id, project_id), }, api=api) node_type = NodeType.find_first({'where': '{"name" : "post"}',}, api=api) form = get_node_form(node_type) if form.validate_on_submit(): user_id = current_user.objectid if process_node_form( form, node_type=node_type, user=user_id): return redirect(url_for('main_blog')) form.parent.data = blog._id return render_template('nodes/custom/post/create.html', node_type=node_type, form=form, project_id=project_id)
def edit(node_type_id): node_type = NodeType.find(node_type_id) form = NodeTypeForm(obj=node_type) if form.validate_on_submit(): node_type.name = form.name.data node_type.description = form.description.data node_type.url = form.url.data # Processing custom fields for field in form.properties: print field.data['id'] else: print form.errors return render_template('node_types/edit.html', node_type=node_type, form=form)
def inject_node_types(): if current_user.is_anonymous: return dict(node_types={}) api = SystemUtility.attract_api() types = NodeType.all(api=api)['_items'] node_types = [] for t in types: # If we need to include more info, we can turn node_types into a dict # node_types[t.name] = dict( # url_view=url_for('nodes.index', node_type_name=t.name)) node_types.append(str(t['name'])) return dict(node_types=node_types)
def index(node_type_name=""): """Generic function to list all nodes """ # Pagination index page = request.args.get('page', 1) max_results = 50 api = SystemUtility.attract_api() if node_type_name == "": node_type_name = "shot" node_type = NodeType.find_first( { 'where': '{"name" : "%s"}' % node_type_name, }, api=api) if not node_type: return "Empty NodeType list", 200 nodes = Node.all( { 'where': '{"node_type" : "%s"}' % (node_type._id), 'max_results': max_results, 'page': page, 'embedded': '{"picture":1}', 'sort': "order" }, api=api) # Build the pagination object pagination = Pagination(int(page), max_results, nodes._meta.total) template = '{0}/index.html'.format(node_type_name) try: return render_template(template, title=node_type_name, nodes=nodes, node_type=node_type, type_names=type_names(), pagination=pagination) except TemplateNotFound: return render_template('nodes/index.html', title=node_type_name, nodes=nodes, node_type=node_type, type_names=type_names(), pagination=pagination)
def index(): """Custom production stats entry point """ api = SystemUtility.attract_api() node_type_list = NodeType.all( {'where': '{"name": "%s"}' % ('shot')}, api=api) node_type = node_type_list['_items'][0] nodes = Node.all({ 'where': '{"node_type": "%s"}' % (node_type['_id']), 'max_results': 100, 'sort' : "order"}, api=api) node_statuses = {} node_totals = { 'count': 0, 'frames': 0 } for shot in nodes._items: status = shot.properties.status if status not in node_statuses: # If they key does not exist, initialize with defaults node_statuses[status] = { 'count': 0, 'frames': 0} # Calculate shot duration and increase status count frames = shot.properties.cut_out - shot.properties.cut_in node_statuses[status]['count'] += 1 node_statuses[status]['frames'] += frames # Update the global stats node_totals['count'] += 1 node_totals['frames'] += frames for node_status in node_statuses: # Calculate completion percentage based on total duration print node_statuses[node_status]['frames'] print node_totals['frames'] node_statuses[node_status]['completion'] = percentage( node_statuses[node_status]['frames'], node_totals['frames']) return render_template( 'stats/index.html', node_statuses=node_statuses)
def add(node_type_id): """Generic function to add a node of any type """ api = SystemUtility.attract_api() ntype = NodeType.find(node_type_id, api=api) form = get_node_form(ntype) user_id = current_user.objectid if form.validate_on_submit(): if process_node_form(form, node_type=ntype, user=user_id): return redirect(url_for('nodes.index', node_type_name=ntype['name'])) else: print form.errors return render_template('nodes/add.html', node_type=ntype, form=form, errors=form.errors, type_names=type_names())
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 = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "project"}', 'projection': '{"name": 1}' }, api=api) projects = Node.all({ 'where': '{"node_type" : "%s", \ "properties.category": "%s"}' % (node_type._id, category), 'embedded': '{"picture":1}', }, api=api) for project in projects._items: attach_project_pictures(project, api) return projects
def index(node_type_name=""): """Generic function to list all nodes """ # Pagination index page = request.args.get('page', 1) max_results = 50 api = SystemUtility.attract_api() if node_type_name == "": node_type_name = "shot" node_type = NodeType.find_first({ 'where': '{"name" : "%s"}' % node_type_name, }, api=api) if not node_type: return "Empty NodeType list", 200 nodes = Node.all({ 'where': '{"node_type" : "%s"}' % (node_type._id), 'max_results': max_results, 'page': page, 'embedded': '{"picture":1}', 'sort' : "order"}, api=api) # Build the pagination object pagination = Pagination(int(page), max_results, nodes._meta.total) template = '{0}/index.html'.format(node_type_name) try: return render_template( template, title=node_type_name, nodes=nodes, node_type=node_type, type_names=type_names(), pagination=pagination) except TemplateNotFound: return render_template( 'nodes/index.html', title=node_type_name, nodes=nodes, node_type=node_type, type_names=type_names(), pagination=pagination)
def delete(node_id): """Generic node deletion """ api = SystemUtility.attract_api() node = Node.find(node_id, api=api) name = node.name node_type = NodeType.find(node.node_type, api=api) try: node.delete(api=api) forbidden = False except ForbiddenAccess: forbidden = True if not forbidden: # print (node_type['name']) return redirect(url_for('nodes.index', node_type_name=node_type['name'])) else: return redirect(url_for('nodes.edit', node_id=node._id))
def add(node_type_id): """Generic function to add a node of any type """ api = SystemUtility.attract_api() ntype = NodeType.find(node_type_id, api=api) form = get_node_form(ntype) user_id = current_user.objectid if form.validate_on_submit(): if process_node_form(form, node_type=ntype, user=user_id): return redirect( url_for('nodes.index', node_type_name=ntype['name'])) else: print form.errors return render_template('nodes/add.html', node_type=ntype, form=form, errors=form.errors, type_names=type_names())
def posts_view(project_id, url=None): """View individual blogpost""" api = SystemUtility.attract_api() node_type = NodeType.find_first( { 'where': '{"name" : "blog"}', 'projection': '{"name": 1}' }, api=api) blog = Node.find_one( { 'where': '{"node_type" : "%s", \ "parent": "%s"}' % (node_type._id, project_id), }, api=api) if url: try: post = Node.find_one( { 'where': '{"parent": "%s", "properties.url": "%s"}' % (blog._id, url), 'embedded': '{"picture":1, "node_type": 1}', }, api=api) except ResourceNotFound: return abort(404) return render_template('nodes/custom/post/view.html', blog=blog, node=post) else: # Render all posts posts = Node.all( { 'where': '{"parent": "%s"}' % (blog._id), 'embedded': '{"picture":1}', 'sort': '-_created' }, api=api) return render_template('nodes/custom/blog/index.html', blog=blog, posts=posts._items)
def delete(node_id): """Generic node deletion """ api = system_util.pillar_api() node = Node.find(node_id, api=api) name = node.name node_type = NodeType.find(node.node_type, api=api) try: node.delete(api=api) forbidden = False except ForbiddenAccess: forbidden = True if not forbidden: # print (node_type['name']) return redirect( url_for('nodes.index', node_type_name=node_type['name'])) else: return redirect(url_for('nodes.edit', node_id=node._id))
def project(self, project_name): """Get single project for one user. The project is searched by looking up project directly associated with that user or organization.""" # Find node_type project id (this could become static) node_type = NodeType.find_first({ 'where': '{"name" : "project"}', }, api=self.api) if not node_type: return abort(404) # Define key for querying for the project if self.is_organization: user_path = 'properties.organization' else: user_path = 'user' project_node = Node.find_first({ 'where': '{"node_type" : "%s", "properties.url" : "%s", "%s": "%s"}'\ % (node_type._id, project_name, user_path, self._id), }, api=self.api) if not project_node: return abort(404) return project_node
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 = SystemUtility.attract_api() node_type = NodeType.find_first( { 'where': '{"name" : "project"}', 'projection': '{"name": 1}' }, api=api) projects = Node.all( { 'where': '{"node_type" : "%s", \ "properties.category": "%s"}' % (node_type._id, category), 'embedded': '{"picture":1}', }, api=api) for project in projects._items: attach_project_pictures(project, api) return projects
def task_add(): api = system_util.pillar_api() shot_id = request.form['shot_id'] task_name = request.form['task_name'] node_type_list = NodeType.all({ 'where': "name=='task'", }, api=api) node_type = node_type_list['_items'][0] node_type_id = node_type._id import datetime RFC1123_DATE_FORMAT = '%a, %d %b %Y %H:%M:%S GMT' node = Node() prop = {} prop['node_type'] = node_type_id prop['name'] = task_name prop['description'] = '' prop['user'] = current_user.objectid prop['parent'] = shot_id prop['properties'] = { 'status': 'todo', 'owners': { 'users': [], 'groups': [] }, 'time': { 'duration': 10, 'start': datetime.datetime.strftime(datetime.datetime.now(), '%a, %d %b %Y %H:%M:%S GMT') } } post = node.post(prop, api=api) return jsonify(node.to_dict())
def comments_index(): parent_id = request.args.get('parent_id') if request.args.get('format'): # Get data only if we format it api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "comment"}', }, api=api) nodes = Node.all({ 'where': '{"node_type" : "%s", "parent": "%s"}' % (node_type._id, 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" : "%s", "parent": "%s"}' % (node_type._id, 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=comments) else: # Data will be requested via javascript return_content = render_template('nodes/custom/_comments.html', parent_id=parent_id) return return_content
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: if not prop in node_properties: continue 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)) else: try: data = node_properties[prop] except KeyError: print("{0} not found in form".format(prop_name)) if schema_prop['type'] == 'datetime': data = datetime.strptime(data, RFC1123_DATE_FORMAT) if prop_name in form: # Other field types 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 data] # Choices should be a tuple with value and name # Assign data to the field if set_data: form[prop_name].data = data api = SystemUtility.attract_api() node = Node.find(node_id, api=api) # TODO: simply embed node_type node_type = NodeType.find(node.node_type, api=api) 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_type_name = node_type.name node_properties = node.properties.to_dict() 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): project_update_nodes_list(node_id) return redirect(url_for('nodes.view', node_id=node_id, embed=1)) else: error = "Server error" print("Error sending data") else: print 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 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) 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)
def assets_create(): name = request.form['name'] parent_id = request.form.get('parent_id') # Detect filetype by extension (improve by detectin real file type) root, ext = os.path.splitext(name) if ext in ['.jpg', '.jpeg', '.png', '.tif', '.tiff']: filetype = 'image' elif ext in ['.blend', '.txt', '.zip']: filetype = 'file' elif ext in ['.mov', '.avi', '.mp4', '.m4v']: filetype = 'video' else: filetype = 'file' # Hash name based on file name, user id and current timestamp hash_name = name + str(current_user.objectid) + str(round(time.time())) link = hashlib.sha1(hash_name).hexdigest() link = os.path.join(link[:2], link + ext) api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "asset"}', }, api=api) # We will create the Node object later on, after creating the file object node_asset_props = dict( name=name, #description=a.description, #picture=picture, user=current_user.objectid, node_type=node_type._id, #parent=node_parent, properties=dict( content_type=filetype, #file=a.link[4:], status='processing')) src_dir_path = os.path.join(app.config['UPLOAD_DIR'], str(current_user.objectid)) # Move the file in designated location destination_dir = os.path.join(app.config['SHARED_DIR'], link[:2]) if not os.path.isdir(destination_dir): os.makedirs(destination_dir) # (TODO) Check if filename already exsits src_file_path = os.path.join(src_dir_path, name) dst_file_path = os.path.join(destination_dir, link[3:]) # (TODO) Thread this operation shutil.copy(src_file_path, dst_file_path) if filetype == 'file': mime_type = 'application' else: mime_type = filetype content_type = "{0}/{1}".format(mime_type, ext.replace(".", "")) node_file = File({ 'name': link, 'filename': name, 'user': current_user.objectid, 'backend': 'cdnsun', 'md5': '', 'content_type': content_type, 'length': 0 }) node_file.create(api=api) node_asset_props['properties']['file'] = node_file._id if parent_id: node_asset_props['parent'] = parent_id node_asset = Node(node_asset_props) node_asset.create(api=api) return jsonify(link=link, name=name, filetype=filetype, asset_id=node_asset._id)
def index(): """Display the node types """ node_types = NodeType.all() node_types = node_types["_items"] return render_template("node_types/index.html", title="node_types", node_types=node_types)
def shots_index(): max_results = 100 api = system_util.pillar_api() node_type_name = "shot" node_type_list = NodeType.all( { 'where': '{"name" : "%s"}' % node_type_name, }, api=api) node_type = node_type_list._items[0] nodes = Node.all( { 'where': '{"node_type" : "%s"}' % node_type._id, 'max_results': max_results, 'embedded': '{"picture":1}', 'sort': "order" }, api=api) # Get the task node type object id node_type_list = NodeType.all({ 'where': '{"name" : "task"}', }, api=api) node_type_task = node_type_list._items[0] nodes_datatables = [] for node in nodes._items: tasks = Node.all({ 'where': '{"node_type" : "%s", "parent" : "%s"}'\ % (node_type_task._id, node._id), 'sort' : "order"}, api=api) shot_status = None try: shot_status = node.properties.status except: # Notify about missing status property. This should be prominent. pass data = { 'DT_RowId': "row_{0}".format(node._id), 'DT_RowAttr': { 'data-shot-status': shot_status }, '_id': node._id, 'order': node.order, 'picture': None, 'name': node.name, #'description': node.description, 'notes': node.properties.notes, 'timing': { 'cut_in': node.properties.cut_in, 'cut_out': node.properties.cut_out }, 'url_view': url_for('nodes.view', node_id=node._id), 'url_edit': url_for('nodes.edit', node_id=node._id, embed=1), 'tasks': { 'animation': None, 'lighting': None, 'fx_hair': None, 'fx_grass': None, 'fx_smoke': None }, } if node.picture: # This is an address on the Attract server, so it should be built # entirely here data['picture'] = "{0}/file_server/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], node.picture.path) # Get previews picture_node = File.find(node.picture['_id'] + \ '/?embedded={"previews":1}', api=api) if picture_node.previews: for preview in picture_node.previews: if preview.size == 'm': data['picture_thumbnail'] = app.config[ 'PILLAR_SERVER_ENDPOINT'] + "/file_server/file/" + preview.path break else: data['picture_thumbnail'] = data['picture'] if node.order is None: data['order'] = 0 for task in tasks._items: # If there are tasks assigned to the shot we loop through them and # match them with the existing data indexes. if task.name in data['tasks']: data['tasks'][task.name] = { 'name': task.name, 'status': task.properties.status, 'url_view': url_for('nodes.view', node_id=task._id, embed=1), 'url_edit': url_for('nodes.edit', node_id=task._id, embed=1), 'is_conflicting': task.properties.is_conflicting, 'is_processing': task.properties.is_rendering, 'is_open': task.properties.is_open } nodes_datatables.append(data) return jsonify(data=nodes_datatables)
def shots_index(): max_results = 100 api = system_util.pillar_api() node_type_name = "shot" node_type_list = NodeType.all({ 'where': '{"name" : "%s"}' % node_type_name, }, api=api) node_type = node_type_list._items[0] nodes = Node.all({ 'where': '{"node_type" : "%s"}' % node_type._id, 'max_results': max_results, 'embedded': '{"picture":1}', 'sort' : "order"}, api=api) # Get the task node type object id node_type_list = NodeType.all({ 'where': '{"name" : "task"}', }, api=api) node_type_task = node_type_list._items[0] nodes_datatables = [] for node in nodes._items: tasks = Node.all({ 'where': '{"node_type" : "%s", "parent" : "%s"}'\ % (node_type_task._id, node._id), 'sort' : "order"}, api=api) shot_status = None try: shot_status = node.properties.status except: # Notify about missing status property. This should be prominent. pass data = { 'DT_RowId': "row_{0}".format(node._id), 'DT_RowAttr': {'data-shot-status':shot_status}, '_id': node._id, 'order': node.order, 'picture': None, 'name': node.name, #'description': node.description, 'notes': node.properties.notes, 'timing': { 'cut_in': node.properties.cut_in, 'cut_out': node.properties.cut_out }, 'url_view': url_for('nodes.view', node_id=node._id), 'url_edit': url_for('nodes.edit', node_id=node._id, embed=1), 'tasks': { 'animation': None, 'lighting': None, 'fx_hair': None, 'fx_grass': None, 'fx_smoke': None }, } if node.picture: # This is an address on the Attract server, so it should be built # entirely here data['picture'] = "{0}/file_server/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], node.picture.path) # Get previews picture_node = File.find(node.picture['_id'] + \ '/?embedded={"previews":1}', api=api) if picture_node.previews: for preview in picture_node.previews: if preview.size == 'm': data['picture_thumbnail'] = app.config['PILLAR_SERVER_ENDPOINT'] + "/file_server/file/" + preview.path break else: data['picture_thumbnail'] = data['picture'] if node.order is None: data['order'] = 0 for task in tasks._items: # If there are tasks assigned to the shot we loop through them and # match them with the existing data indexes. if task.name in data['tasks']: data['tasks'][task.name] = { 'name': task.name, 'status': task.properties.status, 'url_view': url_for('nodes.view', node_id=task._id, embed=1), 'url_edit': url_for('nodes.edit', node_id=task._id, embed=1), 'is_conflicting': task.properties.is_conflicting, 'is_processing': task.properties.is_rendering, 'is_open': task.properties.is_open } nodes_datatables.append(data) return jsonify(data=nodes_datatables)
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: if not prop in node_properties: continue 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)) else: try: data = node_properties[prop] except KeyError: print ("{0} not found in form".format(prop_name)) if schema_prop['type'] == 'datetime': data = datetime.strptime(data, RFC1123_DATE_FORMAT) if prop_name in form: # Other field types 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 data] # Choices should be a tuple with value and name # Assign data to the field if set_data: form[prop_name].data = data api = SystemUtility.attract_api() node = Node.find(node_id, api=api) # TODO: simply embed node_type node_type = NodeType.find(node.node_type, api=api) 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_type_name = node_type.name node_properties = node.properties.to_dict() 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): project_update_nodes_list(node_id) return redirect(url_for('nodes.view', node_id=node_id, embed=1)) else: error = "Server error" print ("Error sending data") else: print 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 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) 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)
def assets_create(): name = request.form['name'] parent_id = request.form.get('parent_id') # Detect filetype by extension (improve by detectin real file type) root, ext = os.path.splitext(name) if ext in ['.jpg', '.jpeg', '.png', '.tif', '.tiff']: filetype = 'image' elif ext in ['.blend', '.txt', '.zip']: filetype = 'file' elif ext in ['.mov', '.avi', '.mp4', '.m4v']: filetype = 'video' else: filetype = 'file' # Hash name based on file name, user id and current timestamp hash_name = name + str(current_user.objectid) + str(round(time.time())) link = hashlib.sha1(hash_name).hexdigest() link = os.path.join(link[:2], link + ext) api = SystemUtility.attract_api() node_type = NodeType.find_first({ 'where': '{"name" : "asset"}', }, api=api) # We will create the Node object later on, after creating the file object node_asset_props = dict( name=name, #description=a.description, #picture=picture, user=current_user.objectid, node_type=node_type._id, #parent=node_parent, properties=dict( content_type=filetype, #file=a.link[4:], status='processing')) src_dir_path = os.path.join(app.config['UPLOAD_DIR'], str(current_user.objectid)) # Move the file in designated location destination_dir = os.path.join(app.config['SHARED_DIR'], link[:2]) if not os.path.isdir(destination_dir): os.makedirs(destination_dir) # (TODO) Check if filename already exsits src_file_path = os.path.join(src_dir_path, name) dst_file_path = os.path.join(destination_dir, link[3:]) # (TODO) Thread this operation shutil.copy(src_file_path, dst_file_path) if filetype == 'file': mime_type = 'application' else: mime_type = filetype content_type = "{0}/{1}".format(mime_type, ext.replace(".", "")) node_file = File({ 'name': link, 'filename': name, 'user': current_user.objectid, 'backend': 'cdnsun', 'md5': '', 'content_type': content_type, 'length': 0 }) node_file.create(api=api) node_asset_props['properties']['file'] = node_file._id if parent_id: node_asset_props['parent'] = parent_id node_asset = Node(node_asset_props) node_asset.create(api=api) return jsonify( link=link, name=name, filetype=filetype, asset_id=node_asset._id)