def test_import_asset(self): self.generate_fixture_asset_type() self.generate_fixture_project_status() self.generate_fixture_project() self.generate_fixture_sequence() self.generate_fixture_shot() self.shot.update({"shotgun_id": 3}) self.load_fixture("projects") self.load_fixture("assets") sg_asset = { "code": "Cake", "description": "yellow cake", "project": { "type": "Project", "id": 1, "name": "Agent 327" }, "sg_asset_type": "Props", "type": "Asset", "parents": [{ "type": "Asset", "id": 1 }], "id": 3, } api_path = "/import/shotgun/assets" self.assets = self.post(api_path, [sg_asset], 200) self.assertEqual(len(self.assets), 1) self.assets = self.get("data/assets/all") self.assertEqual(len(self.assets), 3) assets = sorted(self.assets, key=lambda x: x["name"]) asset = assets[0] asset = assets_service.get_asset_with_relations(asset["id"]) project = Project.get_by(shotgun_id=sg_asset["project"]["id"]) self.assertEqual(asset["description"], sg_asset["description"]) self.assertEqual(asset["shotgun_id"], sg_asset["id"]) self.assertEqual(asset["project_id"], str(project.id)) self.assertEqual(len(asset["entities_out"]), 0) parent = Entity.get_by(shotgun_id=1) self.assertEqual(str(parent.entities_out[0].id), asset["id"])
def task_to_review( task_id, person, comment, preview_path={}, change_status=True ): """ Change the task status to "waiting for approval" if it is not already the case. It emits a *task:to-review* event. """ task = get_task_raw(task_id) to_review_status = get_to_review_status() task_dict_before = task.serialize() if change_status: task.update({"task_status_id": to_review_status["id"]}) task.save() project = Project.get(task.project_id) entity = Entity.get(task.entity_id) entity_type = EntityType.get(entity.entity_type_id) task_dict_after = task.serialize() task_dict_after["project"] = project.serialize() task_dict_after["entity"] = entity.serialize() task_dict_after["entity_type"] = entity_type.serialize() task_dict_after["person"] = person task_dict_after["comment"] = comment task_dict_after["preview_path"] = preview_path events.emit("task:to-review", { "task_id": task_id, "task_shotgun_id": task_dict_before["shotgun_id"], "entity_type_name": entity_type.name, "previous_task_status_id": task_dict_before["task_status_id"], "entity_shotgun_id": entity.shotgun_id, "project_shotgun_id": project.shotgun_id, "person_shotgun_id": person["shotgun_id"], "comment": comment, "preview_path": preview_path, "change_status": change_status }) return task_dict_after
def test_remove_asset_with_working_files(self): self.load_fixture("projects") self.load_fixture("assets") sg_asset = { "code": "Cake", "description": "yellow cake", "project": { "type": "Project", "id": 1, "name": "Cosmos Landromat" }, "sg_asset_type": "Props", "type": "Asset", "parents": [], "id": 3, } api_path = "/import/shotgun/assets" self.assets = self.post(api_path, [sg_asset], 200) asset = self.assets[0] self.asset = Entity.get(asset["id"]) self.generate_fixture_project_status() self.generate_fixture_file_status() self.generate_fixture_person() self.generate_fixture_assigner() self.generate_fixture_software() self.generate_fixture_project() self.generate_fixture_department() self.generate_fixture_task_type() self.generate_fixture_task_status() self.generate_fixture_task() self.generate_fixture_working_file() self.assets = self.get("data/assets/all") self.assertEqual(len(self.assets), 3) api_path = "/import/shotgun/remove/asset" self.assets = self.post(api_path, {"id": sg_asset["id"]}, 200) self.assets = self.get("data/assets/all") self.assertEqual(len(self.assets), 3) asset = self.get("data/assets/%s" % asset["id"], 200) self.assertTrue(asset["canceled"])
def update_metadata_descriptor(metadata_descriptor_id, changes): """ Update metadata descriptor information for given id. """ descriptor = get_metadata_descriptor_raw(metadata_descriptor_id) entities = Entity.get_all_by(project_id=descriptor.project_id) if "name" in changes and len(changes["name"]) > 0: changes["field_name"] = slugify.slugify(changes["name"]) for entity in entities: metadata = fields.serialize_value(entity.data) or {} value = metadata.pop(descriptor.field_name, None) if value is not None: metadata[changes["field_name"]] = value entity.update({"data": metadata}) descriptor.update(changes) events.emit("metadata-descriptor:update", {"descriptor_id": str(descriptor.id)}) return descriptor.serialize()
def generate_fixture_scene( self, name="SC01", project_id=None, sequence_id=None ): if project_id is None: project_id = self.project.id if sequence_id is None: sequence_id = self.sequence.id self.scene = Entity.create( name=name, description="Description Scene 01", data={}, project_id=project_id, entity_type_id=self.scene_type.id, parent_id=self.sequence.id, ) return self.scene
def remove_metadata_descriptor(metadata_descriptor_id): """ Deletee metadata descriptor and related informations. """ descriptor = get_metadata_descriptor_raw(metadata_descriptor_id) entities = Entity.get_all_by(project_id=descriptor.project_id) for entity in entities: metadata = fields.serialize_value(entity.data) if metadata is not None: metadata.pop(descriptor.field_name, None) entity.update({"data": metadata}) try: descriptor.delete() except ObjectDeletedError: pass events.emit("metadata-descriptor:delete", {"descriptor_id": str(descriptor.id)}) return descriptor.serialize()
def get_entities_for_project(project_id, entity_type_id, obj_type="Entity", only_assigned=False): """ Retrieve all entities related to given project of which entity is entity type. """ from zou.app.services import user_service query = (Entity.query.filter( Entity.entity_type_id == entity_type_id).filter( Entity.project_id == project_id).order_by(Entity.name)) if only_assigned: query = query \ .outerjoin(Task) \ .filter(user_service.build_assignee_filter()) result = query.all() return Entity.serialize_list(result, obj_type=obj_type)
def import_entry(self, data): entity = None parent_shotgun_ids = data["parent_shotgun_ids"] del data["parent_shotgun_ids"] try: entity = self.save_entity(data) except IntegrityError: current_app.logger.error("Similar asset already exists " "or project is missing: %s" % data) if entity is not None: for parent_shotgun_id in parent_shotgun_ids: self.parent_map.setdefault(parent_shotgun_id, []) self.parent_map[parent_shotgun_id].append(Entity.get( entity.id)) return entity
def get_episode_raw(episode_id): """ Return given episode as an active record. """ episode_type = get_episode_type() if episode_type is None: episode_type = get_episode_type() try: episode = Entity.get_by( entity_type_id=episode_type["id"], id=episode_id ) except StatementError: raise EpisodeNotFoundException if episode is None: raise EpisodeNotFoundException return episode
def remove_sequence(sequence_id, force=False): """ Remove a sequence and all related shots. """ sequence = get_sequence_raw(sequence_id) if force: for shot in Entity.get_all_by(parent_id=sequence_id): remove_shot(shot.id, force=True) Subscription.delete_all_by(entity_id=sequence_id) ScheduleItem.delete_all_by(object_id=sequence_id) try: sequence.delete() except IntegrityError: raise ModelWithRelationsDeletionException( "Some data are still linked to this sequence." ) clear_sequence_cache(sequence_id) return sequence.serialize(obj_type="Sequence")
def get_project_sequences(project_id): shot_type = shots_service.get_shot_type() sequence_type = shots_service.get_sequence_type() Shot = aliased(Entity, name='shot') query = Entity.query \ .join(Shot, Shot.parent_id == Entity.id) \ .join(Task, Task.entity_id == Shot.id) \ .join(EntityType, EntityType.id == Entity.entity_type_id) \ .join(Project, Project.id == Entity.project_id) \ .join(ProjectStatus) \ .filter(Shot.entity_type_id == shot_type["id"]) \ .filter(Entity.entity_type_id == sequence_type["id"]) \ .filter(Project.id == project_id) \ .filter(assignee_filter()) \ .filter(open_project_filter()) return Entity.serialize_list(query.all(), obj_type="Sequence")
def get_or_create_sequence(project_id, episode_id, name): sequence_type = get_sequence_type() sequence = Entity.get_by(entity_type_id=sequence_type["id"], parent_id=episode_id, project_id=project_id, name=name) if sequence is None: sequence = Entity(entity_type_id=sequence_type["id"], parent_id=episode_id, project_id=project_id, name=name) sequence.save() return sequence.serialize()
def generate_fixture_sequence( self, name="S01", episode_id=None, project_id=None ): if episode_id is None and hasattr(self, "episode"): episode_id = self.episode.id if project_id is None: project_id = self.project.id self.sequence = Entity.create( name=name, project_id=project_id, entity_type_id=self.sequence_type.id, parent_id=episode_id ) return self.sequence
def create_asset(project_id, asset_type_id, name, description, data): """ Create a new asset from given parameters. """ project = projects_service.get_project_raw(project_id) asset_type = get_asset_type_raw(asset_type_id) asset = Entity.create(project_id=project_id, entity_type_id=asset_type_id, name=name, description=description, data=data) asset_dict = asset.serialize(obj_type="Asset") events.emit("asset:new", { "asset": asset.id, "asset_type": asset_type.id, "project_id": project.id }) return asset_dict
def remove_task(task_id, force=False): """ Remove given task. Force deletion if the task has some comments and files related. This will lead to the deletion of all of them. """ task = Task.get(task_id) entity = Entity.get(task.entity_id) if force: working_files = WorkingFile.query.filter_by(task_id=task_id) for working_file in working_files: output_files = OutputFile.query.filter_by( source_file_id=working_file.id) for output_file in output_files: output_file.delete() working_file.delete() comments = Comment.query.filter_by(object_id=task_id) for comment in comments: notifications = Notification.query.filter_by(comment_id=comment.id) for notification in notifications: notification.delete() comment.delete() subscriptions = Subscription.query.filter_by(task_id=task_id) for subscription in subscriptions: subscription.delete() preview_files = PreviewFile.query.filter_by(task_id=task_id) for preview_file in preview_files: remove_preview_file(preview_file) time_spents = TimeSpent.query.filter_by(task_id=task_id) for time_spent in time_spents: time_spent.delete() notifications = Notification.query.filter_by(task_id=task_id) for notification in notifications: notification.delete() task.delete() events.emit("task:delete", {"task_id": task_id}) return task.serialize()
def guess_asset(project, asset_type_name, asset_name): asset_type_id = None if len(asset_type_name) > 0: asset_type = EntityType.get_by(name=asset_type_name) if asset_type is not None: asset_type_id = asset_type.id if len(asset_name) > 0: asset = Entity.get_by( name=asset_name, entity_type_id=asset_type_id, project_id=project["id"], ) else: raise WrongPathFormatException( "Asset name was not found in given path.") return asset
def update_entity_preview(entity_id, preview_file_id): """ Update given entity main preview. If entity or preview is not found, it raises an exception. """ entity = Entity.get(entity_id) if entity is None: raise EntityNotFoundException preview_file = PreviewFile.get(preview_file_id) if preview_file is None: raise PreviewFileNotFoundException entity.update({"preview_file_id": preview_file.id}) events.emit("preview-file:set-main", { "entity_id": entity_id, "preview_file_id": preview_file_id }) return entity.serialize()
def get_or_create_episode(project_id, name): """ Retrieve episode matching given project and name or create it. """ episode_type = get_episode_type() episode = Entity.get_by( entity_type_id=episode_type["id"], project_id=project_id, name=name ) if episode is None: episode = Entity( entity_type_id=episode_type["id"], project_id=project_id, name=name ) episode.save() return episode.serialize()
def test_import_scene(self): self.load_fixture("projects") self.load_fixture("sequences") api_path = "/import/shotgun/scenes" self.scenes = self.post(api_path, [self.sg_scene], 200) self.assertEqual(len(self.scenes), 1) self.scenes = self.get("data/scenes/all") self.assertEqual(len(self.scenes), 1) scene = self.scenes[0] sequence = Entity.get_by( shotgun_id=self.sg_scene["sequence_sg_scenes_1_sequences"][0]["id"], entity_type_id=shots_service.get_sequence_type()["id"] ) project = Project.get_by(name=self.sg_scene["project"]["name"]) self.assertEqual(scene["name"], self.sg_scene["code"]) self.assertEqual(scene["parent_id"], str(sequence.id)) self.assertEqual(scene["project_id"], str(project.id))
def save_entity(self, data): entity = None entities = asset_info.get_assets({"shotgun_id": data["shotgun_id"]}) if len(entities) > 0: entity = entities[0] if entity is None: entity = Entity(**data) entity.save() current_app.logger.info("Entity created: %s" % entity) else: entity.update(data) current_app.logger.info("Entity updated: %s" % entity) return entity
def remove_preview_file(preview_file): """ Remove all files related to given preview file, then remove the preview file entry from the database. """ task = Task.get(preview_file.task_id) entity = Entity.get(task.entity_id) if entity.preview_file_id == preview_file.id: entity.update({"preview_file_id": None}) if preview_file.extension == "png": clear_picture_files(preview_file.id) elif preview_file.extension == "mp4": clear_movie_files(preview_file.id) else: clear_generic_files(preview_file.id) preview_file.comments = [] preview_file.save() preview_file.delete() return preview_file.serialize()
def sync_entity_thumbnails(project, model_name): """ Once every preview files and entities has been imported, this function allows you to import project entities again to set thumbnails id (link to a preview file) for all entities. """ results = gazu.client.fetch_all("projects/%s/%s" % (project["id"], model_name)) total = 0 for result in results: if result.get("preview_file_id") is not None: entity = Entity.get(result["id"]) try: entity.update({ "preview_file_id": result["preview_file_id"], "updated_at": result["updated_at"], }) total += 1 except sqlalchemy.exc.IntegrityError: logger.error("An error occured", exc_info=1) logger.info(" %s %s thumbnails synced." % (total, model_name))
def post_processing(self): # We handle the fact that an asset can have multiple parents by using # the entities out field as a children field. for key in self.parent_map.keys(): try: asset = assets_service.get_asset_by_shotgun_id(key) asset = assets_service.get_full_asset(asset['id']) former_children = [ Entity.get(child_id) for child_id in asset.get('entities_out', []) ] children = list(set(self.parent_map[key] + former_children)) data = {"entities_out": children} assets_service.update_asset(asset["id"], data) assets_service.clear_asset_cache(asset["id"]) except AssetNotFoundException: pass return self.parent_map
def get_sequences_for_project(project_id): """ Return all sequences for given project and for which current user has a task assigned to a shot. """ shot_type = shots_service.get_shot_type() sequence_type = shots_service.get_sequence_type() Shot = aliased(Entity, name="shot") query = (Entity.query.join(Shot, Shot.parent_id == Entity.id).join( Task, Task.entity_id == Shot.id).join( EntityType, EntityType.id == Entity.entity_type_id).join( Project, Project.id == Entity.project_id).join(ProjectStatus).filter( Shot.entity_type_id == shot_type["id"]).filter( Entity.entity_type_id == sequence_type["id"]).filter( Project.id == project_id).filter( build_assignee_filter()).filter( build_open_project_filter())) return Entity.serialize_list(query.all(), obj_type="Sequence")
def get_or_create_sequence(project_id, episode_id, name): """ Retrieve sequence matching given project, episode and name or create it. """ sequence_type = get_sequence_type() sequence = Entity.get_by(entity_type_id=sequence_type["id"], parent_id=episode_id, project_id=project_id, name=name) if sequence is None: sequence = Entity(entity_type_id=sequence_type["id"], parent_id=episode_id, project_id=project_id, name=name) sequence.save() return sequence.serialize()
def setUp(self): super(FileTreeTestCase, self).setUp() self.generate_fixture_project_status() self.generate_fixture_project() self.generate_fixture_project_standard() self.generate_fixture_asset_type() self.generate_fixture_asset() self.generate_fixture_episode() self.generate_fixture_sequence() self.generate_fixture_shot() self.generate_fixture_scene() self.generate_fixture_sequence_standard() self.generate_fixture_shot_standard() self.generate_fixture_person() self.generate_fixture_department() self.generate_fixture_task_type() self.generate_fixture_task_status() self.generate_fixture_assigner() self.generate_fixture_task() self.generate_fixture_shot_task() self.generate_fixture_shot_task_standard() self.generate_fixture_software() self.asset_standard = Entity( name='Car', project_id=self.project_standard.id, entity_type_id=self.asset_type.id ) self.asset_standard.save() self.sequence_standard = Entity( name='Seq1', project_id=self.project.id, entity_type_id=self.sequence_type.id ) self.sequence_standard.save() self.shot_standard = Entity( name='P001', project_id=self.project_standard.id, entity_type_id=self.shot_type.id, parent_id=self.sequence_standard.id ) self.shot_standard.save() self.output_type_materials = files_service.get_or_create_output_type( "Materials") self.output_type_cache = files_service.get_or_create_output_type( "Cache") self.output_type_image = files_service.get_or_create_output_type( "Images")
def test_update_metadata_descriptor(self): asset = self.generate_fixture_asset_type() asset = self.generate_fixture_asset() descriptor = projects_service.add_metadata_descriptor( self.project.id, "Asset", "Contractor", [] ) asset.update({ "data": { "contractor": "contractor 1" } }) self.assertTrue("contractor" in asset.data) projects_service.update_metadata_descriptor( descriptor["id"], {"name": "Team"} ) descriptors = projects_service.get_metadata_descriptors(self.project.id) self.assertEqual(len(descriptors), 1) asset = Entity.get(asset.id) self.assertEqual(asset.data.get("team"), "contractor 1")
def test_add_delete_metadata_descriptor(self): asset = self.generate_fixture_asset_type() asset = self.generate_fixture_asset() descriptor = projects_service.add_metadata_descriptor( self.project.id, "Asset", "Contractor", [] ) asset.update({ "data": { "contractor": "contractor 1" } }) self.assertTrue("contractor" in asset.data) projects_service.remove_metadata_descriptor( descriptor["id"] ) descriptors = projects_service.get_metadata_descriptors(self.project.id) self.assertEqual(len(descriptors), 0) asset = Entity.get(asset.id) self.assertFalse("contractor" in asset.data)
def get(self, instance_id): try: task = task_info.get_task(instance_id) except TaskNotFoundException: abort(404) result = task.serialize() task_type = TaskType.get(task.task_type_id) result["task_type"] = task_type.serialize() assigner = Person.get(task.assigner_id) result["assigner"] = assigner.serialize() project = Project.get(task.project_id) result["project"] = project.serialize() task_status = TaskStatus.get(task.task_status_id) result["task_status"] = task_status.serialize() entity = Entity.get(task.entity_id) result["entity"] = entity.serialize() assignees = [] for assignee in task.assignees: assignees.append(assignee.serialize()) result["persons"] = assignees return result, 200
def test_set_main_preview(self): path = "/pictures/preview-files/%s" % self.preview_file_id file_path_fixture = self.get_fixture_file_path( os.path.join("thumbnails", "th01.png")) self.upload_file(path, file_path_fixture) path = \ "/actions/preview-files/%s/set-main-preview" % self.preview_file_id self.put(path, {}) asset = assets_service.get_asset(self.asset_id) self.assertEqual(asset["preview_file_id"], str(self.preview_file_id)) self.put( "/actions/entities/%s/set-main-preview/%s" % (self.preview_file_id, self.preview_file_id), {}, 404) self.put( "/actions/entities/%s/set-main-preview/%s" % (self.asset_id, self.asset_id), {}, 404) entity = Entity.get(self.asset_id) entity.preview_file_id = None entity.save()