def test_create_tasks(self): shot = self.shot.serialize() shot_2 = self.generate_fixture_shot("S02").serialize() task_type = self.task_type.serialize() status = tasks_service.get_todo_status() tasks = tasks_service.create_tasks(task_type, [shot, shot_2]) self.assertEqual(len(tasks), 2) task = tasks[0] task = tasks_service.get_task(task["id"]) self.assertEqual(task["entity_id"], shot["id"]) self.assertEqual(task["task_type_id"], task_type["id"]) self.assertEqual(task["project_id"], shot["project_id"]) self.assertEqual(task["task_status_id"], status["id"])
def get(self, file_id): try: file_dict = files_service.get_working_file(file_id) task = tasks_service.get_task(file_dict["task_id"]) project_id = task["project_id"] except WorkingFileNotFoundException: file_dict = files_service.get_output_file(file_id) entity = entities_service.get_entity(file_dict["entity_id"]) project_id = entity["project_id"] if not permissions.has_manager_permissions(): user_service.check_has_task_related(project_id) return file_dict
def delete(self, task_id, comment_id): """ Delete a comment corresponding at given ID. """ comment = tasks_service.get_comment(comment_id) task = tasks_service.get_task(comment["object_id"]) user_service.check_manager_project_access(task["project_id"]) self.pre_delete(comment) deletion_service.remove_comment(comment_id) tasks_service.reset_task_data(comment["object_id"]) tasks_service.clear_comment_cache(comment_id) self.post_delete(comment) return "", 204
def post(self, task_id, comment_id, preview_file_id): task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) user_service.check_entity_access(task["entity_id"]) tasks_service.get_comment(comment_id) person = persons_service.get_current_user() related_preview_file = files_service.get_preview_file(preview_file_id) preview_file = tasks_service.add_preview_file_to_comment( comment_id, person["id"], task_id, related_preview_file["revision"]) return preview_file, 201
def delete_news_for_comment(comment_id): """ Delete all news related to comment. It's mandatory to be able to delete the comment afterwards. """ news_list = News.get_all_by(comment_id=comment_id) if len(news_list) > 0: task = tasks_service.get_task(news_list[0].task_id) for news in news_list: news.delete() events.emit("news:delete", {"news_id": news.id}, project_id=task["project_id"]) return fields.serialize_list(news_list)
def put(self): (task_ids) = self.get_arguments() if len(task_ids) > 0: task = tasks_service.get_task(task_ids[0]) user_service.check_manager_project_access(task["project_id"]) for task_id in task_ids: try: tasks_service.clear_assignation(task_id) except TaskNotFoundException: pass return task_ids
def post(self, task_id): (task_status_id, comment, person_id) = self.get_arguments() task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) task_status = tasks_service.get_task_status(task_status_id) if person_id: person = persons_service.get_person(person_id) else: person = persons_service.get_current_user() comment = tasks_service.create_comment(object_id=task_id, object_type="Task", task_status_id=task_status_id, person_id=person["id"], text=comment) status_changed = task_status_id != task["task_status_id"] new_data = { "task_status_id": task_status_id, "last_comment_date": comment["created_at"] } if status_changed: if task_status["is_retake"]: retake_count = task["retake_count"] if retake_count is None or retake_count == 'NoneType': retake_count = 0 new_data["retake_count"] = retake_count + 1 if task_status["is_done"]: new_data["end_date"] = datetime.datetime.now() else: new_data["end_date"] = None if task_status["short_name"] == "wip" \ and task["real_start_date"] is None: new_data["real_start_date"] = datetime.datetime.now() tasks_service.update_task(task_id, new_data) notifications_service.create_notifications_for_task_and_comment( task, comment, change=status_changed) news_service.create_news_for_task_and_comment(task, comment, change=status_changed) comment["task_status"] = task_status comment["person"] = person return comment, 201
def test_get_preview_files_for_artist(self): """ Test route data/preview-files for artist. Artists can only access previews linked to projects he works on. """ route = "data/preview-files" project1_id = str(self.project1.id) self.log_in_cg_artist() preview_files_artist = self.get(route) for preview_file in preview_files_artist: task = tasks_service.get_task(preview_file["task_id"]) self.assertEqual(task["project_id"], project1_id) self.assertEqual(len(preview_files_artist), 2)
def get(self, task_id): result = {} task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) options = request.args relations = options.get("relations", "false").lower() == "true" result = files_service.get_working_files_for_task( task["id"], relations=relations) return result
def test_has_task_related_team(self): self.log_in_cg_artist() self.generate_fixture_asset_type() self.generate_fixture_asset() self.generate_assigned_task() task_id = self.task.id project_id = self.project.id self.get("data/assets/%s" % self.asset.id, 403) self.task = tasks_service.get_task(task_id) projects_service.update_project(project_id, {"team": [self.user_cg_artist]}) self.project.save() self.get("data/assets/%s" % self.asset.id, 200)
def post(self, task_id): (task_status_id, comment, person_id) = self.get_arguments() tasks_service.get_task(task_id) if not permissions.has_manager_permissions(): user_service.check_assigned(task_id) task_status = tasks_service.get_task_status(task_status_id) if person_id: person = persons_service.get_person(person_id) else: person = persons_service.get_current_user() comment = tasks_service.create_comment(object_id=task_id, object_type="Task", task_status_id=task_status_id, person_id=person["id"], text=comment) tasks_service.update_task(task_id, {"task_status_id": task_status_id}) comment["task_status"] = task_status comment["person"] = person events.emit("comment:new", {"id": comment["id"]}) return comment, 201
def post_delete(self, comment): task = tasks_service.get_task(comment["object_id"]) self.new_task_status_id = task["task_status_id"] if self.previous_task_status_id != self.new_task_status_id: events.emit( "task:status-changed", { "task_id": task["id"], "new_task_status_id": self.new_task_status_id, "previous_task_status_id": self.previous_task_status_id }, project_id=task["project_id"] ) return comment
def new_comment( task_id, task_status_id, person_id, text, object_type="Task", files={}, checklist=[], created_at="", ): """ Create a new comment for given object (by default, it considers this object as a Task). """ created_at_date = None task = tasks_service.get_task(task_id) if created_at is not None and len(created_at) > 0: try: created_at_date = fields.get_date_object( created_at, date_format="%Y-%m-%d %H:%M:%S") except ValueError: pass comment = Comment.create( object_id=task_id, object_type=object_type, task_status_id=task_status_id, person_id=person_id, mentions=get_comment_mentions(task_id, text), checklist=checklist, text=text, created_at=created_at_date, ) comment = comment.serialize(relations=True) comment["attachment_files"] = [] for uploaded_file in files.values(): attachment_file = create_attachment(comment, uploaded_file) comment["attachment_files"].append(attachment_file) events.emit( "comment:new", { "comment_id": comment["id"], "task_id": task_id }, project_id=task["project_id"], ) return comment
def check_comment_access(comment_id): """ Return true if current user can have access to a comment. """ if permissions.has_admin_permissions(): return True else: comment = tasks_service.get_comment(comment_id) person_id = comment["person_id"] task_id = comment["object_id"] task = tasks_service.get_task(task_id) if task is None: tasks_service.clear_task_cache(task_id) task = tasks_service.get_task(task_id) check_project_access(task["project_id"]) check_entity_access(task["entity_id"]) if ( permissions.has_supervisor_permissions() or permissions.has_manager_permissions() ): return True elif permissions.has_client_permissions(): current_user = persons_service.get_current_user() project = projects_service.get_project(task["project_id"]) if project.get("is_clients_isolated", False): if not comment["person_id"] == current_user["id"]: raise permissions.PermissionDenied if persons_service.get_person(person_id)["role"] == "client": return True else: raise permissions.PermissionDenied elif persons_service.get_person(person_id)["role"] == "client": raise permissions.PermissionDenied return True
def put(self, task_id): (person_id) = self.get_arguments() try: task = tasks_service.get_task(task_id) user_service.check_manager_project_access(task["project_id"]) self.assign_task(task_id, person_id) notifications_service.create_assignation_notification( task_id, person_id) projects_service.add_team_member(task["project_id"], person_id) except PersonNotFoundException: return {"error": "Assignee doesn't exist in database."}, 400 return task
def post(self, task_id, date, person_id): args = self.get_arguments() try: task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) persons_service.get_person(person_id) time_spent = tasks_service.create_or_update_time_spent( task_id, person_id, date, args["duration"], add=True) return time_spent, 201 except ValueError: abort(404) except WrongDateFormatException: abort(404)
def test_get_preview_file_for_artist(self): """ Test route data/preview-files/<preview_file_id> for artist. Artists can only access previews linked to projects he works on. """ route1_1 = "data/preview-files/%s" % str(self.preview_file1_1.id) route2_1 = "data/preview-files/%s" % str(self.preview_file2_1.id) project1_id = str(self.project1.id) self.log_in_cg_artist() preview_file_artist1_1 = self.get(route1_1) task_related = tasks_service.get_task( preview_file_artist1_1["task_id"]) self.assertEqual(task_related["project_id"], project1_id) self.get(route2_1, code=403)
def get_preview_file_name(preview_file_id): """ Build unique and human readable file name for preview downloads. The convention followed is: [project_name]_[entity_name]_[task_type_name]_v[revivision].[extension]. """ preview_file = files_service.get_preview_file(preview_file_id) task = tasks_service.get_task(preview_file["task_id"]) task_type = tasks_service.get_task_type(task["task_type_id"]) project = projects_service.get_project(task["project_id"]) (entity_name, _) = get_full_entity_name(task["entity_id"]) name = "%s_%s_%s_v%s" % (project["name"], entity_name, task_type["name"], preview_file["revision"]) return "%s.%s" % (slugify.slugify( name, separator="_"), preview_file["extension"])
def delete(self, task_id, comment_id): """ Delete a comment corresponding at given ID. """ comment = tasks_service.get_comment(comment_id) task = tasks_service.get_task(comment["object_id"]) if permissions.has_manager_permissions(): user_service.check_project_access(task["project_id"]) else: user_service.check_working_on_entity(task["entity_id"]) self.pre_delete(comment) deletion_service.remove_comment(comment_id) tasks_service.reset_task_data(comment["object_id"]) tasks_service.clear_comment_cache(comment_id) self.post_delete(comment) return "", 204
def post(self, task_id): (task_status_id, comment, person_id, created_at, checklist) = self.get_arguments() task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) user_service.check_entity_access(task["entity_id"]) files = request.files if not permissions.has_manager_permissions(): person_id = None created_at = None comment = comments_service.create_comment(person_id, task_id, task_status_id, comment, checklist, files, created_at) return comment, 201
def test_get_task(self): self.assertRaises( TaskNotFoundException, tasks_service.get_task, "wrong-id" ) task = tasks_service.get_task(self.task_id) self.assertEqual(str(self.task_id), task["id"]) self.output_file.delete() self.working_file.delete() deletion_service.remove_task(task["id"]) self.assertRaises( TaskNotFoundException, tasks_service.get_task, str(self.task_id) )
def delete_reply(comment_id, reply_id): comment = tasks_service.get_comment_raw(comment_id) task = tasks_service.get_task(comment.object_id) if comment.replies is None: comment.replies = [] comment.replies = [ reply for reply in comment.replies if reply["id"] != reply_id ] comment.save() events.emit("comment:delete-reply", { "task_id": task["id"], "comment_id": str(comment.id), "reply_id": reply_id }, project_id=task["project_id"], persist=False) return comment.serialize()
def check_project_departement_access(task_id, person_id): """ Return true if current user is admin or is manager and is in team or is artist in the task department. """ user = persons_service.get_current_user(relations=True) task = tasks_service.get_task(task_id) task_type = tasks_service.get_task_type(task["task_type_id"]) is_allowed = (permissions.has_admin_permissions() or (permissions.has_manager_permissions() and check_belong_to_project(task["project_id"])) or (check_belong_to_project(task["project_id"]) and task_type["department_id"] in user["departments"] and person_id == user["id"])) if not is_allowed: raise permissions.PermissionDenied return is_allowed
def get(self, attachment_file_id): attachment_file = comments_service.get_attachment_file( attachment_file_id) comment = tasks_service.get_comment(attachment_file["comment_id"]) task = tasks_service.get_task(comment["object_id"]) user_service.check_project_access(task["project_id"]) file_path = comments_service.get_attachment_file_path(attachment_file) try: return flask_send_file( file_path, conditional=True, mimetype=attachment_file["mimetype"], as_attachment=False, attachment_filename=attachment_file["name"], ) except: abort(404)
def post(self, task_id): ( name, mode, software_id, comment, revision, separator, ) = self.get_arguments() try: task = tasks_service.get_task(task_id) user_service.check_project_access(task["project_id"]) user_service.check_entity_access(task["entity_id"]) software = files_service.get_software(software_id) is_revision_set_by_user = revision != 0 if not is_revision_set_by_user: revision = files_service.get_next_working_file_revision( task_id, name) file_path = file_tree_service.get_working_folder_path( task, mode=mode, software=software, name=name, sep=separator, revision=revision, ) file_name = file_tree_service.get_working_file_name( task, mode=mode, revision=revision, software=software, name=name, ) except MalformedFileTreeException as exception: return ( { "message": str(exception), "received_data": request.json }, 400, ) return {"path": file_path, "name": file_name}, 200
def create_notifications_for_task_and_comment(task, comment, change=False): """ For given task and comment, create a notification for every assignee to the task and to every person participating to this task. """ task = tasks_service.get_task(task["id"]) recipient_ids = get_notification_recipients(task) recipient_ids.remove(comment["person_id"]) author_id = comment["person_id"] for recipient_id in recipient_ids: try: notification = create_notification(recipient_id, comment_id=comment["id"], author_id=author_id, task_id=comment["object_id"], read=False, change=change, type="comment") emails_service.send_comment_notification(recipient_id, author_id, comment, task) events.emit("notification:new", { "notification_id": notification["id"], "person_id": recipient_id }, persist=False) except PersonNotFoundException: pass for recipient_id in comment["mentions"]: if recipient_id != comment["person_id"]: notification = create_notification(recipient_id, comment_id=comment["id"], author_id=comment["person_id"], task_id=comment["object_id"], type="mention") emails_service.send_mention_notification(recipient_id, author_id, comment, task) events.emit("notification:new", { "notification_id": notification["id"], "person_id": recipient_id }, persist=False) return recipient_ids
def generate_playlisted_shot_from_task(task_id): previews = {} task = tasks_service.get_task(task_id) shot = shots_service.get_shot(task["entity_id"]) sequence = shots_service.get_sequence(shot["parent_id"]) preview_files = get_preview_files_for_task(task_id) task_type_id = task["task_type_id"] shot["preview_file_task_id"] = task_id shot["sequence_id"] = sequence["id"] shot["sequence_name"] = sequence["name"] if len(preview_files) > 0: previews[task_type_id] = get_playlist_preview_file_list(preview_files) shot["preview_file_id"] = previews[task_type_id][0]["id"] shot["preview_file_extension"] = previews[task_type_id][0]["extension"] shot["preview_file_annotations"] = previews[task_type_id][0][ "annotations"] shot["preview_files"] = previews return shot
def build_row(self, shot): name, _ = names_service.get_full_entity_name(shot["entity_id"]) preview_file = files_service.get_preview_file(shot["preview_file_id"]) task = tasks_service.get_task(shot["preview_file_task_id"]) task_type = self.task_type_map[task["task_type_id"]] task_status = self.task_status_map[task["task_status_id"]] comment = self.task_comment_map.get(task["id"], {}) author = self.get_author(comment) date = self.get_date(comment) return [ name, task_type["name"], preview_file["revision"], task_status["name"], author, date, comment.get("text",""), ]
def post(self, task_id): ( name, mode, software_id, comment, revision, separator ) = self.get_arguments() try: task = tasks_service.get_task(task_id) if not permissions.has_manager_permissions(): user_service.check_has_task_related(task["project_id"]) software = files_service.get_software(software_id) is_revision_set_by_user = revision != 0 if not is_revision_set_by_user: revision = files_service.get_next_working_file_revision( task_id, name ) file_path = file_tree_service.get_working_folder_path( task, mode=mode, software=software, name=name, sep=separator ) file_name = file_tree_service.get_working_file_name( task, mode=mode, revision=revision, software=software, name=name ) except MalformedFileTreeException: return { "error": "Tree is not properly written, check modes and variables", "received_data": request.json, }, 400 return {"path": file_path, "name": file_name}, 200
def put(self, task_id): """ Assign given task list to given person. --- tags: - Tasks parameters: - in: path name: task_id required: True schema: type: UUID example: a24a6ea4-ce75-4665-a070-57453082c25 - in: body name: Person description: Person ID schema: type: object required: - person_id properties: person_id: type: UUID example: a24a6ea4-ce75-4665-a070-57453082c25 responses: 200: description: Given task assigned to given person 400: description: Assignee non-existent in database """ (person_id) = self.get_arguments() try: task = tasks_service.get_task(task_id) user_service.check_manager_project_access(task["project_id"]) self.assign_task(task_id, person_id) notifications_service.create_assignation_notification( task_id, person_id) projects_service.add_team_member(task["project_id"], person_id) except PersonNotFoundException: return {"error": "Assignee doesn't exist in database."}, 400 return task