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 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 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 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 __init__(self, name): self.api = SystemUtility.attract_api() # Check if organization exists user = Organization.find_first({ 'where': '{"url" : "%s"}' % (name), }, api=self.api) if user: self.is_organization = True self.name = user.name self.url = user.url self.description = user.description self.gravatar = gravatar(user.email) else: # Check if user exists user = User.find_first({ 'where': '{"username" : "%s"}' % (name), }, api=self.api) if user: self.is_organization = False self.name = user.first_name self.url = user.username else: return abort(404) self._id = user._id
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 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 tasks(): """User-assigned tasks""" # Pagination index page = request.args.get("page", 1) max_results = 50 api = SystemUtility.attract_api() node_type_list = NodeType.all({"where": "name=='task'"}, api=api) if len(node_type_list["_items"]) == 0: return "Empty NodeType list", 200 node_type = node_type_list._items[0] tasks = Node.all( { "where": '{"node_type" : "%s", "properties.owners.users": {"$in": ["%s"]}}' % (node_type["_id"], current_user.objectid), "max_results": max_results, "page": page, "embedded": '{"parent":1, "picture":1}', "sort": "order", }, api=api, ) # Build the pagination object # pagination = Pagination(int(page), max_results, tasks._meta.total) tasks_datatable = [] for task in tasks._items: cut_in = 0 cut_out = 0 if task.parent.properties.cut_in: cut_in = task.parent.properties.cut_in if task.parent.properties.cut_out: cut_out = task.parent.properties.cut_out data = { "DT_RowId": "row_{0}".format(task._id), "_id": task._id, "order": task.order, "picture": None, "name": task.name, "timing": {"cut_in": task.parent.properties.cut_in, "cut_out": task.parent.properties.cut_out}, "parent": task.parent.to_dict(), "description": task.description, "url_view": url_for("nodes.view", node_id=task._id), "url_edit": url_for("nodes.edit", node_id=task._id, embed=1), "status": task.properties.status, } tasks_datatable.append(data) return render_template( "users/tasks.html", title="task", tasks_data=json.dumps(tasks_datatable), node_type=node_type )
def tasks(): """User-assigned tasks""" # Pagination index page = request.args.get('page', 1) max_results = 50 api = SystemUtility.attract_api() node_type_list = NodeType.all({'where': "name=='task'"}, api=api) if len(node_type_list['_items']) == 0: return "Empty NodeType list", 200 node_type = node_type_list._items[0] tasks = Node.all({ 'where': '{"node_type" : "%s", "properties.owners.users": {"$in": ["%s"]}}'\ % (node_type['_id'], current_user.objectid), 'max_results': max_results, 'page': page, 'embedded': '{"parent":1, "picture":1}', 'sort' : "order"}, api=api) # Build the pagination object # pagination = Pagination(int(page), max_results, tasks._meta.total) tasks_datatable = [] for task in tasks._items: cut_in = 0 cut_out = 0 if task.parent.properties.cut_in: cut_in = task.parent.properties.cut_in if task.parent.properties.cut_out: cut_out = task.parent.properties.cut_out data = { 'DT_RowId': "row_{0}".format(task._id), '_id': task._id, 'order': task.order, 'picture': None, 'name': task.name, 'timing': { 'cut_in': task.parent.properties.cut_in, 'cut_out': task.parent.properties.cut_out, }, 'parent': task.parent.to_dict(), 'description': task.description, 'url_view': url_for('nodes.view', node_id=task._id), 'url_edit': url_for('nodes.edit', node_id=task._id, embed=1), 'status': task.properties.status, } tasks_datatable.append(data) return render_template('users/tasks.html', title="task", tasks_data=json.dumps(tasks_datatable), node_type=node_type)
def projects_move_node(): # Process the move action node_id = request.form['node_id'] dest_parent_node_id = request.form['dest_parent_node_id'] api = SystemUtility.attract_api() node = Node.find(node_id, api=api) node.parent = dest_parent_node_id node.update(api=api) return jsonify(status='success', data=dict(message='node moved'))
def assigned_users_to(node, node_type): api = SystemUtility.attract_api() if node_type['name'] != "task": return [] users = node['properties']['owners']['users'] owners = [] for user in users: user_node = User.find(user, api=api) owners.append(user_node) return owners
def profile(): """Profile view and edit page. This is a temporary implementation. """ api = SystemUtility.attract_api() user = User.find(current_user.objectid, api=api) form = UserProfileForm(first_name=user.first_name, last_name=user.last_name) if form.validate_on_submit(): user.first_name = form.first_name.data user.last_name = form.last_name.data user.update(api=api) flash("Profile updated") return render_template("users/profile.html", form=form)
def authenticate(username, password): import requests import socket payload = dict(username=username, password=password, hostname=socket.gethostname()) try: r = requests.post("{0}/u/identify".format(SystemUtility.blender_id_endpoint()), data=payload) except requests.exceptions.ConnectionError as e: raise e if r.status_code == 200: response = r.json() else: response = None return response
def profile(): """Profile view and edit page. This is a temporary implementation. """ api = SystemUtility.attract_api() user = User.find(current_user.objectid, api=api) form = UserProfileForm(first_name=user.first_name, last_name=user.last_name) if form.validate_on_submit(): user.first_name = form.first_name.data user.last_name = form.last_name.data user.update(api=api) flash("Profile updated") return render_template('users/profile.html', form=form)
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 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(): """Generic function to list all nodes """ # Pagination index page = request.args.get("page", 1) max_results = 50 api = SystemUtility.attract_api() organizations = Organization.all({"max_results": max_results, "page": page}, api=api) # Build the pagination object pagination = Pagination(int(page), max_results, organizations._meta.total) template = "organizations/index.html" return render_template(template, title="organizations", organizations=organizations, 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 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 authenticate(username, password): import requests import socket payload = dict(username=username, password=password, hostname=socket.gethostname()) try: r = requests.post("{0}/u/identify".format( SystemUtility.blender_id_endpoint()), data=payload) except requests.exceptions.ConnectionError as e: raise e if r.status_code == 200: response = r.json() else: response = None return response
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 jstree_get_children(node_id): api = SystemUtility.attract_api() children_list = [] if node_id.startswith('n_'): node_id = node_id.split('_')[1] try: children = Node.all({ 'projection': '{"name": 1, "parent": 1, "node_type": 1, "properties": 1}', 'embedded': '{"node_type": 1}', 'where': '{"parent": "%s"}' % node_id}, api=api) for child in children._items: # Skip nodes of type comment if child.node_type.name != 'comment': children_list.append(jstree_parse_node(child)) except ForbiddenAccess: pass return children_list
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 shot_edit(): """We want to be able to edit the following properties: - notes - status - cut in - cut out - picture (optional) """ api = SystemUtility.attract_api() shot_id = request.form['shot_id'] shot = Node.find(shot_id, api=api) shot.properties.notes = request.form['shot_notes'] shot.properties.status = request.form['shot_status'] shot.properties.cut_in = int(request.form['shot_cut_in']) shot.properties.cut_out = int(request.form['shot_cut_out']) shot.update(api=api) return jsonify(shot.to_dict())
def create(): name = request.form['name'] size = request.form['size'] content_type = request.form['type'] root, ext = os.path.splitext(name) # 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) 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) api = SystemUtility.attract_api() node_file = File({ 'name': link, 'filename': name, 'user': current_user.objectid, 'backend': 'cdnsun', 'md5': '', 'content_type': content_type, 'length': size }) node_file.create(api=api) thumbnail = node_file.thumbnail_file('s', api=api) return jsonify(status='success', data=dict(id=node_file._id, link=thumbnail.link))
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 project_update_nodes_list(node_id, 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 not project_id and 'current_project_id' in session: project_id = session['current_project_id'] elif not project_id: return None api = SystemUtility.attract_api() project = Node.find(project_id, api=api) if list_name == 'latest': nodes_list = project.properties.nodes_latest else: nodes_list = project.properties.nodes_featured # Do not allow adding project to lists if node_id == project._id: return "fail" if not nodes_list: node_list_name = 'nodes_' + list_name project.properties[node_list_name] = [] nodes_list = project.properties[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 jstree_get_children(node_id): api = SystemUtility.attract_api() children_list = [] if node_id.startswith('n_'): node_id = node_id.split('_')[1] try: children = Node.all( { 'projection': '{"name": 1, "parent": 1, "node_type": 1, "properties": 1}', 'embedded': '{"node_type": 1}', 'where': '{"parent": "%s"}' % node_id }, api=api) for child in children._items: # Skip nodes of type comment if child.node_type.name != 'comment': children_list.append(jstree_parse_node(child)) except ForbiddenAccess: pass return children_list
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 = 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 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 index(): """Generic function to list all nodes """ # Pagination index page = request.args.get('page', 1) max_results = 50 api = SystemUtility.attract_api() organizations = Organization.all({ 'max_results': max_results, 'page': page }, api=api) # Build the pagination object pagination = Pagination(int(page), max_results, organizations._meta.total) template = 'organizations/index.html' return render_template(template, title='organizations', organizations=organizations, pagination=pagination)
def comments_rate(comment_id): """Comment rating function :param comment_id: the comment id :type comment_id: str :param rating: the rating (is cast from 0 to False and from 1 to True) :type rating: int """ rating_is_positive = False if request.form['is_positive'] == 'false' else True api = SystemUtility.attract_api() comment = Node.find(comment_id, api=api) # Check if comment has been rated user_comment_rating = None if comment.properties.ratings: for rating in comment.properties.ratings: if rating['user'] == current_user.objectid: user_comment_rating = rating #r = next((r for r in comment.ratings if r['user'] == current_user.objectid), None) if user_comment_rating: # Update or remove rating if user_comment_rating['is_positive'] == rating_is_positive: # If the rating matches, remove the it comment.properties.ratings.remove(user_comment_rating) # Update global rating values if rating_is_positive: comment.properties.rating_positive -= 1 else: comment.properties.rating_negative -= 1 comment.update(api=api) return_data = dict(is_rated=False, rating_up=comment.properties.rating_positive) else: # If the rating differs from the current, update its value. In this # case we make sure we update the existing global rating values as well user_comment_rating['is_positive'] = rating_is_positive if rating_is_positive: comment.properties.rating_positive += 1 comment.properties.rating_negative -= 1 else: comment.properties.rating_negative += 1 comment.properties.rating_positive -= 1 comment.update(api=api) return_data = dict(is_positive=rating_is_positive, is_rated=True, rating_up=comment.properties.rating_positive) else: # Create rating for current user user_comment_rating = dict(user=current_user.objectid, is_positive=rating_is_positive, # Hardcoded to default (auto valid) weight=3) if not comment.properties.ratings: comment.properties.ratings = [] comment.properties.ratings.append(user_comment_rating) if rating_is_positive: comment.properties.rating_positive += 1 else: comment.properties.rating_negative += 1 comment.update(api=api) return_data = dict(is_positive=rating_is_positive, is_rated=True, rating_up=comment.properties.rating_positive) return jsonify(status='success', data=return_data)
def task_edit(): """We want to be able to edit the following properties: - status - owners - description - picture (optional) """ api = SystemUtility.attract_api() task_id = request.form["task_id"] task = Node.find(task_id, api=api) task.description = request.form["task_description"] if request.form["task_revision"]: task.properties.revision = int(request.form["task_revision"]) task.properties.status = request.form["task_status"] task.properties.filepath = request.form["task_filepath"] task.properties.owners.users = request.form.getlist("task_owners_users[]") siblings = Node.all( {"where": 'parent==ObjectId("%s")' % task.parent, "embedded": '{"picture":1, "user":1}'}, api=api ) def check_conflict(task_current, task_sibling): return revsion_conflict[task_current.name](task_current, task_sibling) def task_animation(task_current, task_sibling): if task_sibling.name in ["fx_hair", "fx_smoke", "fx_grass", "lighting"]: if task_current.properties.revision > task_sibling.properties.revision: return True return False def task_lighting(task_current, task_sibling): if task_sibling.name in ["fx_hair", "fx_smoke", "fx_grass", "animation"]: if task_current.properties.revision < task_sibling.properties.revision: return True return False def task_fx_hair(task_current, task_sibling): if task_sibling.name in ["animation"]: if task_current.properties.revision < task_sibling.properties.revision: return True if task_sibling.name in ["lighting"]: if task_current.properties.revision > task_sibling.properties.revision: return True return False def task_fx_grass(task_current, task_sibling): pass def task_fx_smoke(task_current, task_sibling): pass revsion_conflict = { "animation": task_animation, "lighting": task_lighting, "fx_hair": task_fx_hair, "fx_grass": task_fx_grass, "fx_smoke": task_fx_smoke, } if task.properties.revision: for sibling in siblings._items: if sibling.properties.revision and sibling._id != task_id: if check_conflict(task, sibling) == True: task.properties.is_conflicting = True break else: task.properties.is_conflicting = False task.update(api=api) return jsonify(task.to_dict())
def process_node_form(form, node_id=None, node_type=None, user=None): """Generic function used to process new nodes, as well as edits """ if not user: print ("User is None") return False api = SystemUtility.attract_api() node_schema = node_type['dyn_schema'].to_dict() form_schema = node_type['form_schema'].to_dict() if node_id: # Update existing node node = pillarsdk.Node.find(node_id, api=api) node.name = form.name.data node.description = form.description.data if 'picture' in form: node.picture = form.picture.data if node.picture == "None": node.picture = None if 'parent' in form: node.parent = form.parent.data def update_data(node_schema, form_schema, prefix=""): for pr in node_schema: schema_prop = node_schema[pr] form_prop = form_schema[pr] if pr == 'items': continue if 'visible' in form_prop and not form_prop['visible']: continue prop_name = "{0}{1}".format(prefix, pr) if schema_prop['type'] == 'dict': update_data( schema_prop['schema'], form_prop['schema'], "{0}__".format(prop_name)) continue data = form[prop_name].data if schema_prop['type'] == 'dict': if data == 'None': continue if schema_prop['type'] == 'integer': if data == '': data = 0 else: data = int(form[prop_name].data) if schema_prop['type'] == 'datetime': data = datetime.strftime(data, RFC1123_DATE_FORMAT) else: if pr in form: data = form[prop_name].data path = prop_name.split('__') if len(path) > 1: recursive_prop = recursive( path, node.properties.to_dict(), data) node.properties = recursive_prop else: node.properties[prop_name] = data update_data(node_schema, form_schema) # send_file(form, node, user) update = node.update(api=api) # if form.picture.data: # image_data = request.files[form.picture.name].read() # post = node.replace_picture(image_data, api=api) return update else: # Create a new node node = pillarsdk.Node() prop = {} files = {} prop['name'] = form.name.data prop['description'] = form.description.data prop['user'] = user if 'picture' in form: prop['picture'] = form.picture.data if prop['picture'] == 'None': prop['picture'] = None if 'parent' in form: prop['parent'] = form.parent.data prop['properties'] = {} def get_data(node_schema, form_schema, prefix=""): for pr in node_schema: schema_prop = node_schema[pr] form_prop = form_schema[pr] if pr == 'items': continue if 'visible' in form_prop and not form_prop['visible']: continue prop_name = "{0}{1}".format(prefix, pr) if schema_prop['type'] == 'dict': get_data( schema_prop['schema'], form_prop['schema'], "{0}__".format(prop_name)) continue data = form[prop_name].data if schema_prop['type'] == 'media': tmpfile = '/tmp/binary_data' data.save(tmpfile) binfile = open(tmpfile, 'rb') files[pr] = binfile continue if schema_prop['type'] == 'integer': if data == '': data = 0 if schema_prop['type'] == 'list': if data == '': data = [] if schema_prop['type'] == 'datetime': data = datetime.strftime(data, RFC1123_DATE_FORMAT) if schema_prop['type'] == 'objectid': if data == '': data = None path = prop_name.split('__') if len(path) > 1: prop['properties'] = recursive(path, prop['properties'], data) else: prop['properties'][prop_name] = data get_data(node_schema, form_schema) prop['node_type'] = form.node_type_id.data post = node.post(prop, api=api) return post
def index(): """Custom files entry point """ rfiles = [] backend = app.config['STORAGE_BACKEND'] api = SystemUtility.attract_api() user = current_user.objectid node_picture = File() for file_ in request.files: filestorage = request.files[file_] # Save file on AttractWeb Storage picture_path = os.path.join( app.config['UPLOAD_DIR'], filestorage.filename) filestorage.save(picture_path) picture_file_file = open(picture_path, 'rb') if backend == 'pillar': hash_ = hashfile(picture_file_file, hashlib.md5()) name = "{0}{1}".format(hash_, os.path.splitext(picture_path)[1]) picture_file_file.close() file_check = node_picture.all( {"where": "path=='{0}'".format(name)}, api=api) file_check = file_check['_items'] if len(file_check) == 0: prop = {} prop['name'] = filestorage.filename prop['description'] = "File {0}".format(filestorage.filename) prop['user'] = user prop['content_type'] = filestorage.content_type # TODO Fix length value prop['length'] = filestorage.content_length prop['md5'] = hash_ prop['filename'] = filestorage.filename prop['backend'] = backend if backend in ["pillar"]: prop['path'] = name node_picture.post(prop, api=api) prop['_id'] = node_picture['_id'] if backend == 'pillar': node_picture.post_file(picture_path, name, api=api) node_picture.build_previews(name, api=api) url = "{0}/file_storage/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], prop['path']) rfiles.append( { "id": prop['_id'], "name": prop['filename'], "size": prop['length'], "url": url, "thumbnailUrl": url, "deleteUrl": url, "deleteType": "DELETE" }) else: url = "{0}/file_storage/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], file_check[0]['path']) rfiles.append( { "id": file_check[0]['_id'], "name": file_check[0]['filename'], "size": file_check[0]['length'], "url": url, "thumbnailUrl": url, "deleteUrl": url, "deleteType": "DELETE" }) return jsonify(dict(files=rfiles))
def entrypoint(self): return os.path.join(SystemUtility.attract_server_endpoint(), self.path, self.storage_node.properties.backend, self.storage_node.properties.project, self.storage_node.properties.subdir)
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 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 view(node_id): #import time #start = time.time() api = SystemUtility.attract_api() # Get node with embedded picture data try: node = Node.find(node_id + '/?embedded={"picture":1, "node_type":1}', api=api) except ResourceNotFound: return abort(404) except ForbiddenAccess: return abort(403) node_type_name = node.node_type.name # JsTree functionality. # This return a lightweight version of the node, to be used by JsTree in the # frontend. We have two possible cases: # - https://pillar/<node_id>/view?format=jstree (construct the whole expanded # tree starting from the node_id. Use only once) # - https://pillar/<node_id>/view?format=jstree&children=1 (deliver the # children of a node - use in the navigation of the tree) if request.args.get('format') and request.args.get('format') == 'jstree': if request.args.get('children') == '1': if node_type_name == 'storage': storage = StorageNode(node) # Check if we specify a path within the storage path = request.args.get('path') # Generate the storage listing listing = storage.browse(path) # Inject the current node id in the response, so that JsTree can # expose the storage_node property and use it for further queries listing['storage_node'] = node._id if 'children' in listing: for child in listing['children']: child['storage_node'] = node._id return jsonify(listing) else: return jsonify(jstree_build_children(node)) else: return jsonify(items=jstree_build_from_node(node)) # Continue to process the node (for HTML, HTML embeded and JSON responses) # Set the default name of the template path based on the node name template_path = os.path.join('nodes', 'custom', node_type_name) # Set the default action for a template. By default is view and we override # it only if we are working storage nodes, where an 'index' is also possible template_action = 'view' # XXX Code to detect a node of type asset, and aggregate file data if node_type_name == 'asset': node_file = File.find(node.properties.file, api=api) node_file_children = node_file.children(api=api) # Attach the file node to the asset node setattr(node, 'file', node_file) try: asset_type = node_file.content_type.split('/')[0] except AttributeError: asset_type = None if asset_type == 'video': # Process video type and select video template sources = [] if node_file_children: for f in node_file_children._items: sources.append(dict( type=f.content_type, src=f.link)) setattr(node, 'video_sources', json.dumps(sources)) setattr(node, 'file_children', node_file_children) template_path = os.path.join(template_path, asset_type) elif asset_type == 'image': # Process image type and select image template #setattr(node, 'file_children', node_file_children) template_path = os.path.join(template_path, asset_type) else: # Treat it as normal file (zip, blend, application, etc) template_path = os.path.join(template_path, 'file') # XXX The node is of type project elif node_type_name == 'project': if node.properties.picture_square: picture_square = File.find(node.properties.picture_square, api=api) node.properties.picture_square = picture_square if node.properties.picture_header: picture_header = File.find(node.properties.picture_header, api=api) node.properties.picture_header = picture_header if node.properties.nodes_latest: list_latest = [] for node_id in node.properties.nodes_latest: try: node_item = Node.find(node_id, { 'projection': '{"name":1, "user":1, "node_type":1}', 'embedded': '{"user":1}', }, api=api) list_latest.append(node_item) except ForbiddenAccess: list_latest.append(FakeNodeAsset()) node.properties.nodes_latest = list(reversed(list_latest)) if node.properties.nodes_featured: list_featured = [] for node_id in node.properties.nodes_featured: try: node_item = Node.find(node_id, { 'projection': '{"name":1, "user":1, "picture":1, "node_type":1}', 'embedded': '{"user":1}', }, api=api) picture = File.find(node_item.picture, api=api) node_item.picture = picture list_featured.append(node_item) except ForbiddenAccess: list_featured.append(FakeNodeAsset()) node.properties.nodes_featured = list(reversed(list_featured)) elif node_type_name == 'storage': storage = StorageNode(node) path = request.args.get('path') listing = storage.browse(path) node.name = listing['name'] listing['storage_node'] = node._id # If the item has children we are working with a group if 'children' in listing: for child in listing['children']: child['storage_node'] = node._id child['name'] = child['text'] child['content_type'] = os.path.dirname(child['type']) node.children = listing['children'] template_action = 'index' else: node.status = 'published' node.length = listing['size'] node.download_link = listing['signed_url'] # Get previews if node.picture: node.picture = File.find(node.picture._id, api=api) # Get Parent try: parent = Node.find(node['parent'], api=api) except KeyError: parent = None except ResourceNotFound: parent = None # Get children try: children = Node.all({ 'where': '{"parent": "%s"}' % node._id, 'embedded': '{"picture": 1, "node_type": 1}'}, api=api) children = children._items except ForbiddenAccess: return abort(403) for child in children: if child.picture: child.picture = File.find(child.picture._id, api=api) if request.args.get('format'): if request.args.get('format') == 'json': node = node.to_dict() node['url_edit'] = url_for('nodes.edit', node_id=node['_id']), if parent: parent = parent.to_dict() return_content = jsonify({ 'node': node, 'children': children.to_dict(), 'parent': parent }) else: 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' # Check if template exists on the filesystem template_path = '{0}/{1}{2}.html'.format(template_path, template_action, embed_string) template_path_full = os.path.join(app.config['TEMPLATES_PATH'], template_path) if not os.path.exists(template_path_full): return "Missing template" return_content = render_template(template_path, node=node, type_names=type_names(), parent=parent, children=children, config=app.config) #print(time.time() - start) return return_content
def shots_index(): max_results = 100 api = SystemUtility.attract_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 get_node_form(node_type): class ProceduralForm(Form): pass api = SystemUtility.attract_api() node_schema = node_type['dyn_schema'].to_dict() form_prop = node_type['form_schema'].to_dict() parent_prop = node_type['parent'].to_dict() setattr(ProceduralForm, 'name', TextField('Name', validators=[DataRequired()])) # Parenting if 'node_types' in parent_prop and len(parent_prop['node_types']) > 0: # select = [] # for parent_type in parent_prop['node_types']: # parent_node_type = pillarsdk.NodeType.all( # {'where': '{"name" : "%s"}' % parent_type}, api=api) # nodes = Node.all({ # 'where': '{"node_type" : "%s"}' % str( # parent_node_type._items[0]['_id']), # 'max_results': 999, # 'sort': "order"}, # api=api) # for option in nodes._items: # select.append((str(option._id), str(option.name))) parent_names = "" for parent_type in parent_prop['node_types']: parent_names = "{0} {1},".format(parent_names, parent_type) # setattr(ProceduralForm, # 'parent', # SelectField('Parent ({0})'.format(parent_names), # choices=select)) setattr(ProceduralForm, 'parent', HiddenField('Parent ({0})'.format(parent_names))) setattr(ProceduralForm, 'description', TextAreaField('Description')) setattr(ProceduralForm, 'picture', FileSelectField('Picture')) setattr(ProceduralForm, 'node_type_id', HiddenField(default=node_type._id)) def build_form(node_schema, form_schema, prefix=""): for prop in node_schema: schema_prop = node_schema[prop] form_prop = form_schema[prop] if prop == 'items': continue if 'visible' in form_prop and not form_prop['visible']: continue prop_name = "{0}{1}".format(prefix, prop) # Recursive call if detects a dict if schema_prop['type'] == 'dict': # This works if the dictionary schema is hardcoded. # I we define it useing propertyschema dna valueschema, this # validation pattern does not work and crahses. build_form(schema_prop['schema'], form_prop['schema'], "{0}__".format(prop_name)) continue if schema_prop['type'] == 'list' and 'items' in form_prop: # Attempt at populating the content of a select menu. If this # is a large collection this will not work because of pagination. # This whole section should just be removed in the future. See # the next statement for an improved approach to this. for item in form_prop['items']: items = eval("pillarsdk.{0}".format(item[0])) items_to_select = items.all(api=api) if items_to_select: items_to_select = items_to_select["_items"] else: items_to_select = [] select = [] for select_item in items_to_select: select.append( (select_item['_id'], select_item[item[1]])) if item[0] == 'File': setattr(ProceduralForm, prop_name, FileSelectMultipleField(choices=select)) else: setattr( ProceduralForm, prop_name, SelectMultipleField(choices=select, coerce=str)) elif schema_prop['type'] == 'list': # Create and empty multiselect field, which will be populated # with choices from the data it's being initialized with. setattr(ProceduralForm, prop_name, SelectMultipleField(choices=[])) elif 'allowed' in schema_prop: select = [] for option in schema_prop['allowed']: select.append((str(option), str(option))) setattr(ProceduralForm, prop_name, SelectField(choices=select)) elif schema_prop['type'] == 'datetime': if 'dateonly' in form_prop and form_prop['dateonly']: setattr(ProceduralForm, prop_name, DateField(prop_name, default=date.today())) else: setattr(ProceduralForm, prop_name, DateTimeField(prop_name, default=datetime.now())) elif schema_prop['type'] == 'integer': setattr(ProceduralForm, prop_name, IntegerField(prop_name)) elif schema_prop['type'] == 'boolean': setattr(ProceduralForm, prop_name, BooleanField(prop_name)) elif schema_prop['type'] == 'media': setattr(ProceduralForm, prop_name, FileField(prop_name)) elif 'maxlength' in schema_prop and schema_prop['maxlength'] > 64: setattr(ProceduralForm, prop_name, TextAreaField(prop_name)) else: setattr(ProceduralForm, prop_name, TextField(prop_name)) build_form(node_schema, form_prop) return ProceduralForm()
def index(): """Custom files entry point """ rfiles = [] backend = app.config['STORAGE_BACKEND'] api = SystemUtility.attract_api() user = current_user.objectid node_picture = File() for file_ in request.files: filestorage = request.files[file_] # Save file on AttractWeb Storage picture_path = os.path.join(app.config['UPLOAD_DIR'], filestorage.filename) filestorage.save(picture_path) picture_file_file = open(picture_path, 'rb') if backend == 'pillar': hash_ = hashfile(picture_file_file, hashlib.md5()) name = "{0}{1}".format(hash_, os.path.splitext(picture_path)[1]) picture_file_file.close() file_check = node_picture.all({"where": "path=='{0}'".format(name)}, api=api) file_check = file_check['_items'] if len(file_check) == 0: prop = {} prop['name'] = filestorage.filename prop['description'] = "File {0}".format(filestorage.filename) prop['user'] = user prop['content_type'] = filestorage.content_type # TODO Fix length value prop['length'] = filestorage.content_length prop['md5'] = hash_ prop['filename'] = filestorage.filename prop['backend'] = backend if backend in ["pillar"]: prop['path'] = name node_picture.post(prop, api=api) prop['_id'] = node_picture['_id'] if backend == 'pillar': node_picture.post_file(picture_path, name, api=api) node_picture.build_previews(name, api=api) url = "{0}/file_storage/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], prop['path']) rfiles.append({ "id": prop['_id'], "name": prop['filename'], "size": prop['length'], "url": url, "thumbnailUrl": url, "deleteUrl": url, "deleteType": "DELETE" }) else: url = "{0}/file_storage/file/{1}".format( app.config['PILLAR_SERVER_ENDPOINT'], file_check[0]['path']) rfiles.append({ "id": file_check[0]['_id'], "name": file_check[0]['filename'], "size": file_check[0]['length'], "url": url, "thumbnailUrl": url, "deleteUrl": url, "deleteType": "DELETE" }) return jsonify(dict(files=rfiles))
def jstree_build_from_node(node): api = SystemUtility.attract_api() open_nodes = [jstree_parse_node(node)] # Get the current node again (with parent data) try: parent = Node.find(node.parent, { 'projection': '{"name": 1, "parent": 1, "node_type": 1}', 'embedded': '{"node_type":1}', }, api=api) except ResourceNotFound: parent = None except ForbiddenAccess: parent = None while (parent): open_nodes.append(jstree_parse_node(parent)) # If we have a parent if parent.parent: try: parent = Node.find(parent.parent, { 'projection': '{"name":1, "parent":1, "node_type": 1}', 'embedded': '{"node_type":1}', }, api=api) except ResourceNotFound: parent = None else: parent = None open_nodes.reverse() #open_nodes.pop(0) nodes_list = [] for node in jstree_get_children(open_nodes[0]['id']): # Nodes at the root of the project node_dict = { 'id': node['id'], 'text': node['text'], 'type': node['type'], 'children': True } if len(open_nodes) > 1: # Opening and selecting the tree nodes according to the landing place if node['id'] == open_nodes[1]['id']: current_dict = node_dict current_dict['state'] = {'opened': True} current_dict['children'] = jstree_get_children(node['id']) # Iterate on open_nodes until the end for n in open_nodes[2:]: for c in current_dict['children']: if n['id'] == c['id']: current_dict = c break current_dict['state'] = {'opened': True} current_dict['children'] = jstree_get_children(n['id']) # if landing_asset_id: # current_dict['children'] = aux_product_tree_node(open_nodes[-1]) # for asset in current_dict['children']: # if int(asset['id'][1:])==landing_asset_id: # asset.update(state=dict(selected=True)) nodes_list.append(node_dict) return nodes_list
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 process_node_form(form, node_id=None, node_type=None, user=None): """Generic function used to process new nodes, as well as edits """ if not user: print("User is None") return False api = SystemUtility.attract_api() node_schema = node_type['dyn_schema'].to_dict() form_schema = node_type['form_schema'].to_dict() if node_id: # Update existing node node = pillarsdk.Node.find(node_id, api=api) node.name = form.name.data node.description = form.description.data if 'picture' in form: node.picture = form.picture.data if node.picture == "None": node.picture = None if 'parent' in form: node.parent = form.parent.data def update_data(node_schema, form_schema, prefix=""): for pr in node_schema: schema_prop = node_schema[pr] form_prop = form_schema[pr] if pr == 'items': continue if 'visible' in form_prop and not form_prop['visible']: continue prop_name = "{0}{1}".format(prefix, pr) if schema_prop['type'] == 'dict': update_data(schema_prop['schema'], form_prop['schema'], "{0}__".format(prop_name)) continue data = form[prop_name].data if schema_prop['type'] == 'dict': if data == 'None': continue if schema_prop['type'] == 'integer': if data == '': data = 0 else: data = int(form[prop_name].data) if schema_prop['type'] == 'datetime': data = datetime.strftime(data, RFC1123_DATE_FORMAT) else: if pr in form: data = form[prop_name].data path = prop_name.split('__') if len(path) > 1: recursive_prop = recursive(path, node.properties.to_dict(), data) node.properties = recursive_prop else: node.properties[prop_name] = data update_data(node_schema, form_schema) # send_file(form, node, user) update = node.update(api=api) # if form.picture.data: # image_data = request.files[form.picture.name].read() # post = node.replace_picture(image_data, api=api) return update else: # Create a new node node = pillarsdk.Node() prop = {} files = {} prop['name'] = form.name.data prop['description'] = form.description.data prop['user'] = user if 'picture' in form: prop['picture'] = form.picture.data if prop['picture'] == 'None': prop['picture'] = None if 'parent' in form: prop['parent'] = form.parent.data prop['properties'] = {} def get_data(node_schema, form_schema, prefix=""): for pr in node_schema: schema_prop = node_schema[pr] form_prop = form_schema[pr] if pr == 'items': continue if 'visible' in form_prop and not form_prop['visible']: continue prop_name = "{0}{1}".format(prefix, pr) if schema_prop['type'] == 'dict': get_data(schema_prop['schema'], form_prop['schema'], "{0}__".format(prop_name)) continue data = form[prop_name].data if schema_prop['type'] == 'media': tmpfile = '/tmp/binary_data' data.save(tmpfile) binfile = open(tmpfile, 'rb') files[pr] = binfile continue if schema_prop['type'] == 'integer': if data == '': data = 0 if schema_prop['type'] == 'list': if data == '': data = [] if schema_prop['type'] == 'datetime': data = datetime.strftime(data, RFC1123_DATE_FORMAT) if schema_prop['type'] == 'objectid': if data == '': data = None path = prop_name.split('__') if len(path) > 1: prop['properties'] = recursive(path, prop['properties'], data) else: prop['properties'][prop_name] = data get_data(node_schema, form_schema) prop['node_type'] = form.node_type_id.data post = node.post(prop, api=api) return post