Exemple #1
0
    def _execute(self, location_name, mapset_name, strds_name, timestamp):
        """Prepare and enqueue the raster area statistics

        Raises:
            InvalidUsage: In case the timestamp is wrong or the XML content is missing

        """
        # Check the time stamp
        try:
            datetime.strptime(timestamp, "%Y-%m-%dT%H:%M:%S")
        except ValueError as e:
            msg = "Wrong timestamp format. Required format is: " \
                  "YYYY-MM-DDTHH:MM:SS for example 2001-03-16T12:30:15"
            self.create_error_response(message=msg)
            return False

        rdc = self.preprocess(has_json=True,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=strds_name)
        if rdc:
            rdc.set_user_data(timestamp)
            enqueue_job(self.job_timeout, start_job, rdc)
            return True

        return False
    def _delete(self, location_name, mapset_name):
        """Remove a list of layers identified by a pattern

        The g.remove "pattern" parameters must be provided::

            http://<url>?pattern="*"

        Args:
            location_name (str): The name of the location
            mapset_name (str): The name of the mapset

        Return:
            flask.Response: HTTP 200 in case of success, HTTP 400 otherwise

        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        if rdc:
            args = glist_parser.parse_args()
            rdc.set_user_data((args, self.layer_type))
            enqueue_job(self.job_timeout, remove_raster_layers, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #3
0
    def post(self, location_name):
        """Create a new location based on EPSG code in the user database.
        """
        # Create only new locations if they did not exist in the global database
        location = os_path_normpath([self.grass_data_base, location_name])

        # Check the location path
        if os.path.isdir(location):
            return self.get_error_response(
                message="Unable to create location. "
                "Location <%s> exists in global database." % location_name)

        # Check also for the user database
        location = os_path_normpath(
            [self.grass_user_data_base, self.user_group, location_name])
        # Check the location path
        if os.path.isdir(location):
            return self.get_error_response(
                message="Unable to create location. "
                "Location <%s> exists in user database." % location_name)

        rdc = self.preprocess(has_json=True,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name="PERMANENT")
        if rdc:
            enqueue_job(self.job_timeout, create_location, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #4
0
    def post(self, executable):
        """Run a custom process

        The process is identified by executable

        Args:
            executable (str): Name of the executable

        Process arguments must be provided as JSON document in the POST request::

            ["arg_1", "arg_2", "arg_3", "arg_4", ...]

        Returns:
            flask.Response:
            The HTTP status and a JSON document that includes the
            status URL of the export task that must be polled for updates.

        """
        # Preprocess the post call
        rdc = self.preprocess(has_json=True)

        if rdc:
            rdc.set_user_data(executable)
            enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
Exemple #5
0
    def get(self, location_name, mapset_name, vector_name):
        """Render a single vector map layer
        """
        parser = self.create_parser()
        args = parser.parse_args()
        options = self.create_parser_options(args)

        if isinstance(options, dict) is False:
            return options

        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=vector_name)

        rdc.set_user_data(options)

        enqueue_job(self.job_timeout, start_job, rdc)

        http_code, response_model = self.wait_until_finish(0.05)
        if http_code == 200:
            result_file = response_model["process_results"]
            # Open the image file, read it and then delete it
            if result_file:
                if os.path.isfile(result_file):
                    image = open(result_file, "rb").read()
                    os.remove(result_file)
                    return Response(image, mimetype='image/png')

        return make_response(jsonify(response_model), http_code)
    def get(self, location_name, mapset_name):
        """Get the location/mapset lock status.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        enqueue_job(self.job_timeout, get_mapset_lock, rdc)
        http_code, response_model = self.wait_until_finish()
        return make_response(jsonify(response_model), http_code)
    def delete(self, location_name, mapset_name):
        """Delete a location/mapset lock.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        enqueue_job(self.job_timeout, unlock_mapset, rdc)
        http_code, response_model = self.wait_until_finish()
        return make_response(jsonify(response_model), http_code)
    def post(self, location_name, mapset_name):
        """Create a new mapset in an existing location.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        enqueue_job(self.job_timeout, create_mapset, rdc)
        http_code, response_model = self.wait_until_finish()
        return make_response(jsonify(response_model), http_code)
Exemple #9
0
    def post(self, location_name):
        """Execute a user defined process chain in an ephemeral location/mapset
        and store the processing result in an Google cloud storage bucket
        """
        rdc = self.preprocess(has_json=True, location_name=location_name)
        rdc.set_storage_model_to_gcs()

        enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
Exemple #10
0
    def delete(self):
        """Clean the download cache and remove all cached data"""
        rdc = self.preprocess(has_json=False, has_xml=False)

        if rdc:
            enqueue_job(self.job_timeout, start_download_cache_remove, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #11
0
    def _execute(self, location_name, mapset_name, strds_name):

        rdc = self.preprocess(has_json=True,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=strds_name)
        if rdc:
            enqueue_job(self.job_timeout, start_job, rdc)

        return rdc
    def get(self, location_name, mapset_name):
        """Get the current computational region of the mapset and the projection
        of the location as WKT string.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        enqueue_job(self.job_timeout, read_current_region, rdc)
        http_code, response_model = self.wait_until_finish()
        return make_response(jsonify(response_model), http_code)
Exemple #13
0
    def get(self):
        """Get the current size of the download cache"""
        rdc = self.preprocess(has_json=False, has_xml=False)

        if rdc:
            enqueue_job(self.job_timeout, start_download_cache_size, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def post(self, location_name, mapset_name, raster_name):
        """Create a new raster layer by uploading a GeoTIFF
        """

        allowed_extensions = ['tif', 'tiff']

        # TODO check if another content type can be used
        content_type = request.content_type.split(';')[0]
        if content_type != "multipart/form-data":
            return make_response(jsonify(SimpleResponseModel(
                status="error",
                message="Content type is not 'multipart/form-data'")), 400)

        if 'file' not in request.files:
            return make_response(jsonify(SimpleResponseModel(
                status="error",
                message="No file part indicated in postbody.")), 400)

        # create download cache path if does not exists
        if os.path.exists(self.download_cache):
            pass
        else:
            os.mkdir(self.download_cache)

        # save file from request
        id = str(uuid4())
        file = request.files['file']
        if file.filename == '':
            return make_response(jsonify(SimpleResponseModel(
                status="error",
                message="No selected file")), 400)
        if allowed_file(file.filename, allowed_extensions):
            name, extension = secure_filename(file.filename).rsplit('.', 1)
            filename = f"{name}_{id}.{extension}"
            file_path = os.path.join(self.download_cache, filename)
            file.save(file_path)
        else:
            os.remove(file_path)
            return make_response(jsonify(SimpleResponseModel(
                status="error",
                message="File has a not allowed extension. "
                        f"Please use {','.join(allowed_extensions)}.")), 400)

        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=raster_name)
        if rdc:
            rdc.set_request_data(file_path)
            enqueue_job(self.job_timeout, start_create_job, rdc)

        http_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), http_code)
    def get(self, location_name):
        """Get a list of all mapsets that are located in a specific location.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name="PERMANENT")
        if rdc:
            enqueue_job(self.job_timeout, list_raster_mapsets, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #16
0
    def _execute(self, location_name, mapset_name, raster_name,
                 use_raster_region):

        rdc = self.preprocess(has_json=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=raster_name)
        if rdc:
            rdc.set_user_data(use_raster_region)
            enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
    def delete(self, location_name, mapset_name, raster_name):
        """Delete an existing raster map layer.
        """
        rdc = self.preprocess(has_json=False, has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=raster_name)
        if rdc:
            enqueue_job(self.job_timeout, start_delete_job, rdc)
            http_code, response_model = self.wait_until_finish(0.1)
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #18
0
    def get(self, location_name):
        """Get the location projection and current computational region of the PERMANENT mapset
        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name="PERMANENT")
        if rdc:
            enqueue_job(self.job_timeout, read_current_region, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def post(self, location_name):
        """Validate a process chain asynchronously, check the provided sources
        and the mapsets."""

        rdc = self.preprocess(has_json=True,
                              has_xml=True,
                              location_name=location_name)

        if rdc:
            rdc.set_storage_model_to_file()
            enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
Exemple #20
0
    def get(self, location_name, mapset_name, strds_name):
        """Get information about a STRDS that is located in a specific location/mapset.
        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=strds_name)
        if rdc:
            enqueue_job(self.job_timeout, strds_info, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def _put(self, location_name, mapset_name):
        """Rename a list of layers

        The old names and new names must be provided as a
        list of tuples:

            [(a, a_new),(b, b_new),(c, c_new), ...]

        Args:
            location_name (str): The name of the location
            mapset_name (str): The name of the mapset

        Return:
            flask.Response: HTTP 200 in case of success, HTTP 400 otherwise

        """
        rdc = self.preprocess(has_json=True,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        # Analyse the name list
        if isinstance(self.request_data, list) is False:
            return self.get_error_response(
                message="Wrong format for layer list")

        if len(self.request_data) == 0:
            return self.get_error_response(message="Empty layer list")

        for name_tuple in self.request_data:
            if (isinstance(name_tuple, tuple) is False
                    and isinstance(name_tuple, list) is False):
                return self.get_error_response(
                    message="List entry is not a tuple or list")

            if len(name_tuple) != 2:
                return self.get_error_response(
                    message="A tuple of layer names must have 2 entries")

        if rdc:
            args = glist_parser.parse_args()
            rdc.set_user_data((args, self.layer_type))
            enqueue_job(self.job_timeout, rename_raster_layers, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #22
0
    def post(self, location_name, mapset_name, strds_name):
        """Create a new STRDS in a specific location/mapset.
        """
        rdc = self.preprocess(has_json=True,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=strds_name)

        if rdc:
            enqueue_job(self.job_timeout, strds_create, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def get(self, location_name, mapset_name, vector_name):
        """Get information about an existing vector map layer.
        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=vector_name)

        if rdc:
            enqueue_job(self.job_timeout, start_info_job, rdc)
            http_code, response_model = self.wait_until_finish(0.02)
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def get(self, location_name, mapset_name):
        """Render three raster map layer as composed RGB PNG image.
        """

        parser = self.create_parser()
        parser.add_argument(
            'red',
            required=True,
            type=str,
            help='The name of the raster layer associated with the color red')
        parser.add_argument(
            'green',
            required=True,
            type=str,
            help='The name of the raster layer associated with the color green'
        )
        parser.add_argument(
            'blue',
            required=True,
            type=str,
            help='The name of the raster layer associated with the color blue')

        args = parser.parse_args()
        rgb_options = self.extract_rgb_maps(args, mapset_name)

        if isinstance(rgb_options, dict) is False:
            return rgb_options

        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        rdc.set_user_data(rgb_options)

        enqueue_job(self.job_timeout, start_rgb_job, rdc)

        http_code, response_model = self.wait_until_finish(0.05)
        if http_code == 200:
            result_file = response_model["process_results"]
            # Open the image file, read it and then delete it
            if result_file:
                if os.path.isfile(result_file):
                    image = open(result_file, "rb").read()
                    os.remove(result_file)
                    return Response(image, mimetype='image/png')
        return make_response(jsonify(response_model), http_code)
    def _get(self, location_name, mapset_name):
        """Return a collection of all available layers
        in the provided mapset.

        Optionally can g.list parameters be provided::

            http://<url>?pattern="*"

        Args:
            location_name (str): The name of the location
            mapset_name (str): The name of the mapset

        Return:
            flask.Response: HTTP 200 and a list of layers as JSON document in
                            case of success, HTTP 400 otherwise

        Example::

            {"Process result":
              [ "lsat7_2002_10",
                "lsat7_2002_20",
                "lsat7_2002_30",
                "lsat7_2002_40",
                "lsat7_2002_50",
                "lsat7_2002_61",
                "lsat7_2002_62",
                "lsat7_2002_70",
                "lsat7_2002_80"
              ],
              "Status": "success"
            }

        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        if rdc:
            args = glist_parser.parse_args()
            rdc.set_user_data((args, self.layer_type))
            enqueue_job(self.job_timeout, list_raster_layers, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #26
0
    def post(self, location_name, mapset_name):
        """Merge several existing mapsets into a single one.
        All mapsets that should be merged and the target mapset will be locked
        for the processing.

        Args:
            location_name (str): The name of the location
            target_mapset_name (str): The name of the target mapset, into other
                                      mapsets should be merged

        Process arguments must be provided as JSON document in the POST request::

            ["mapset_A", "mapset_B", "mapset_C", "mapset_D", ...]

        Returns:
            flask.Response:
            The HTTP status and a JSON document that includes the
            status URL of the task that must be polled for updates.

        Example::

            {
              "HTTP code": 200,
              "Messages": "Resource accepted",
              "Resource id": "resource_id-985164c9-1db9-49cf-b2c4-3e8e48500e31",
              "Status": "accepted",
              "URLs": {
                "Resources": [],
                "Status": "http://104.155.60.87/resources/soeren/"
                          "resource_id-985164c9-1db9-49cf-b2c4-3e8e48500e31"
              },
              "User id": "soeren"
            }


        """
        # Preprocess the post call
        rdc = self.preprocess(
            has_json=True, location_name=location_name, mapset_name=mapset_name)

        if rdc:
            enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
Exemple #27
0
    def get(self, location_name, mapset_name):
        """Get a list of all STRDS that are located in a specific location/mapset.
        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name)

        if rdc:
            args = where_parser.parse_args()
            rdc.set_user_data(args)

            enqueue_job(self.job_timeout, list_raster_mapsets, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
Exemple #28
0
    def delete(self, location_name, mapset_name, strds_name):
        """Delete a STRDS that is located in a specific location/mapset.
        """
        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=strds_name)

        if rdc:
            args = recursive_parser.parse_args()
            rdc.set_user_data(args)

            enqueue_job(self.job_timeout, strds_delete, rdc)
            http_code, response_model = self.wait_until_finish()
        else:
            http_code, response_model = pickle.loads(self.response_data)

        return make_response(jsonify(response_model), http_code)
    def post(self, location_name, mapset_name):
        """Execute a user defined process chain that creates a new mapset or
        runs in an existing one.

        The process chain that describes the GRASS modules that should be
        executed must be provided as JSON payload of the POST request.

        Args:
            location_name (str): The name of the location
            mapset_name (str): The name of the mapset

        Returns:
            flask.Response:
            The HTTP status and a JSON document that includes the
            status URL of the task that must be polled for updates.

        Process chain input format:

            {                                           # A process chain is a
                                                          dict with entries for
                                                          each module that should
                                                          be run
               Id:{                                     # Id must be numerical
                                                          and indicates the process
                                                          order
                    "module": <module_name>,            # Name of the module to run
                    "stdin":  <Id::stdout | Id::stderr> # Use the output of a
                                                          specific module as
                                                          input for this module
                                                        # Id:stdout, Id:stderr
                                                          are available
                    "inputs ":{                         # Definition of all input
                                                          parameters as key:value
                                                          pairs
                              <parameter name>:<value>, # e.g.: value ==
                                                          "raster_name@mapset_name"
                                                          or "degree" or 0.0
                              <parameter name>:<value>  # e.g.: value ==
                                                          $file::slope_output_file
                                                          to specify an output file
                                                        # that name will be
                                                          automatically generated
                                                          by the API.
                    },
                    "outputs": {                         # Definition of all
                                                           outputs using key:value
                                                           pairs
                        <parameter name>: {
                            "name":<value>,              # Output name e.g.
                                                           "my_aspect_map" or a
                                                           temporary file id
                                                         # definition: $file::id
                                                           eg: $file::aspect_output_file
                                                         # This file can be used
                                                           in other module as input
                            "export": {                  # Export options, if present
                                                           this map will be exported
                                "format": <value>        # Set the export format
                                                           raster=GeoTiff (default),
                                                           vector = shape (default)
                                "type": <output type>,   # Output type e.g.: raster,
                                                           vector, file, stds
                            }
                        },
                        <parameter name>: {
                            "name": <value>,             # Output name e.g.
                                                           "my_slope_map"
                            "export": {                  # Export options, if
                                                           present this map will
                                                           be exported
                                "format": <value>        # Set the export format
                                                           raster=GeoTiff (default),
                                                           vector = shape (default)
                                "type": <output type>,   # Output type e.g.: raster,
                                                           vector, file, stds
                            }
                        }
                    },
                    "flags": <flags>,                    # All flags in a string
                                                           e.g.: "ge"
                    "overwrite": <True|False>,           # Set True to overwrite
                                                           existing data
                    "verbose": <True|False>              # Verbosity of the module
                },
               Id: {                                     # The id of an executable
                                                           command, that is not a
                                                           grass module
                    "executable": <path>,                # The name and path of
                                                           the executable e.g. /bin/cp
                    "stdin": <Id::stdout | Id::stderr>   # Use the output of a
                                                           specific module as
                                                           input for this module
                                                         # Id::stdout, Id::stderr
                                                           are available
                    "parameters": [<parameter>,]         # A list of strings that
                                                           represent the parameters
                                                           that may contain
                                                         # temporary file definitions:
                                                           $file::id  eg:
                                                           $file::aspect_output_file
               },
                ...
            }

        """
        # Preprocess the post call
        rdc = self.preprocess(
            has_json=True, location_name=location_name, mapset_name=mapset_name)

        if rdc:
            enqueue_job(self.job_timeout, start_job, rdc)

        html_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), html_code)
    def post(self, location_name, mapset_name, vector_name):
        """Create a new vector layer by uploading a GPKG, zipped Shapefile,
        or GeoJSON.
        """

        allowed_extensions = ['gpkg', 'zip', 'json', 'geojson']

        # TODO check if another content type can be used
        content_type = request.content_type.split(';')[0]
        if content_type != "multipart/form-data":
            return make_response(
                jsonify(
                    SimpleResponseModel(
                        status="error",
                        message="Content type is not 'multipart/form-data'")),
                400)

        if 'file' not in request.files:
            return make_response(
                jsonify(
                    SimpleResponseModel(
                        status="error",
                        message="No file part indicated in postbody.")), 400)

        # create download cache path if it does not exist
        if os.path.exists(self.download_cache):
            pass
        else:
            os.mkdir(self.download_cache)

        # save file from request
        id = str(uuid4())
        file = request.files['file']
        if file.filename == '':
            return make_response(
                jsonify(
                    SimpleResponseModel(status="error",
                                        message="No selected file")), 400)

        if allowed_file(file.filename, allowed_extensions):
            name, extension = secure_filename(file.filename).rsplit('.', 1)
            filename = f"{name}_{id}.{extension}"
            file_path = os.path.join(self.download_cache, filename)
            file.save(file_path)
        else:
            os.remove(file_path)
            return make_response(
                jsonify(
                    SimpleResponseModel(
                        status="error",
                        message="File has a not allowed extension. "
                        f"Please use {','.join(allowed_extensions)}.")), 400)

        # Shapefile upload as zip
        if extension == 'zip':
            unzip_folder = os.path.join(self.download_cache, f'unzip_{id}')
            with ZipFile(file_path, "r") as zip_ref:
                zip_ref.extractall(unzip_folder)
            shp_files = [
                entry for entry in os.listdir(unzip_folder)
                if entry.endswith('.shp')
            ]
            if len(shp_files) == 0:
                return make_response(
                    jsonify(
                        SimpleResponseModel(
                            status="error",
                            message="No .shp file found in zip file.")), 400)
            elif len(shp_files) > 1:
                return make_response(
                    jsonify(
                        SimpleResponseModel(
                            status="error",
                            message=
                            f"{len(shp_files)} .shp files found in zip file."
                            "Please put only one in the zip file.")), 400)
            else:
                os.remove(file_path)
                file_path = os.path.join(unzip_folder, shp_files[0])

        rdc = self.preprocess(has_json=False,
                              has_xml=False,
                              location_name=location_name,
                              mapset_name=mapset_name,
                              map_name=vector_name)
        if rdc:
            rdc.set_request_data(file_path)
            enqueue_job(self.job_timeout, start_create_job, rdc)

        http_code, response_model = pickle.loads(self.response_data)
        return make_response(jsonify(response_model), http_code)