def loadModel(self):
        imd = None
        try:
            loader = ModelLoader(self.ui.mDataLineEdit.text())
            models = loader.detect_models()
            model_names = map(lambda m: m.name, models)
            self._log_output("Looking up models: " + ', '.join(model_names))
            ili = loader.gen_lookup_ili()
            qDebug(ili)
            wpsreq = self._create_wps_request(ili)
            url = self.ui.mIlisMetaUrlLineEdit.text()
            req = QNetworkRequest(QUrl(url))
            req.setHeader(QNetworkRequest.ContentTypeHeader, 'application/xml')
            data = QByteArray()
            data.append(wpsreq)
            reply = QgsNetworkAccessManager.instance().blockingPost(req, data)

            if reply.error() == QNetworkReply.NoError:
                result = reply.content()
                imd = self._parse_wps_response(result)
        except Exception as e:
            qDebug("Exception during IlisModel download")
        if imd is None:
            self._show_log_window()
            QgsApplication.messageLog().logMessage(
                "Couldn't download Ilismeta model", "Interlis",
                Qgis.MessageLevel(1))
            self.ui.mModelLineEdit.setText("")
        else:
            fh, imdfn = tempfile.mkstemp(suffix='.imd')
            os.close(fh)
            with codecs.open(imdfn, "w", encoding='utf-8') as file:
                file.write(imd)
            self.ui.mModelLineEdit.setText(imdfn)
Ejemplo n.º 2
0
    def api_authentification(self):
        logger.debug("\n------------------ Authentication ------------------")

        # creating credentials header
        crd_header_value = QByteArray()
        crd_header_value.append("Basic ")
        crd_header_value.append(
            base64.b64encode("{}:{}".format(self.app_id, self.app_secrets).encode())
        )

        crd_header_name = QByteArray()
        crd_header_name.append("Authorization")

        # creating Content-Type header
        ct_header_value = QByteArray()
        ct_header_value.append("application/json")

        # creating request
        token_rqst = QNetworkRequest(QUrl(self.token_url))

        # setting headers
        token_rqst.setRawHeader(crd_header_name, crd_header_value)
        token_rqst.setHeader(token_rqst.ContentTypeHeader, ct_header_value)

        # creating data
        data = QByteArray()
        data.append(urlencode({"grant_type": "client_credentials"}))

        # requesting and handle reply
        logger.debug("Asking for token")
        token_reply = self.naMngr.post(token_rqst, data)
        token_reply.finished.connect(partial(self.api_handle_token, reply=token_reply))
Ejemplo n.º 3
0
 def prepare_request(self, url, content_type):
     url = self.get_url(url)
     req = QNetworkRequest(QUrl(url))
     req.setHeader(QNetworkRequest.ContentTypeHeader, content_type)
     req.setRawHeader(b'Accept', b'application/json')
     if self._token:
         req.setRawHeader(b'Authorization', self.str_to_byte_array(
             'Bearer {0}'.format(self._token)))
     return req
 def testPost(self):
     request = QgsBlockingNetworkRequest()
     spy = QSignalSpy(request.finished)
     handler = mockedwebserver.SequentialHandler()
     handler.add('POST', '/test.html', 200, expected_body=b"foo")
     with mockedwebserver.install_http_handler(handler):
         req = QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html'))
         req.setHeader(QNetworkRequest.ContentTypeHeader, 'text/plain')
         err = request.post(req, b"foo")
     self.assertEqual(err, QgsBlockingNetworkRequest.NoError)
     self.assertEqual(request.errorMessage(), '')
Ejemplo n.º 5
0
    def create_request(self, request_type: str):
        """Creates a QNetworkRequest() with appropriate headers and URL according to the
        'request_type' parameter.

        :param str request_type: type of request to create. Options:
            - 'token'
            - 'search'
            - 'details'
            - 'shares'

        :returns: the QNetworkRequest to send to the Isogeo's API

        :rtype: QNetworkRequest
        """
        # creating headers (same steps wathever request_type value)
        header_value = QByteArray()
        header_name = QByteArray()
        header_name.append("Authorization")
        # for token request
        if request_type == "token":
            # filling request header with credentials
            header_value.append("Basic ")
            header_value.append(
                base64.b64encode("{}:{}".format(self.app_id,
                                                self.app_secret).encode()))
            # creating the QNetworkRequest from oAuth2 authentication URL
            request = QNetworkRequest(QUrl(self.api_url_token))
            # creating and setting the 'Content-type header'
            ct_header_value = QByteArray()
            ct_header_value.append("application/json")
            request.setHeader(request.ContentTypeHeader, ct_header_value)
        # for other request_type, setting appropriate url
        else:
            if request_type == "shares":
                url = QUrl("{}/shares".format(self.api_url_base))
            elif request_type == "search" or request_type == "details":
                url = QUrl(self.currentUrl)
            else:
                logger.debug(
                    "Unkown request type asked : {}".format(request_type))
                raise ValueError
                return 0
            # filling request header with token
            header_value.append(self.token)
            request = QNetworkRequest(url)
        # creating QNetworkRequest from appropriate url
        request.setRawHeader(header_name, header_value)
        return request
    def fetchResults(self, search, context, feedback):

        if len(search) < 2:
            return

        # see https://operations.osmfoundation.org/policies/nominatim/
        # "Auto-complete search This is not yet supported by Nominatim and you must not implement such a service on the client side using the API."
        # so end with a space to trigger a search:
        if search[-1] != ' ':
            return

        url = '{}{}'.format(self.SEARCH_URL, search)
        self.info('Search url {}'.format(url))
        try:
            # see https://operations.osmfoundation.org/policies/nominatim/
            # "Pro4 vide a valid HTTP Referer or User-Agent identifying the application (QGIS geocoder)"
            # TODO
            #headers = {b'User-Agent': self.USER_AGENT}

            # nam = Network Access Manager
            nam = QgsBlockingNetworkRequest()
            request = QNetworkRequest(QUrl(url))
            request.setHeader(QNetworkRequest.UserAgentHeader, self.USER_AGENT)
            nam.get(request, forceRefresh=True)
            reply = nam.reply()
            if reply.attribute(
                    QNetworkRequest.HttpStatusCodeAttribute
            ) == 200:  # other codes are handled by NetworkAccessManager
                content_string = reply.content().data().decode('utf8')
                locations = json.loads(content_string)
                for loc in locations:
                    result = QgsLocatorResult()
                    result.filter = self
                    result.displayString = '{} ({})'.format(
                        loc['display_name'], loc['type'])
                    # use the json full item as userData, so all info is in it:
                    result.userData = loc
                    self.resultFetched.emit(result)

        except Exception as err:
            # Handle exception..
            # only this one seems to work
            self.info(err)
Ejemplo n.º 7
0
    def _post_sync(self,
                   qurl: QUrl,
                   timeout: int = 20000,
                   data: bytes = b'',
                   content_type=None):
        '''
        synchronous POST-request
        '''
        request = QNetworkRequest(qurl)
        if content_type:
            request.setHeader(QNetworkRequest.ContentTypeHeader, content_type)
        # newer versions of QGIS (3.6+) support synchronous requests
        if hasattr(self._manager, 'blockingPost'):
            reply = self._manager.blockingPost(request,
                                               data,
                                               forceRefresh=True)
        # use blocking event loop for older versions
        else:
            loop = QEventLoop()
            timer = QTimer()
            timer.setSingleShot(True)
            # reply or timeout break event loop, whoever comes first
            timer.timeout.connect(loop.quit)
            reply = self._manager.post(request, data)
            reply.finished.connect(loop.quit)

            timer.start(timeout)

            # start blocking loop
            loop.exec()
            loop.deleteLater()
            if not timer.isActive():
                reply.deleteLater()
                raise ConnectionError('Timeout')

            timer.stop()
        if reply.error():
            self.error.emit(reply.errorString())
            raise ConnectionError(reply.errorString())
        res = Reply(reply)
        self.finished.emit(res)
        return res
Ejemplo n.º 8
0
    def do_request(self, point: QgsPointXY) -> None:
        query = QUrlQuery()
        query.addQueryItem("lat", str(point.y()))
        query.addQueryItem("lon", str(point.x()))
        query.addQueryItem("format", "json")

        url = QUrl(self.URL)
        url.setQuery(query)

        request = QNetworkRequest(url)
        request.setHeader(QNetworkRequest.UserAgentHeader,
                          "*****@*****.**")

        response = self.nam.blockingGet(request)
        self._status_code = response.attribute(
            QNetworkRequest.HttpStatusCodeAttribute)
        self._content = json.loads(bytes(response.content()))
        if self._content.get("error"):
            self._error_string = self._content["error"]
            return
Ejemplo n.º 9
0
        def run():
            def sslVerifyNone(req):
                conf = req.sslConfiguration()
                conf.setPeerVerifyMode( QSslSocket.VerifyNone )
                req.setSslConfiguration( conf )

            req = QNetworkRequest( url )
            sslVerifyNone( req ) # Need for Windows, error 'Handshake failed'
            if json_request is None:
                reply = self.nam.get( req )
            else:
                req.setHeader( QNetworkRequest.ContentTypeHeader, "application/json" )
                data = QByteArray()
                data.append( json.dumps( json_request ) )
                reply = self.nam.post( req, data )
            if reply is None:
                response = { 'isOk': False, 'message': "Network error", 'errorCode': -1 }
                self.finished.emit( response )
                return
            self.abortReply.connect( reply.abort )
            if not self.responseAllFinished:
                self._connectReply( reply )
Ejemplo n.º 10
0
    def loadModel(self):
        imd = None
        try:
            loader = ModelLoader(self.ui.mDataLineEdit.text())
            models = loader.detect_models()
            model_names = map(lambda m: m.name, models)
            self._log_output("Looking up models: " + ', '.join(model_names))
            ili = loader.gen_lookup_ili()
            qDebug(ili)
            wpsreq = self._create_wps_request(ili)
            url = self.ui.mIlisMetaUrlLineEdit.text()
            req = QNetworkRequest(QUrl(url))
            req.setHeader(QNetworkRequest.ContentTypeHeader, 'application/xml')
            reply = QgsNetworkAccessManager.instance().post(req, wpsreq)

            # Wait for reply or timeout
            loop = QEventLoop()
            reply.finished.connect(loop.quit)
            QTimer.singleShot(15000, reply.abort)
            loop.exec_()

            if reply.isFinished() and reply.error() == QNetworkReply.NoError:
                result = reply.readAll()
                imd = self._parse_wps_response(result)
        except:
            qDebug("Exception during IlisModel download")
        if imd is None:
            self._show_log_window()
            QgsApplication.messageLog().logMessage(
                "Couldn't download Ilismeta model", "Interlis",
                Qgis.MessageLevel(1))
            self.ui.mModelLineEdit.setText("")
        else:
            fh, imdfn = tempfile.mkstemp(suffix='.imd')
            os.close(fh)
            with codecs.open(imdfn, "w", encoding='utf-8') as file:
                file.write(imd)
            self.ui.mModelLineEdit.setText(imdfn)
Ejemplo n.º 11
0
    def result(self, result):
        # See if OK was pressed
        if result:
            project = QgsProject.instance()
            # First get all the values of the GUI items
            crs_input = self.dlg.crs_input.crs()
            crs_out = QgsCoordinateReferenceSystem(
                'EPSG:4326')  # we need this to be WGS84 for Nominatim
            lineedit_text = self.dlg.lineedit_xy.value()

            # Protect the free text field for coordinates from generic user failure
            try:
                lineedit_yx = [
                    float(coord.strip()) for coord in lineedit_text.split(',')
                ]
            except:
                QMessageBox.critical(
                    self.iface.mainWindow(), 'QuickAPI error',
                    "Did you really specify a coordinate in comma-separated Lat/Long?\nExiting..."
                )
                return

            # Create a Point and transform if necessary
            point = QgsPointXY(*reversed(lineedit_yx))
            if crs_input.authid() != 'EPSG:4326':
                xform = QgsCoordinateTransform(crs_input, crs_out, project)
                point_transform = xform.transform(point)
                point = point_transform

            # Set up the GET Request to Nominatim
            query = QUrlQuery()
            query.addQueryItem('lat', str(point.y()))
            query.addQueryItem('lon', str(point.x()))
            query.addQueryItem('format', 'json')

            url = QUrl('https://nominatim.openstreetmap.org/reverse')
            url.setQuery(query)

            request = QNetworkRequest(url)
            request.setHeader(QNetworkRequest.UserAgentHeader,
                              '*****@*****.**')

            nam = QgsNetworkAccessManager()
            response: QgsNetworkReplyContent = nam.blockingGet(request)

            # Only process if HTTP status code is 200
            status_code = response.attribute(
                QNetworkRequest.HttpStatusCodeAttribute)
            if status_code == 200:
                # Get the content of the response and process it
                response_json = json.loads(bytes(response.content()))
                if response_json.get('error'):
                    QMessageBox.critical(
                        self.iface.mainWindow(), "Quick API error",
                        "The request was not processed succesfully!\n\n"
                        "Message:\n"
                        "{}".format(response_json['error']))
                    return

                x = float(response_json['lon'])
                y = float(response_json['lat'])
                address = response_json['display_name']
                license = response_json['licence']

                # Create the output memory layer
                layer_out = QgsVectorLayer(
                    "Point?crs=EPSG:4326&field=address:string&field=license:string",
                    "Nominatim Reverse Geocoding", "memory")

                # Create the output feature (only one here)
                point_out = QgsPointXY(x, y)
                feature = QgsFeature()
                feature.setGeometry(QgsGeometry.fromPointXY(point_out))
                feature.setAttributes([address, license])

                # Add feature to layer and layer to map
                layer_out.dataProvider().addFeature(feature)
                layer_out.updateExtents()
                project.addMapLayer(layer_out)

                # build bbox for auto-zoom feature
                bbox = [float(coord) for coord in response_json['boundingbox']]
                min_y, max_y, min_x, max_x = bbox
                bbox_geom = QgsGeometry.fromRect(
                    QgsRectangle(min_x, min_y, max_x, max_y))

                # Transform bbox if map canvas has a different CRS
                if project.crs().authid() != 'EPSG:4326':
                    xform = QgsCoordinateTransform(crs_out, project.crs(),
                                                   project)
                    bbox_geom.transform(xform)

                self.iface.mapCanvas().zoomToFeatureExtent(
                    QgsRectangle.fromWkt(bbox_geom.asWkt()))
Ejemplo n.º 12
0
    def request(self,
                url,
                first_request_time=None,
                retry_counter=0,
                post_json=None):
        """Performs HTTP GET/POST with credentials, returning the body as
        JSON.

        :param url: URL extension for request. Should begin with a slash.
        :type url: string

        :param first_request_time: The time of the first request (None if no
            retries have occurred).
        :type first_request_time: datetime.datetime

        :param post_json: Parameters for POST endpoints
        :type post_json: dict

        :raises valhalla.utils.exceptions.ApiError: when the API returns an error.

        :returns: openrouteservice response body
        :rtype: dict
        """

        if not first_request_time:
            first_request_time = datetime.now()

        elapsed = datetime.now() - first_request_time
        if elapsed > self.retry_timeout:
            raise exceptions.Timeout()

        if retry_counter > 0:
            # 0.5 * (1.5 ^ i) is an increased sleep time of 1.5x per iteration,
            # starting at 0.5s when retry_counter=1. The first retry will occur
            # at 1, so subtract that first.
            delay_seconds = 1.5**(retry_counter - 1)

            # Jitter this value by 50% and pause.
            time.sleep(delay_seconds * (random.random() + 0.5))

        # Define the request
        params = {'access_token': self.key}
        authed_url = self._generate_auth_url(
            url,
            params,
        )
        url_object = QUrl(self.base_url + authed_url)
        self.url = url_object.url()
        body = QJsonDocument.fromJson(json.dumps(post_json).encode())
        request = QNetworkRequest(url_object)
        request.setHeader(QNetworkRequest.ContentTypeHeader,
                          'application/json')

        logger.log(
            "url: {}\nParameters: {}".format(
                self.url,
                # final_requests_kwargs
                json.dumps(post_json, indent=2)),
            0)

        start = time.time()
        response: QgsNetworkReplyContent = self.nam.blockingPost(
            request, body.toJson())
        self.response_time = time.time() - start

        try:
            self.handle_response(response, post_json['id'])
        except exceptions.OverQueryLimit:
            # Let the instances know smth happened
            self.overQueryLimit.emit()
            return self.request(url, first_request_time, retry_counter + 1,
                                post_json)

        response_content = json.loads(bytes(response.content()))

        # Mapbox treats 400 errors with a 200 status code
        if 'error' in response_content:
            raise exceptions.ApiError(str(response_content['status_code']),
                                      response_content['error'])

        return response_content