from contextlib import closing from os import mkdir from os import path from pathlib import Path from shutil import copytree from uuid import uuid1 from flask import abort from flask import make_response from flask import request from flask.views import View from pycs import app from pycs import db from pycs.database.LabelProvider import LabelProvider from pycs.database.Model import Model from pycs.database.Project import Project from pycs.frontend.endpoints.projects.ExecuteExternalStorage import ExecuteExternalStorage from pycs.frontend.endpoints.projects.ExecuteLabelProvider import ExecuteLabelProvider from pycs.frontend.notifications.NotificationManager import NotificationManager from pycs.jobs.JobRunner import JobRunner from pycs.util.PipelineUtil import load_from_root_folder as load_pipeline class CreateProject(View): """ create a project, insert data into database and create directories """ # pylint: disable=arguments-differ methods = ['POST'] @property def project_folder(self): return app.config["TEST_PROJECTS_DIR"] if app.config["TESTING"] else 'projects' def dispatch_request(self): # extract request data data = request.get_json(force=True) if None in [data.get('name'), data.get('description')]: return abort(400, "name and description information missing!") name = data['name'] description = data['description'] model_id = data['model'] label_provider_id = data['label'] data_folder = data['external'] external_data = data_folder is not None # find model model = Model.query.get(model_id) if model is None: return abort(404, "Model not found") # find label provider label_provider = None if label_provider_id is not None: label_provider = LabelProvider.query.get(label_provider_id) if label_provider is None: return abort(404, "Label provider not found") # create project folder project_folder = Path(self.project_folder, str(uuid1())) project_folder.mkdir(parents=True) temp_folder = project_folder / 'temp' temp_folder.mkdir() # check project data directory if external_data: # check if exists if not path.exists(data_folder): return abort(400, "Data folder does not exist!") else: data_folder = project_folder / 'data' data_folder.mkdir() # copy model to project folder model_folder = project_folder / 'model' copytree(model.root_folder, str(model_folder)) model, _ = model.copy_to(f'{model.name} ({name})', str(model_folder)) # create entry in database project = Project.new( name=name, description=description, model_id=model.id, label_provider_id=label_provider_id, root_folder=str(project_folder), external_data=external_data, data_folder=str(data_folder) ) # execute label provider and add labels to project if label_provider is not None: ExecuteLabelProvider.execute_label_provider(project, label_provider) root_folder = model.root_folder # load model and add collections to the project def load_model_and_get_collections(): with closing(load_pipeline(root_folder)) as pipeline: return pipeline.collections() project_id = project.id def add_collections_to_project(provided_collections): project = Project.query.get(project_id) with db.session.begin_nested(): for position, collection in enumerate(provided_collections): project.create_collection( collection['reference'], collection['name'], collection['description'], position + 1, collection['autoselect'], commit=False, ) JobRunner.run(project, 'Media Collections', f'{project.name}', f'{project.id}/media-collections', executable=load_model_and_get_collections, result=add_collections_to_project) # find media files if external_data: ExecuteExternalStorage.find_media_files(project) # fire event NotificationManager.created("model", model.id, Model) NotificationManager.created("project", project.id, Project) # return success response return make_response()