def get(self, person_id): """ Retrieve desktop login logs. --- tags: - Persons description: Desktop login logs can only be created by current user. parameters: - in: path name: person_id required: True schema: type: UUID example: a24a6ea4-ce75-4665-a070-57453082c25 responses: 200: description: Desktop login logs """ current_user = persons_service.get_current_user() if ( current_user["id"] != person_id and not permissions.has_manager_permissions() ): raise permissions.PermissionDenied persons_service.get_person(person_id) return persons_service.get_desktop_login_logs(person_id)
def get(self, task_id): task = tasks_service.get_task(task_id) if not permissions.has_manager_permissions(): user_service.check_has_task_related(task["project_id"]) result = task task_type = tasks_service.get_task_type(task["task_type_id"]) result["task_type"] = task_type assigner = persons_service.get_person(task["assigner_id"]) result["assigner"] = assigner project = projects_service.get_project(task["project_id"]) result["project"] = project task_status = tasks_service.get_task_status(task["task_status_id"]) result["task_status"] = task_status entity = tasks_service.get_entity(task["entity_id"]) result["entity"] = entity if entity["parent_id"] is not None: sequence = shots_service.get_sequence(entity["parent_id"]) result["sequence"] = sequence if sequence["parent_id"] is not None: episode = shots_service.get_episode(sequence["parent_id"]) result["episode"] = episode entity_type = tasks_service.get_entity_type(entity["entity_type_id"]) result["entity_type"] = entity_type assignees = [] for assignee_id in task["assignees"]: assignees.append(persons_service.get_person(assignee_id)) result["persons"] = assignees result["type"] = "Task" return result, 200
def get(self, person_id): current_user = persons_service.get_current_user() if (current_user["id"] != person_id and not permissions.has_manager_permissions()): raise permissions.PermissionDenied persons_service.get_person(person_id) return persons_service.get_desktop_login_logs(person_id)
def post(self, task_id, date, person_id): """ Set time spent by a person on a task for a given day. --- tags: - Tasks parameters: - in: path name: task_id required: True schema: type: UUID example: a24a6ea4-ce75-4665-a070-57453082c25 - in: path name: date required: True schema: type: timestamp example: 2022-07-12 - in: path name: person_id required: True schema: type: UUID example: a24a6ea4-ce75-4665-a070-57453082c25 - in: body name: Duration schema: type: object properties: duration: type: integer responses: 201: description: Time spent by given person on given task for given day is set 404: description: Wrong date format """ args = 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"]) persons_service.get_person(person_id) time_spent = tasks_service.create_or_update_time_spent( task_id, person_id, datetime.datetime.strptime(date, "%Y-%m-%d"), args["duration"], ) return time_spent, 201 except ValueError: abort(404) except WrongDateFormatException: abort(404)
def post(self, task_id, date, person_id): args = self.get_arguments() try: if not permissions.has_manager_permissions(): user_service.check_assigned(task_id) tasks_service.get_task(task_id) persons_service.get_person(person_id) time_spent = tasks_service.create_or_update_time_spent( task_id, person_id, date, args["duration"]) return time_spent, 200 except WrongDateFormatException: abort(404)
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 post(self, asset_instance_id): args = self.get_arguments() try: revision = int(args["revision"]) try: working_file = files_service.get_working_file( args["working_file_id"] ) working_file_id = working_file["id"] except WorkingFileNotFoundException: pass asset_instance = assets_service.get_asset_instance( asset_instance_id ) entity = assets_service.get_asset(asset_instance["asset_id"]) if not permissions.has_manager_permissions(): user_service.check_has_task_related(entity["project_id"]) output_type = files_service.get_output_type(args["output_type_id"]) task_type = tasks_service.get_task_type(args["task_type_id"]) if args["person_id"] is None: person = persons_service.get_current_user() else: person = persons_service.get_person(args["person_id"]) output_file = files_service.create_new_output_revision( asset_instance["asset_id"], working_file_id, output_type["id"], person["id"], task_type["id"], asset_instance_id=asset_instance["id"], revision=revision, name=args["name"], representation=args["representation"], comment=args["comment"], extension=args["extension"] ) output_file_dict = self.add_path_info( output_file, "output", asset_instance, output_type, task_type=task_type, name=args["name"], extension=args["extension"], representation=args["representation"], separator=args["sep"] ) except OutputTypeNotFoundException: return {"message": "Cannot find given output type."}, 400 except PersonNotFoundException: return {"message": "Cannot find given person."}, 400 except EntryAlreadyExistsException: return {"message": "The given output file already exists."}, 400 return output_file_dict, 201
def on_identity_loaded(sender, identity): if identity.id is not None: from zou.app.services import persons_service try: identity.user = persons_service.get_person(identity.id) if hasattr(identity.user, "id"): identity.provides.add(UserNeed(identity.user["id"])) if identity.user["role"] == "admin": identity.provides.add(RoleNeed("admin")) identity.provides.add(RoleNeed("manager")) if identity.user["role"] == "manager": identity.provides.add(RoleNeed("manager")) return identity except PersonNotFoundException: return None except TimeoutError: current_app.logger.error("Identity loading timed out") return None except Exception as exception: current_app.logger.error(exception) if hasattr(exception, 'message'): current_app.logger.error(exception.message) return None
def send_comment_notification(person_id, author_id, comment, task): """ Send a notification emali telling that a new comment was posted to person matching given person id. """ person = persons_service.get_person(person_id) if (person["notifications_enabled"] or person["notifications_slack_enabled"]): task_status = tasks_service.get_task_status(task["task_status_id"]) task_status_name = task_status["short_name"].upper() (author, task_name, task_url) = get_task_descriptors(author_id, task) subject = "[Kitsu] %s - %s commented on %s" % ( task_status_name, author["first_name"], task_name, ) if len(comment["text"]) > 0: email_message = """<p><strong>%s</strong> wrote a comment on <a href="%s">%s</a> and set the status to <strong>%s</strong>.</p> <p><em>%s</em></p> """ % ( author["full_name"], task_url, task_name, task_status_name, comment["text"], ) slack_message = """*%s* wrote a comment on <%s|%s> and set the status to *%s*. _%s_ """ % ( author["full_name"], task_url, task_name, task_status_name, comment["text"], ) else: email_message = """<p><strong>%s</strong> changed status of <a href="%s">%s</a> to <strong>%s</strong>.</p> """ % ( author["full_name"], task_url, task_name, task_status_name, ) slack_message = """*%s* changed status of <%s|%s> to *%s*. """ % ( author["full_name"], task_url, task_name, task_status_name, ) messages = { "email_message": email_message, "slack_message": slack_message, } send_notification(person_id, subject, messages) return True
def send_notification(person_id, subject, messages): """ Send email notification to given person. Use the job queue if it is activated. """ person = persons_service.get_person(person_id) email_message = messages["email_message"] slack_message = messages["slack_message"] if person["notifications_enabled"]: if config.ENABLE_JOB_QUEUE: queue_store.job_queue.enqueue( emails.send_email, args=( subject, email_message + get_signature(), person["email"], ), ) else: emails.send_email(subject, email_message + get_signature(), person["email"]) if person["notifications_slack_enabled"]: organisation = persons_service.get_organisation() userid = person["notifications_slack_userid"] token = organisation.get("chat_token_slack", "") if config.ENABLE_JOB_QUEUE: queue_store.job_queue.enqueue(chats.send_to_slack, args=(token, userid, slack_message)) else: chats.send_to_slack(token, userid, slack_message) return True
def get_author(self, comment): author = "" person_id = comment.get("person_id", None) if person_id is not None: person = persons_service.get_person(person_id) author = person["full_name"] return author
def test_remove_from_department(self): person = self.person.serialize() department = self.department.serialize() persons_service.add_to_department(department["id"], person["id"]) persons_service.remove_from_department(department["id"], person["id"]) person = persons_service.get_person(person["id"]) self.assertEqual(len(person["departments"]), 0)
def put(self, task_id): (person_id, comment, working_file_id) = self.get_arguments() try: task = tasks_service.get_task(task_id) if not permissions.has_manager_permissions(): user_service.check_assigned(task_id) person = persons_service.get_person(person_id) preview_path = "" if working_file_id is not None: working_file = files_service.get_working_file(working_file_id) software = files_service.get_software( working_file["software_id"]) revision = working_file["revision"] preview_path = self.get_preview_path(task, working_file["name"], revision, software) task = tasks_service.task_to_review(task["id"], person, comment, preview_path) except PersonNotFoundException: return {"error": "Cannot find given person."}, 400 return task
def get_task_descriptors(person_id, task): """ Build task information needed to write notification emails: author object, full task name and task URL. """ author = persons_service.get_person(person_id) project = projects_service.get_project(task["project_id"]) task_type = tasks_service.get_task_type(task["task_type_id"]) entity = entities_service.get_entity(task["entity_id"]) (entity_name, episode_id) = names_service.get_full_entity_name(entity["id"]) episode_segment = "" entity_type = "assets" if task_type["for_shots"]: entity_type = "shots" if project["production_type"] == "tvshow": episode_segment = "/episodes/%s" % episode_id task_name = "%s / %s / %s" % ( project["name"], entity_name, task_type["name"], ) task_url = "%s://%s/productions/%s%s/%s/tasks/%s" % ( config.DOMAIN_PROTOCOL, config.DOMAIN_NAME, task["project_id"], episode_segment, entity_type, task["id"], ) return (author, task_name, task_url)
def send_assignation_notification(person_id, author_id, task): """ Send a notification email telling that somenone assigned to a task the person matching given person id. """ person = persons_service.get_person(person_id) if (person["notifications_enabled"] or person["notifications_slack_enabled"]): (author, task_name, task_url) = get_task_descriptors(author_id, task) subject = "[Kitsu] You were assigned to %s" % task_name email_message = """<p><strong>%s</strong> assigned you to <a href="%s">%s</a>.</p> """ % ( author["full_name"], task_url, task_name, ) slack_message = """*%s* assigned you to <%s|%s>. """ % ( author["full_name"], task_url, task_name, ) messages = { "email_message": email_message, "slack_message": slack_message, } return send_notification(person_id, subject, messages) return True
def post(self, task_id): (task_status_id, comment, person_id) = self.get_arguments() task = 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) status_changed = task_status_id != task["task_status_id"] tasks_service.update_task(task_id, {"task_status_id": task_status_id}) notifications_service.create_notifications_for_task_and_comment( task, comment, change=status_changed) comment["task_status"] = task_status comment["person"] = person events.emit("comment:new", {"id": comment["id"]}) return comment, 201
def put(self, task_id): ( person_id, comment, name, revision, change_status, ) = 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["project_id"]) if person_id is not None: person = persons_service.get_person(person_id) else: person = persons_service.get_current_user() preview_path = self.get_preview_path(task, name, revision) task = tasks_service.task_to_review(task["id"], person, comment, preview_path, change_status) except PersonNotFoundException: return {"error": True, "message": "Cannot find given person."}, 400 return task
def post(self, asset_instance_id, temporal_entity_id): args = self.get_arguments() try: revision = int(args["revision"]) try: working_file = files_service.get_working_file( args["working_file_id"]) working_file_id = working_file["id"] except WorkingFileNotFoundException: working_file_id = None asset_instance = assets_service.get_asset_instance( asset_instance_id) entity = assets_service.get_asset(asset_instance["asset_id"]) user_service.check_project_access(entity["project_id"]) output_type = files_service.get_output_type(args["output_type_id"]) task_type = tasks_service.get_task_type(args["task_type_id"]) if args["person_id"] is None: person = persons_service.get_current_user() else: person = persons_service.get_person(args["person_id"]) output_file_dict = files_service.create_new_output_revision( asset_instance["asset_id"], working_file_id, output_type["id"], person["id"], task_type["id"], asset_instance_id=asset_instance["id"], temporal_entity_id=temporal_entity_id, revision=revision, name=args["name"], path=args["path"], render_info=args["render_info"], representation=args["representation"], comment=args["comment"], nb_elements=int(args["nb_elements"]), extension=args["extension"], file_status_id=args['file_status_id'], ) if args["path"]: folder_path, file_name = os.path.split(args["path"]) output_file_dict.update({ "folder_path": folder_path, "file_name": file_name }) except OutputTypeNotFoundException: return {"message": "Cannot find given output type."}, 400 except PersonNotFoundException: return {"message": "Cannot find given person."}, 400 except EntryAlreadyExistsException: return {"message": "The given output file already exists."}, 400 return output_file_dict, 201
def post(self, entity_id): args = self.get_arguments() try: revision = int(args["revision"]) try: working_file = files_service.get_working_file( args["working_file_id"] ) working_file_id = working_file["id"] except WorkingFileNotFoundException: working_file_id = None entity = entities_service.get_entity(entity_id) user_service.check_project_access(entity["project_id"]) output_type = files_service.get_output_type(args["output_type_id"]) task_type = tasks_service.get_task_type(args["task_type_id"]) if args["person_id"] is None: person = persons_service.get_current_user() else: person = persons_service.get_person(args["person_id"]) output_file = files_service.create_new_output_revision( entity_id, working_file_id, output_type["id"], person["id"], args["task_type_id"], revision=revision, name=args["name"], comment=args["comment"], representation=args["representation"], extension=args["extension"], nb_elements=int(args["nb_elements"]), file_status_id=args['file_status_id'], ) output_file_dict = self.add_path_info( output_file, "output", entity, output_type, task_type=task_type, name=args["name"], extension=args["extension"], representation=args["representation"], separator=args["sep"], nb_elements=int(args["nb_elements"]), ) except OutputTypeNotFoundException: return {"error": "Cannot find given output type."}, 400 except PersonNotFoundException: return {"error": "Cannot find given person."}, 400 except EntryAlreadyExistsException: return {"error": "The given output file already exists."}, 400 return output_file_dict, 201
def test_get_person(self): self.assertRaises(PersonNotFoundException, persons_service.get_person, "wrong-id") person = persons_service.get_person(self.person_id) self.assertEqual(self.person_id, person["id"]) persons_service.delete_person(self.person_id) self.assertRaises(PersonNotFoundException, persons_service.get_person, self.person_id)
def send_mention_notification(person_id, author_id, comment, task): """ Send a notification email telling that somenone mentioned the person matching given person id. """ person = persons_service.get_person(person_id) project = projects_service.get_project(task["project_id"]) if (person["notifications_enabled"] or person["notifications_slack_enabled"] or person["notifications_mattermost_enabled"] or person["notifications_discord_enabled"]): (author, task_name, task_url) = get_task_descriptors(author_id, task) subject = "[Kitsu] %s mentioned you on %s" % ( author["first_name"], task_name, ) email_message = """<p><strong>%s</strong> mentioned you in a comment on <a href="%s">%s</a>:</p> <p><em>%s</em></p> """ % ( author["full_name"], task_url, task_name, comment["text"], ) slack_message = """*%s* mentioned you in a comment on <%s|%s>. _%s_ """ % ( author["full_name"], task_url, task_name, comment["text"], ) discord_message = """*%s* mentioned you in a comment on [%s](%s). _%s_ """ % ( author["full_name"], task_name, task_url, comment["text"], ) messages = { "email_message": email_message, "slack_message": slack_message, "mattermost_message": { "message": slack_message, "project_name": project["name"], }, "discord_message": discord_message, } return send_notification(person_id, subject, messages) else: return True
def send_reply_notification(person_id, author_id, comment, task, reply): """ Send a notification email telling that a new reply was posted to person matching given person id. """ person = persons_service.get_person(person_id) if (person["notifications_enabled"] or person["notifications_slack_enabled"]): task_status = tasks_service.get_task_status(task["task_status_id"]) project = projects_service.get_project(task["project_id"]) (author, task_name, task_url) = get_task_descriptors(author_id, task) subject = "[Kitsu] %s replied on %s" % ( author["first_name"], task_name, ) email_message = """<p><strong>%s</strong> wrote a reply on <a href="%s">%s</a>.</p> <p><em>%s</em></p> """ % ( author["full_name"], task_url, task_name, reply["text"], ) slack_message = """*%s* wrote a reply on <%s|%s>. _%s_ """ % ( author["full_name"], task_url, task_name, reply["text"], ) discord_message = """*%s* wrote a reply on [%s](%s). _%s_ """ % ( author["full_name"], task_name, task_url, reply["text"], ) messages = { "email_message": email_message, "slack_message": slack_message, "mattermost_message": { "message": slack_message, "project_name": project["name"], }, "discord_message": discord_message, } send_notification(person_id, subject, messages) return True
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) task = tasks_service.get_task_with_relations(task_id) 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 search_persons(query, limit=3): """ Perform a search on the index. The query is a simple string. The result is a list of persons (3 results maximum by default). """ index = get_person_index() persons = [] ids = indexing.search(index, query, limit=limit) for person_id in ids: person = persons_service.get_person(person_id) persons.append(person) return persons
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"]) user_service.check_entity_access(task["entity_id"]) persons_service.get_person(person_id) time_spent = tasks_service.create_or_update_time_spent( task_id, person_id, datetime.datetime.strptime(date, "%Y-%m-%d"), args["duration"], description=args.get("description"), validation_status_id=args.get("validation_status_id"), ) return time_spent, 201 except ValueError: abort(404) except WrongDateFormatException: abort(404)
def get_full_task(task_id): task = get_task_with_relations(task_id) task_type = get_task_type(task["task_type_id"]) project = projects_service.get_project(task["project_id"]) task_status = get_task_status(task["task_status_id"]) entity = entities_service.get_entity(task["entity_id"]) entity_type = entities_service.get_entity_type(entity["entity_type_id"]) assignees = [ persons_service.get_person(assignee_id) for assignee_id in task["assignees"] ] task.update({ "entity": entity, "task_type": task_type, "task_status": task_status, "project": project, "entity_type": entity_type, "persons": assignees, "type": "Task", }) try: assigner = persons_service.get_person(task["assigner_id"]) task["assigner"] = assigner except PersonNotFoundException: pass if entity["parent_id"] is not None: if entity_type["name"] == "Edit": episode_id = entity["parent_id"] else: sequence = shots_service.get_sequence(entity["parent_id"]) task["sequence"] = sequence episode_id = sequence["parent_id"] if episode_id is not None: episode = shots_service.get_episode(episode_id) task["episode"] = episode return task
def get(self, task_id): task = tasks_service.get_task(task_id) if not permissions.has_manager_permissions(): user_service.check_has_task_related(task["project_id"]) task_type = tasks_service.get_task_type(task["task_type_id"]) project = projects_service.get_project(task["project_id"]) task_status = tasks_service.get_task_status(task["task_status_id"]) entity = entities_service.get_entity(task["entity_id"]) entity_type = entities_service.get_entity_type( entity["entity_type_id"]) assignees = [] for assignee_id in task["assignees"]: assignees.append(persons_service.get_person(assignee_id)) task.update({ "entity": entity, "task_type": task_type, "task_status": task_status, "project": project, "entity_type": entity_type, "persons": assignees, "type": "Task" }) try: assigner = persons_service.get_person(task["assigner_id"]) task["assigner"] = assigner except PersonNotFoundException: pass if entity["parent_id"] is not None: sequence = shots_service.get_sequence(entity["parent_id"]) task["sequence"] = sequence if sequence["parent_id"] is not None: episode = shots_service.get_episode(sequence["parent_id"]) task["episode"] = episode return task, 200
def clean_get_result(self, result): if permissions.has_client_permissions(): person = persons_service.get_person(result["person_id"]) if person["role"] != "client": result["text"] = "" result["attachment_files"] = [] result["checklist"] = [] attachment_files = [] if ("attachment_files" in result and len(result["attachment_files"]) > 0): for attachment_file_id in result["attachment_files"]: attachment_file = AttachmentFile.get(attachment_file_id) attachment_files.append(attachment_file.present()) result["attachment_files"] = attachment_files return result
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 on_identity_loaded(sender, identity): if identity.id is not None: from zou.app.services import persons_service try: identity.user = persons_service.get_person(identity.id) if hasattr(identity.user, "id"): identity.provides.add(UserNeed(identity.user["id"])) if identity.user is None: raise PersonNotFoundException if identity.user["role"] == "admin": identity.provides.add(RoleNeed("admin")) identity.provides.add(RoleNeed("manager")) if identity.user["role"] == "manager": identity.provides.add(RoleNeed("manager")) if identity.user["role"] == "supervisor": identity.provides.add(RoleNeed("supervisor")) if identity.user["role"] == "client": identity.provides.add(RoleNeed("client")) if identity.user["role"] == "vendor": identity.provides.add(RoleNeed("vendor")) if not identity.user["active"]: current_app.logger.error("Current user is not active anymore") logout() return wrong_auth_handler(identity.user) return identity except PersonNotFoundException: return wrong_auth_handler() except TimeoutError: current_app.logger.error("Identity loading timed out") return wrong_auth_handler() except Exception as exception: current_app.logger.error(exception, exc_info=1) if hasattr(exception, "message"): current_app.logger.error(exception.message) return wrong_auth_handler()