Beispiel #1
0
def write_json_response(data: Dict[str, str],
                        response: QgsServerResponse,
                        code: int = 200) -> None:
    """ Write data as JSON response. """
    response.setStatusCode(code)
    response.setHeader("Content-Type", "application/json")
    response.write(json.dumps(data))
Beispiel #2
0
    def get_pdf(self, params: Dict[str, str],
                response: QgsServerResponse) -> None:
        """ Get PDF files previously exported
        """
        ptoken = params.get('TOKEN')
        if not ptoken:
            raise CadastreError(400, "Missing parameter: token")

        path = self.cachedir / ('%s.pdf' % ptoken)

        if self.debugMode:
            QgsMessageLog.logMessage("GetPDF = path is %s" % path.as_posix(),
                                     'cadastre', Qgis.Debug)

        if not path.exists():
            raise CadastreError(404, "PDF not found")

        # Send PDF
        response.setHeader('Content-type', 'application/pdf')
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except:
            QgsMessageLog.logMessage("Error occured while reading PDF file",
                                     'cadastre', Qgis.Critical)
            raise
    def get_pdf(self, params: Dict[str,str], response: QgsServerResponse ) -> None:
        """ Get PDF files previously exported
        """
        ptoken = params.get('TOKEN')
        if not ptoken:
            raise CadastreError(400,"Missing parameter: token")

        path = self.cachedir / ('%s.pdf' % ptoken)

        if self.debugMode:
            QgsMessageLog.logMessage("GetPDF = path is %s" % path.as_posix(),'cadastre', Qgis.Debug)

        if not path.exists():
            raise CadastreError(404,"PDF not found")

        # Send PDF
        response.setHeader('Content-type', 'application/pdf')
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except:
            QgsMessageLog.logMessage("Error occured while reading PDF file",'cadastre',QGis.Critical)
            raise
 def __init__(self):
     QgsServerResponse.__init__(self)
     self._buffer = QBuffer()
     self._buffer.open(QIODevice.ReadWrite)
Beispiel #5
0
 def __init__( self ):
     QgsServerResponse.__init__(self)
     self._buffer = QBuffer()
     self._buffer.open(QIODevice.ReadWrite)
    def virtualFields(params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None:
        """ Get virtual fields for features
        In parameters:
            LAYER=wms-layer-name
            VIRTUALS={"key1": "first expression", "key2": "second expression"}
            // optionals
            FILTER=An expression to filter layer
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        """
        layer_name = params.get('LAYER', '')
        if not layer_name:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = find_vector_layer(layer_name, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualFields': {} provided".format(layer_name),
                400)

        # get virtuals
        virtuals = params.get('VIRTUALS', '')
        if not virtuals:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS parameter is mandatory",
                400)

        # try to load virtuals dict
        try:
            vir_json = json.loads(virtuals)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads virtuals '{}' exception:\n{}".format(virtuals, traceback.format_exc()),
                "lizmap", Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed".format(virtuals),
                400)

        if not isinstance(vir_json, dict):
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'VirtualFields' REQUEST: VIRTUALS '{}' are not well formed".format(virtuals),
                400)

        # create expression context
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope(project))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))

        # create distance area context
        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs(), project.transformContext())
        da.setEllipsoid(project.ellipsoid())

        # parse virtuals
        exp_map = {}
        exp_parser_errors = []
        for k, e in vir_json.items():
            exp = QgsExpression(e)
            exp.setGeomCalculator(da)
            exp.setDistanceUnits(project.distanceUnits())
            exp.setAreaUnits(project.areaUnits())

            if exp.hasParserError():
                exp_parser_errors.append('Error "{}": {}'.format(e, exp.parserErrorString()))
                continue

            if not exp.isValid():
                exp_parser_errors.append('Expression not valid "{}"'.format(e))
                continue

            exp.prepare(exp_context)
            exp_map[k] = exp

        # expression parser errors found
        if exp_parser_errors:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid VIRTUALS for 'VirtualFields':\n{}".format('\n'.join(exp_parser_errors)),
                400)

        req = QgsFeatureRequest()

        # get filter
        req_filter = params.get('FILTER', '')
        if req_filter:
            req_exp = QgsExpression(req_filter)
            req_exp.setGeomCalculator(da)
            req_exp.setDistanceUnits(project.distanceUnits())
            req_exp.setAreaUnits(project.areaUnits())

            if req_exp.hasParserError():
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid FILTER for 'VirtualFields' Error \"{}\": {}".format(
                        req_filter, req_exp.parserErrorString()),
                    400)

            if not req_exp.isValid():
                raise ExpressionServiceError(
                    "Bad request error",
                    "Invalid FILTER for 'VirtualFields' Expression not valid \"{}\"".format(req_filter),
                    400)

            req_exp.prepare(exp_context)
            req = QgsFeatureRequest(req_exp, exp_context)

        # With geometry
        with_geom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't']
        if not with_geom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

        # Fields
        pk_attributes = layer.primaryKeyAttributes()
        attribute_list = [i for i in pk_attributes]
        fields = layer.fields()
        r_fields = [f.strip() for f in params.get('FIELDS', '').split(',') if f]
        for f in r_fields:
            attribute_list.append(fields.indexOf(f))

        # response
        response.setStatusCode(200)
        response.setHeader("Content-Type", "application/json")
        response.write('{ "type": "FeatureCollection","features":[')
        response.flush()

        json_exporter = QgsJsonExporter(layer)
        if attribute_list:
            json_exporter.setAttributes(attribute_list)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layer_name + '.' + get_server_fid(feat, pk_attributes)

            extra = {}

            # Update context
            exp_context.setFeature(feat)
            exp_context.setFields(feat.fields())

            # Evaluate expressions for virtual fields
            errors = {}
            for k, exp in exp_map.items():
                value = exp.evaluate(exp_context)
                if exp.hasEvalError():
                    extra[k] = None
                    errors[k] = exp.evalErrorString()
                else:
                    extra[k] = json.loads(QgsJsonUtils.encodeValue(value))
                    errors[k] = exp.expression()

            response.write(separator + json_exporter.exportFeature(feat, extra, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
    def get_feature_with_form_scope(params: Dict[str, str], response: QgsServerResponse, project: QgsProject) -> None:
        """ Get filtered features with a form scope
        In parameters:
            LAYER=wms-layer-name
            FILTER=An expression to filter layer
            FORM_FEATURE={"type": "Feature", "geometry": {}, "properties": {}}
            // optionals
            FIELDS=list of requested field separated by comma
            WITH_GEOMETRY=False
        """
        layer_name = params.get('LAYER', '')
        if not layer_name:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: LAYER parameter is mandatory",
                400)

        # get layer
        layer = find_vector_layer(layer_name, project)
        # layer not found
        if not layer:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid LAYER parameter for 'VirtualField': {} provided".format(layer_name),
                400)

        # get filter
        exp_filter = params.get('FILTER', '')
        if not exp_filter:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FILTER parameter is mandatory",
                400)

        # get form feature
        form_feature = params.get('FORM_FEATURE', '')
        if not form_feature:
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE parameter is mandatory",
                400)

        # Check features
        try:
            geojson = json.loads(form_feature)
        except Exception:
            QgsMessageLog.logMessage(
                "JSON loads form feature '{}' exception:\n{}".format(form_feature, traceback.format_exc()),
                "lizmap", Qgis.Critical)
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed".format(form_feature),
                400)

        if not geojson or not isinstance(geojson, dict):
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed".format(form_feature),
                400)

        if ('type' not in geojson) or geojson['type'] != 'Feature':
            raise ExpressionServiceError(
                "Bad request error",
                ("Invalid 'GetFeatureWithFormScope' REQUEST: FORM_FEATURE '{}' are not well formed: type not defined "
                 "or not Feature.").format(form_feature),
                400)

        # try to load form feature
        # read fields
        form_feature_fields = QgsJsonUtils.stringToFields(
            form_feature,
            QTextCodec.codecForName("UTF-8"))
        # read features
        form_feature_list = QgsJsonUtils.stringToFeatureList(
            form_feature,
            form_feature_fields,
            QTextCodec.codecForName("UTF-8"))

        # features not well formed
        if not form_feature_list:
            raise ExpressionServiceError(
                "Bad request error",
                ("Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n"
                 "{}").format(form_feature),
                400)

        if len(form_feature_list) != 1:
            raise ExpressionServiceError(
                "Bad request error",
                ("Invalid FORM_FEATURE for 'GetFeatureWithFormScope': not GeoJSON feature provided\n"
                 "{}").format(form_feature),
                400)

        # Get the form feature
        form_feat = form_feature_list[0]

        # create expression context
        exp_context = QgsExpressionContext()
        exp_context.appendScope(QgsExpressionContextUtils.globalScope())
        exp_context.appendScope(QgsExpressionContextUtils.projectScope(project))
        exp_context.appendScope(QgsExpressionContextUtils.layerScope(layer))
        exp_context.appendScope(QgsExpressionContextUtils.formScope(form_feat))

        # create distance area context
        da = QgsDistanceArea()
        da.setSourceCrs(layer.crs(), project.transformContext())
        da.setEllipsoid(project.ellipsoid())

        # Get filter expression
        exp_f = QgsExpression(exp_filter)
        exp_f.setGeomCalculator(da)
        exp_f.setDistanceUnits(project.distanceUnits())
        exp_f.setAreaUnits(project.areaUnits())

        if exp_f.hasParserError():
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FILTER for 'GetFeatureWithFormScope': Error \"{}\": {}".format(
                    exp_filter, exp_f.parserErrorString()),
                400)

        if not exp_f.isValid():
            raise ExpressionServiceError(
                "Bad request error",
                "Invalid FILTER for 'GetFeatureWithFormScope': Expression not valid \"{}\"".format(exp_filter),
                400)

        exp_f.prepare(exp_context)

        req = QgsFeatureRequest(exp_f, exp_context)

        # With geometry
        with_geom = params.get('WITH_GEOMETRY', '').lower() in ['true', '1', 't']
        if not with_geom:
            req.setFlags(QgsFeatureRequest.NoGeometry)

        # Fields
        pk_attributes = layer.primaryKeyAttributes()
        attribute_list = [i for i in pk_attributes]
        fields = layer.fields()
        r_fields = [f.strip() for f in params.get('FIELDS', '').split(',') if f]
        for f in r_fields:
            attribute_list.append(fields.indexOf(f))

        # response
        response.setStatusCode(200)
        response.setHeader("Content-Type", "application/json")
        response.write('{ "type": "FeatureCollection","features":[')
        response.flush()

        json_exporter = QgsJsonExporter(layer)
        if attribute_list:
            json_exporter.setAttributes(attribute_list)

        separator = ''
        for feat in layer.getFeatures(req):
            fid = layer_name + '.' + get_server_fid(feat, pk_attributes)
            response.write(separator + json_exporter.exportFeature(feat, {}, fid))
            response.flush()
            separator = ',\n'
        response.write(']}')
        return
Beispiel #8
0
 def formatResponse(self, response: QgsServerResponse) -> None:
     """ Format error response
     """
     body = {'status': 'fail', 'code': self.code, 'message': self.msg}
     response.clear()
     write_json_response(body, response, self.response_code)
Beispiel #9
0
    def get_print(self, params: Dict[str, str], response: QgsServerResponse,
                  project: QgsProject) -> None:
        """ Get print document
        """

        template = params.get('TEMPLATE')
        feature_filter = params.get('EXP_FILTER', None)
        scale = params.get('SCALE')
        scales = params.get('SCALES')

        try:
            if not template:
                raise AtlasPrintException('TEMPLATE is required')

            if feature_filter:
                expression = QgsExpression(feature_filter)
                if expression.hasParserError():
                    raise AtlasPrintException(
                        'Expression is invalid: {}'.format(
                            expression.parserErrorString()))

            if scale and scales:
                raise AtlasPrintException(
                    'SCALE and SCALES can not be used together.')

            if scale:
                try:
                    scale = int(scale)
                except ValueError:
                    raise AtlasPrintException('Invalid number in SCALE.')

            if scales:
                try:
                    scales = [int(scale) for scale in scales.split(',')]
                except ValueError:
                    raise AtlasPrintException('Invalid number in SCALES.')

            additional_params = {
                k: v
                for k, v in params.items()
                if k not in ['TEMPLATE', 'EXP_FILTER', 'SCALE', 'SCALES']
            }

            pdf_path = print_layout(project=project,
                                    layout_name=params['TEMPLATE'],
                                    scale=scale,
                                    scales=scales,
                                    feature_filter=feature_filter,
                                    **additional_params)
        except AtlasPrintException as e:
            raise AtlasPrintError(
                400,
                'ATLAS - Error from the user while generating the PDF: {}'.
                format(e))
        except Exception:
            self.logger.critical("Unhandled exception:\n{}".format(
                traceback.format_exc()))
            raise AtlasPrintError(500, "Internal 'atlasprint' service error")

        path = Path(pdf_path)
        if not path.exists():
            raise AtlasPrintError(404, "ATLAS PDF not found")

        # Send PDF
        response.setHeader('Content-Type', 'application/pdf')
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except Exception:
            self.logger.critical("Error occured while reading PDF file")
            raise
Beispiel #10
0
 def formatResponse(self, response: QgsServerResponse) -> None:
     """ Format error response
     """
     body = {"status": "fail", "message": self.msg}
     response.clear()
     write_json_response(body, response, self.code)
Beispiel #11
0
    def get_print(
        self, params: Dict[str, str], response: QgsServerResponse, project: QgsProject
    ) -> None:
        """ Get print document
        """

        template = params.get("TEMPLATE")
        feature_filter = params.get("EXP_FILTER", None)
        scale = params.get("SCALE")
        scales = params.get("SCALES")
        output_format = parse_output_format(params.get("FORMAT", params.get("format")))

        try:
            if not template:
                raise AtlasPrintException("TEMPLATE is required")

            if feature_filter:
                expression = QgsExpression(feature_filter)
                if expression.hasParserError():
                    raise AtlasPrintException(
                        "Expression is invalid: {}".format(
                            expression.parserErrorString()
                        )
                    )

            if scale and scales:
                raise AtlasPrintException("SCALE and SCALES can not be used together.")

            if scale:
                try:
                    scale = int(scale)
                except ValueError:
                    raise AtlasPrintException("Invalid number in SCALE.")

            if scales:
                try:
                    scales = [int(scale) for scale in scales.split(",")]
                except ValueError:
                    raise AtlasPrintException("Invalid number in SCALES.")

            additional_params = {
                k: v
                for k, v in params.items()
                if k
                not in (
                    "TEMPLATE",
                    "EXP_FILTER",
                    "SCALE",
                    "SCALES",
                    "FORMAT",
                    "MAP",
                    "REQUEST",
                    "SERVICE",
                )
            }
            Logger().info(
                "Additional params: " + str(additional_params["PERMIT_REQUEST_ID"])
            )
            # When the project has OAPIF datasources, the sources must first be reloaded.
            # In order to prevent massive request to DB, a basic server side filter is added
            OAPIFRefresher.refresh_geocity_oapif_layers_for_current_atlas_feature(
                additional_params["PERMIT_REQUEST_ID"]
            )
            Logger().info("Refreshed: " + str(additional_params["PERMIT_REQUEST_ID"]))

            output_path = print_layout(
                project=project,
                layout_name=params["TEMPLATE"],
                output_format=output_format,
                scale=scale,
                scales=scales,
                feature_filter=feature_filter,
                **additional_params,
            )
        except AtlasPrintException as e:
            raise AtlasPrintError(
                400,
                "ATLAS - Error from the user while generating the PDF: {}".format(e),
            )
        except Exception:
            self.logger.critical(
                "Unhandled exception:\n{}".format(traceback.format_exc())
            )
            raise AtlasPrintError(500, "Internal 'atlasprint' service error")

        path = Path(output_path)
        if not path.exists():
            raise AtlasPrintError(404, "ATLAS {} not found".format(output_format.name))

        # Send PDF
        response.setHeader("Content-Type", output_format.value)
        response.setStatusCode(200)
        try:
            response.write(path.read_bytes())
            path.unlink()
        except Exception:
            self.logger.critical(
                "Error occurred while reading {} file".format(output_format.name)
            )
            raise
 def formatResponse(self, response: QgsServerResponse) -> None:
     """ Format error response
     """
     body = { 'status': 'fail', 'message': self.msg }
     response.clear()
     write_json_response(body, response, self.code)
def write_json_response( data: Dict[str,str], response: QgsServerResponse, code: int=200) -> None:
    """ Write data as json response
    """
    response.setStatusCode(code)
    response.setHeader("Content-Type", "application/json")
    response.write(json.dumps(data))