Example #1
0
    def sendVote(self, plugin_id, vote):
        """ send vote via the RPC """

        if not plugin_id or not vote:
            return False
        url = "http://plugins.qgis.org/plugins/RPC2/"
        params = "{\"id\":\"djangorpc\",\"method\":\"plugin.vote\",\"params\":[%s,%s]}" % (str(plugin_id), str(vote))
        req = QNetworkRequest(QUrl(url))
        req.setRawHeader("Content-Type", "application/json")
        QgsNetworkAccessManager.instance().post(req, params)
        return True
Example #2
0
    def sendVote(self, plugin_id, vote):
        """ send vote via the RPC """

        if not plugin_id or not vote:
            return False
        url = "http://plugins.qgis.org/plugins/RPC2/"
        params = {"id": "djangorpc", "method": "plugin.vote", "params": [str(plugin_id), str(vote)]}
        req = QNetworkRequest(QUrl(url))
        req.setRawHeader(b"Content-Type", b"application/json")
        QgsNetworkAccessManager.instance().post(req, bytes(json.dumps(params), "utf-8"))
        return True
Example #3
0
    def fetchNext(self):
        if len(self.queue) == 0:
            return
        url = self.queue.pop(0)
        self.log("fetchNext: %s" % url)

        request = QNetworkRequest(QUrl(url))
        request.setRawHeader("User-Agent", self.userAgent)
        reply = QgsNetworkAccessManager.instance().get(request)
        reply.finished.connect(self.replyFinishedSlot)
        self.requestingUrls.append(url)
        self.replies.append(reply)
        return reply
    def fetch(self):
        """Fetch the content."""
        # Initialize some properties again
        self._content = None
        self._network_finished = False
        self._network_timeout = False

        request = QNetworkRequest(QUrl(self._url))
        request.setAttribute(
            QNetworkRequest.CacheLoadControlAttribute,
            QNetworkRequest.AlwaysNetwork)

        if self._auth_cfg and qgis_version() >= 21200:
            LOGGER.info('Update request with auth_cfg %s' % self._auth_cfg)
            QgsAuthManager.instance().updateNetworkRequest(
                request, self._auth_cfg
            )

        self._reply = self._network_manager.get(request)
        self._reply.finished.connect(self.fetch_finished)
        self._network_manager.requestTimedOut.connect(self.request_timeout)

        while not self._reply.isFinished():
            # noinspection PyArgumentList
            QCoreApplication.processEvents()

        # Finished
        description = None
        if self._reply.error() != QNetworkReply.NoError:
            status = False
            description = self._reply.errorString()
        else:
            status = True
            self._content = self._reply.readAll()

        self._reply.deleteLater()

        return status, description
Example #5
0
    def testFetchRequestContent(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        request = QNetworkRequest(
            QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) +
                 '/qgis_local_server/index.html'))
        fetcher.fetchContent(request)
        fetcher.finished.connect(self.contentLoaded)
        while not self.loaded:
            app.processEvents()

        r = fetcher.reply()
        assert r.error() == QNetworkReply.NoError, r.error()

        html = fetcher.contentAsString()
        assert 'QGIS' in html
Example #6
0
    def json_reply_finished(self):
        error = self.reply.error()

        if error == QNetworkReply.NoError:
            redirect = self.reply.attribute(
                QNetworkRequest.RedirectionTargetAttribute)
            if redirect is not None and redirect != self.reply.url():
                url = self.reply.url()
                if redirect.isRelative():
                    url = self.reply.url().resolved(redirect)

                log.debug(f'Redirected to {url.toString()}')
                self.reply.deleteLater()
                self.reply = None
                # noinspection PyArgumentList
                self.reply = QgsNetworkAccessManager.instance().get(
                    QNetworkRequest(url))
                self.reply.finished.connect(self.json_reply_finished)
                return

            status = self.reply.attribute(
                QNetworkRequest.HttpStatusCodeAttribute)
            msg = self.reply.attribute(
                QNetworkRequest.HttpReasonPhraseAttribute)
            log.debug(f'Request finished: {status} - {msg}')
            try:
                data = bytes(self.reply.readAll())
                self.json = json.loads(data)
            except Exception as e:
                log.debug(str(e))
            # noinspection PyUnresolvedReferences
            self.finished.emit()
        else:
            # report any errors except for the one we have caused
            # by cancelling the request
            if error != QNetworkReply.OperationCanceledError:
                msg = f'Network request failed: {self.reply.errorString()}'
                log.debug(msg)
                # noinspection PyUnresolvedReferences
                self.errored.emit(msg)
            else:
                # noinspection PyUnresolvedReferences
                self.aborted.emit()

            self.reply.deleteLater()
            self.reply = None
Example #7
0
    def requestDownloading(self):
        self.request = QNetworkRequest(self.url)
        authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
        if authcfg and isinstance(authcfg, str):
            if not QgsApplication.authManager().updateNetworkRequest(
                    self.request, authcfg.strip()):
                self.mResult = self.tr(
                    "Update of network request with authentication "
                    "credentials FAILED for configuration '{0}'").format(authcfg)
                self.request = None

        if self.request is not None:
            self.reply = QgsNetworkAccessManager.instance().get(self.request)
            self.reply.downloadProgress.connect(self.readProgress)
            self.reply.finished.connect(self.requestFinished)

            self.stateChanged(4)
    def requestDownloading(self):
        self.request = QNetworkRequest(self.url)
        self.request.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.AttributeInitiatorClass), "QgsPluginInstallerInstallingDialog")
        authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
        if authcfg and isinstance(authcfg, str):
            if not QgsApplication.authManager().updateNetworkRequest(
                    self.request, authcfg.strip()):
                self.mResult = self.tr(
                    "Update of network request with authentication "
                    "credentials FAILED for configuration '{0}'").format(authcfg)
                self.request = None

        if self.request is not None:
            self.reply = QgsNetworkAccessManager.instance().get(self.request)
            self.reply.downloadProgress.connect(self.readProgress)
            self.reply.finished.connect(self.requestFinished)

            self.stateChanged(4)
def _get_json_results(path, feedback):
    req = QgsBlockingNetworkRequest()
    req_status = req.get(
        QNetworkRequest(QUrl(urljoin(_TAXREF_API_BASE_URL, path))))
    if req_status != QgsBlockingNetworkRequest.NoError:
        for error_name in ('NetworkError', 'TimeoutError',
                           'ServerExceptionError'):
            if req_status == getattr(QgsBlockingNetworkRequest, error_name):
                feedback.reportError('{}: {}'.format(error_name,
                                                     req.errorMessage()))
                break
        return None
    content = bytes(req.reply().content())
    if not content:
        feedback.reportError('Error while downloading data from {}.'.format(
            urljoin(_TAXREF_API_BASE_URL, path)))
        return None
    return json.loads(content)['_embedded']
Example #10
0
def _download_qgis(packageUrl, handle):
    from qgis.core import QgsNetworkAccessManager

    request = QNetworkRequest(QUrl(packageUrl))
    reply = QgsNetworkAccessManager.instance().get(request)
    evloop = QEventLoop()
    reply.finished.connect(evloop.quit)
    evloop.exec_(QEventLoop.ExcludeUserInputEvents)
    content_type = reply.rawHeader('Content-Type')
    if bytearray(content_type) == bytearray('text/plain; charset=utf-8'):
        handle.write(bytearray(reply.readAll()))
    else:
        msg = 'Failed to download %s\n\nPlease check your QGIS network settings and authentication db' % (
            packageUrl)
        ret_code = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
        if ret_code:
            msg += '\n\nThe HTTP status code was %d.' % (ret_code)
        raise Exception(msg)
    def process_put_call(self, url, data=None, report_url=True):
        """
        Run a PUT request and return reply data
        :param url: url for request
        :param data:
        :param report_url: True if URL should be reported to feedback
        :return: response or error message in json format
        """

        if self.connection.read_only:
            return {
                "error": {
                    "msg": "Graphium connection is set to read-only!"
                }
            }

        url_query = QUrl(url)
        if report_url:
            self.report_info('PUT ' + url_query.toString())

        data_byte_array = QJsonDocument.fromVariant(data)

        request = QNetworkRequest(url_query)
        if self.connection.auth_cfg != '':
            self.auth = 0
            config = QgsAuthMethodConfig()
            QgsApplication.authManager().loadAuthenticationConfig(
                self.connection.auth_cfg, config, True)
            concatenated = config.configMap(
            )['username'] + ":" + config.configMap()['password']

            data = base64.encodebytes(concatenated.encode("utf-8")).replace(
                '\n'.encode("utf-8"), ''.encode("utf-8"))
            request.setRawHeader("Authorization".encode("utf-8"),
                                 ("Basic %s" % data).encode("utf-8"))
            request.setRawHeader("Accept".encode("utf-8"),
                                 "*/*".encode("utf-8"))
        loop = QEventLoop()  # https://stackoverflow.com/a/46514984
        reply = self.network_access_manager.put(request,
                                                data_byte_array.toJson())
        reply.finished.connect(loop.quit)
        loop.exec_()

        return self.process_q_reply(reply)
    def download_image(self, url):
        res = False
        img = None
        msg = {'text': '', 'level': Qgis.Warning}
        if url:
            self.logger.info(__name__, "Downloading file from {}".format(url))
            msg_status_bar = "Downloading image from document repository (this might take a while)..."
            with ProcessWithStatus(msg_status_bar):
                if is_connected(TEST_SERVER):

                    nam = QNetworkAccessManager()
                    request = QNetworkRequest(QUrl(url))
                    reply = nam.get(request)

                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()

                    status = reply.attribute(
                        QNetworkRequest.HttpStatusCodeAttribute)
                    if status == 200:
                        res = True
                        img = reply.readAll()
                    else:
                        res = False
                        msg['text'] = QCoreApplication.translate(
                            "SettingsDialog",
                            "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL."
                        )
                else:
                    res = False
                    msg['text'] = QCoreApplication.translate(
                        "SettingsDialog",
                        "There was a problem connecting to Internet.")

        else:
            res = False
            msg['text'] = QCoreApplication.translate("SettingsDialog",
                                                     "Not valid URL")

        if not res:
            self.logger.log_message(__name__, msg['text'], msg['level'])

        return res, img
    def process_post_call(self,
                          url,
                          url_query_items,
                          data,
                          is_read_only=True,
                          report_url=True):
        """
        Run a POST request and return reply data
        :param url: url for request
        :param url_query_items:
        :param data:
        :param is_read_only: True if the request does not update data
        :param report_url: True if URL should be reported to feedback
        :return: response or error message in json format
        """

        if self.connection.read_only and not is_read_only:
            return {
                "error": {
                    "msg": "Graphium connection is set to read-only!"
                }
            }

        url_query = QUrl(url)
        if report_url:
            self.report_info('POST ' + url_query.toString())

        if url_query_items:
            url_query.setQuery(url_query_items)

        # data_byte_array = json.dumps(data).encode('utf8')
        # data = QtCore.QByteArray( json.dumps( json_request ) )
        data_byte_array = QJsonDocument.fromVariant(data)

        request = QNetworkRequest(url_query)
        if self.connection.auth_cfg != '':
            request.setRawHeader("Accept".encode("utf-8"),
                                 "*/*".encode("utf-8"))
        request.setHeader(QNetworkRequest.ContentTypeHeader,
                          "application/json")
        reply = self.network_access_manager.blockingPost(
            request, data_byte_array.toJson(), self.connection.auth_cfg, True,
            self.feedback)
        return self.process_qgs_reply(reply)
def _sync_get(url):
    global __network_manager
    if __network_manager is None:
        __network_manager = QNetworkAccessManager()
        __network_manager.setProxy(QgsNetworkAccessManager.instance().proxy())
    pause = QEventLoop()
    req = QNetworkRequest(url)
    req.setRawHeader(b"Accept", b"application/xml")
    req.setRawHeader(b"Accept-Language", bytes(settings.value("default_language", "fr"), "utf8"))
    req.setRawHeader(b"User-Agent", bytes(settings.value('http_user_agent', plugin_name()), "utf8"))
    reply = __network_manager.get(req)
    reply.finished.connect(pause.quit)
    is_ok = [True]
    def onError(self):
        is_ok[0] = False
        pause.quit()
    reply.error.connect(onError)
    pause.exec_()
    return reply, is_ok[0]
    def logIn(self):
        if self.connectWidget.login().strip() == "" or self.connectWidget.password().strip() == "":
            self._showMessage("Please enter valid Connect credentials "
                              "to use plugin.")
            return

        setPluginSetting("rememberCredentials", self.connectWidget.remember())

        utils.addBoundlessRepository()

        self.request = QNetworkRequest(QUrl(authEndpointUrl))
        httpAuth = base64.b64encode(b"%s:%s" % (self.connectWidget.login().strip(), self.connectWidget.password().strip())).decode("ascii")
        self.request.setRawHeader('Authorization', 'Basic {}'.format(httpAuth))
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        self.token = connect.getToken(self.connectWidget.login().strip(), self.connectWidget.password().strip())
        if self.token is None:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, "Error!", "Can not get token. Please check you credentials and endpoint URL in plugin settings.")
            return
        self.reply = QgsNetworkAccessManager.instance().get(self.request)
        self.reply.finished.connect(self.requestFinished)
 def testGet(self):
     request = QgsBlockingNetworkRequest()
     spy = QSignalSpy(request.downloadFinished)
     err = request.get(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/qgis_local_server/index.html')))
     self.assertEqual(len(spy), 1)
     self.assertEqual(err, QgsBlockingNetworkRequest.NoError)
     self.assertEqual(request.errorMessage(), '')
     reply = request.reply()
     self.assertEqual(reply.error(), QNetworkReply.NoError)
     self.assertEqual(reply.content(), '<!DOCTYPE html>\n<html lang="en">\n<head>\n\t<meta charset="utf-8" />\n\t<title>Local QGIS Server Default Index</title>\n</head>\n<body>\n  <h2 style="font-family:Arial;">Web Server Working<h2/>\n</body>\n</html>\n')
     self.assertEqual(reply.rawHeaderList(), [b'Server',
                                              b'Date',
                                              b'Content-type',
                                              b'Content-Length',
                                              b'Last-Modified'])
     self.assertEqual(reply.rawHeader(b'Content-type'), 'text/html')
     self.assertEqual(reply.rawHeader(b'xxxxxxxxx'), '')
     self.assertEqual(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), 200)
     self.assertEqual(reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute), 'OK')
     self.assertEqual(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), 200)
     self.assertEqual(reply.attribute(QNetworkRequest.RedirectionTargetAttribute), None)
    def process_delete_call(self, url, report_url=True):
        """
        Run a DELETE request and return reply data
        :param url: url for request
        :param report_url: True if URL should be reported to feedback
        :return: response or error message in json format
        """

        if self.connection.read_only:
            return {
                "error": {
                    "msg": "Graphium connection is set to read-only!"
                }
            }

        url_query = QUrl(url)
        if report_url:
            self.report_info('DELETE ' + url_query.toString())

        request = QNetworkRequest(url_query)
        if self.connection.auth_cfg != '':
            self.auth = 0
            config = QgsAuthMethodConfig()
            QgsApplication.authManager().loadAuthenticationConfig(
                self.connection.auth_cfg, config, True)
            concatenated = config.configMap(
            )['username'] + ":" + config.configMap()['password']

            data = base64.encodebytes(concatenated.encode("utf-8")).replace(
                '\n'.encode("utf-8"), ''.encode("utf-8"))
            request.setRawHeader("Authorization".encode("utf-8"),
                                 ("Basic %s" % data).encode("utf-8"))
            request.setRawHeader("Accept".encode("utf-8"),
                                 "*/*".encode("utf-8"))
        loop = QEventLoop()
        reply = self.network_access_manager.deleteResource(request)
        reply.finished.connect(loop.quit)
        loop.exec_()

        return self.process_q_reply(reply)
 def testGet(self):
     request = QgsBlockingNetworkRequest()
     spy = QSignalSpy(request.finished)
     handler = mockedwebserver.SequentialHandler()
     handler.add('GET', '/test.html', 200, {'Content-type': 'text/html'}, '<html></html>\n')
     with mockedwebserver.install_http_handler(handler):
         err = request.get(QNetworkRequest(QUrl('http://localhost:' + str(TestQgsBlockingNetworkRequest.port) + '/test.html')), True)
     self.assertEqual(len(spy), 1)
     self.assertEqual(err, QgsBlockingNetworkRequest.NoError)
     self.assertEqual(request.errorMessage(), '')
     reply = request.reply()
     self.assertEqual(reply.error(), QNetworkReply.NoError)
     self.assertEqual(reply.content(), '<html></html>\n')
     self.assertEqual(reply.rawHeaderList(), [b'Server',
                                              b'Date',
                                              b'Content-type',
                                              b'Content-Length'])
     self.assertEqual(reply.rawHeader(b'Content-type'), 'text/html')
     self.assertEqual(reply.rawHeader(b'xxxxxxxxx'), '')
     self.assertEqual(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute), 200)
     self.assertEqual(reply.attribute(QNetworkRequest.HttpReasonPhraseAttribute), 'OK')
     self.assertEqual(reply.attribute(QNetworkRequest.RedirectionTargetAttribute), None)
def _sync_get(url):
    global __network_manager
    if __network_manager is None:
        __network_manager = QNetworkAccessManager()
        __network_manager.setProxy(QgsNetworkAccessManager.instance().proxy())
    pause = QEventLoop()
    req = QNetworkRequest(url)
    req.setRawHeader(b"Accept", b"application/xml")
    req.setRawHeader(b"Accept-Language",
                     bytes(settings.value("default_language", "fr"), "utf8"))
    req.setRawHeader(
        b"User-Agent",
        bytes(settings.value("http_user_agent", plugin_name()), "utf8"))
    reply = __network_manager.get(req)
    reply.finished.connect(pause.quit)
    is_ok = [True]

    def onError(self):
        is_ok[0] = False
        pause.quit()

    reply.error.connect(onError)
    pause.exec_()
    return reply, is_ok[0]
Example #20
0
    def testFetchBadUrl2(self):
        request = QgsBlockingNetworkRequest()
        spy = QSignalSpy(request.downloadFinished)

        handler = mockedwebserver.SequentialHandler()
        handler.add(
            'GET', '/ffff', 404, {},
            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n        "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n    <head>\n        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">\n        <title>Error response</title>\n    </head>\n    <body>\n        <h1>Error response</h1>\n        <p>Error code: 404</p>\n        <p>Message: File not found.</p>\n        <p>Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.</p>\n    </body>\n</html>\n'
        )
        with mockedwebserver.install_http_handler(handler):
            err = request.get(
                QNetworkRequest(
                    QUrl('http://localhost:' +
                         str(TestQgsBlockingNetworkRequest.port) + '/ffff')))
        self.assertEqual(len(spy), 1)
        self.assertEqual(err, QgsBlockingNetworkRequest.ServerExceptionError)
        self.assertIn('Not Found', request.errorMessage())
        reply = request.reply()
        self.assertEqual(reply.error(), QNetworkReply.ContentNotFoundError)
        self.assertEqual(
            reply.content(),
            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"\n        "http://www.w3.org/TR/html4/strict.dtd">\n<html>\n    <head>\n        <meta http-equiv="Content-Type" content="text/html;charset=utf-8">\n        <title>Error response</title>\n    </head>\n    <body>\n        <h1>Error response</h1>\n        <p>Error code: 404</p>\n        <p>Message: File not found.</p>\n        <p>Error code explanation: HTTPStatus.NOT_FOUND - Nothing matches the given URI.</p>\n    </body>\n</html>\n'
        )
Example #21
0
    def reply_finished(self, reply):

        if reply != None:
            possibleRedirectUrl = reply.attribute(
                QNetworkRequest.RedirectionTargetAttribute)

            # If the URL is not empty, we're being redirected.
            if possibleRedirectUrl != None:
                request = QNetworkRequest(possibleRedirectUrl)
                result = self.nam.get(request)
                self.parent.init_progress()
                self.parent.add_download_progress(reply)
                result.downloadProgress.connect(
                    lambda done, all, reply=result: self.progress(
                        done, all, reply))
            else:
                if reply.error() != None:
                    if reply.error() == QNetworkReply.ContentNotFoundError:
                        self.parent.set_progress()
                        reply.abort()
                        reply.deleteLater()

                    elif reply.error() == QNetworkReply.NoError:
                        result = reply.readAll()
                        f = open(self.filename, 'wb')
                        f.write(result)
                        f.close()

                        out_image = self.unzip(self.filename)
                        (dir, file) = os.path.split(out_image)
                        if not self.layer_exists(file):
                            self.iface.addRasterLayer(out_image, file)

                        self.parent.set_progress()

                        # Clean up. */
                        reply.deleteLater()
Example #22
0
    def requestFetching(self, key):
        """ start fetching the repository given by key """
        self.mRepositories[key]["state"] = 1
        url = QUrl(self.mRepositories[key]["url"] + self.urlParams())
        #v=str(Qgis.QGIS_VERSION_INT)
        #url.addQueryItem('qgis', '.'.join([str(int(s)) for s in [v[0], v[1:3]]]) ) # don't include the bugfix version!

        self.mRepositories[key]["QRequest"] = QNetworkRequest(url)
        authcfg = self.mRepositories[key]["authcfg"]
        if authcfg and isinstance(authcfg, basestring):
            if not QgsAuthManager.instance().updateNetworkRequest(
                    self.mRepositories[key]["QRequest"], authcfg.strip()):
                msg = QCoreApplication.translate(
                    "QgsPluginInstaller",
                    "Update of network request with authentication "
                    "credentials FAILED for configuration '{0}'").format(authcfg)
                iface.pluginManagerInterface().pushMessage(msg, QgsMessageBar.WARNING)
                self.mRepositories[key]["QRequest"] = None
                return
        self.mRepositories[key]["QRequest"].setAttribute(QNetworkRequest.User, key)
        self.mRepositories[key]["xmlData"] = QgsNetworkAccessManager.instance().get(self.mRepositories[key]["QRequest"])
        self.mRepositories[key]["xmlData"].setProperty('reposName', key)
        self.mRepositories[key]["xmlData"].downloadProgress.connect(self.mRepositories[key]["Relay"].dataReadProgress)
        self.mRepositories[key]["xmlData"].finished.connect(self.xmlDownloaded)
Example #23
0
    def _sendRequest(self, url, params, headers={}):
        if self.asynchonous:

            if self.reply is not None:
                self.reply.finished.disconnect(self.reply_finished)
                self.reply.abort()
                self.reply = None

            url = QUrl(url)
            urlQuery = QUrlQuery(url)
            for key, value in params.items():
                urlQuery.addQueryItem(key, value)
            QgsLogger.debug('Request: {}'.format(url.toEncoded()))
            url.setQuery(urlQuery)
            request = QNetworkRequest(url)
            for key, value in headers.items():
                request.setRawHeader(key, value)
            self.reply = QgsNetworkAccessManager.instance().get(request)

        else:
            url = url + '?' + urllib.parse.urlencode(params)
            response = urllib.request.urlopen(url)
            data = json.load(response)
            self.load_data(data)
def _sync_get(url):
    global __network_manager
    if __network_manager is None:
        __network_manager = QNetworkAccessManager()
        __network_manager.setProxy(QgsNetworkAccessManager.instance().proxy())
    pause = QEventLoop()
    req = QNetworkRequest(url)
    req.setRawHeader(b"Accept", b"application/xml")
    req.setRawHeader(b"Accept-Language", b"fr")
    reply = __network_manager.get(req)
    reply.finished.connect(pause.quit)
    is_ok = [True]

    def onError(self):
        is_ok[0] = False
        pause.quit()

    reply.error.connect(onError)
    pause.exec_()
    return reply, is_ok[0]
    def setupUi(self):
        self.labels = {}
        self.widgets = {}
        self.checkBoxes = {}
        self.showAdvanced = False
        self.wrappers = {}
        self.valueItems = {}
        self.dependentItems = {}
        self.resize(650, 450)
        self.buttonBox = QDialogButtonBox()
        self.buttonBox.setOrientation(Qt.Horizontal)
        self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel
                                          | QDialogButtonBox.Ok)
        tooltips = self._alg.getParameterDescriptions()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setSpacing(5)
        self.verticalLayout.setMargin(20)

        self.bar = QgsMessageBar()
        self.bar.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        self.verticalLayout.addWidget(self.bar)

        hLayout = QHBoxLayout()
        hLayout.setSpacing(5)
        hLayout.setMargin(0)
        descriptionLabel = QLabel(self.tr("Description"))
        self.descriptionBox = QLineEdit()
        self.descriptionBox.setText(self._alg.displayName())
        hLayout.addWidget(descriptionLabel)
        hLayout.addWidget(self.descriptionBox)
        self.verticalLayout.addLayout(hLayout)
        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)
        self.verticalLayout.addWidget(line)

        for param in self._alg.parameters:
            if param.isAdvanced:
                self.advancedButton = QPushButton()
                self.advancedButton.setText(
                    self.tr('Show advanced parameters'))
                self.advancedButton.clicked.connect(
                    self.showAdvancedParametersClicked)
                advancedButtonHLayout = QHBoxLayout()
                advancedButtonHLayout.addWidget(self.advancedButton)
                advancedButtonHLayout.addStretch()
                self.verticalLayout.addLayout(advancedButtonHLayout)
                break
        for param in self._alg.parameters:
            if param.hidden:
                continue
            desc = param.description
            if isinstance(param, ParameterExtent):
                desc += self.tr('(xmin, xmax, ymin, ymax)')
            if isinstance(param, ParameterPoint):
                desc += self.tr('(x, y)')
            if param.optional:
                desc += self.tr(' [optional]')
            label = QLabel(desc)
            self.labels[param.name] = label

            wrapper = param.wrapper(self)
            self.wrappers[param.name] = wrapper

            widget = wrapper.widget
            if widget is not None:
                self.valueItems[param.name] = widget
                if param.name in list(tooltips.keys()):
                    tooltip = tooltips[param.name]
                else:
                    tooltip = param.description
                label.setToolTip(tooltip)
                widget.setToolTip(tooltip)
                if param.isAdvanced:
                    label.setVisible(self.showAdvanced)
                    widget.setVisible(self.showAdvanced)
                    self.widgets[param.name] = widget

                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(widget)

        for output in self._alg.outputs:
            if output.hidden:
                continue
            if isinstance(output, (OutputRaster, OutputVector, OutputTable,
                                   OutputHTML, OutputFile, OutputDirectory)):
                label = QLabel(output.description + '<' +
                               output.__class__.__name__ + '>')
                item = QLineEdit()
                if hasattr(item, 'setPlaceholderText'):
                    item.setPlaceholderText(ModelerParametersDialog.ENTER_NAME)
                self.verticalLayout.addWidget(label)
                self.verticalLayout.addWidget(item)
                self.valueItems[output.name] = item

        label = QLabel(' ')
        self.verticalLayout.addWidget(label)
        label = QLabel(self.tr('Parent algorithms'))
        self.dependenciesPanel = self.getDependenciesPanel()
        self.verticalLayout.addWidget(label)
        self.verticalLayout.addWidget(self.dependenciesPanel)
        self.verticalLayout.addStretch(1000)

        self.setPreviousValues()
        self.setWindowTitle(self._alg.displayName())
        self.verticalLayout2 = QVBoxLayout()
        self.verticalLayout2.setSpacing(2)
        self.verticalLayout2.setMargin(0)
        self.tabWidget = QTabWidget()
        self.tabWidget.setMinimumWidth(300)
        self.paramPanel = QWidget()
        self.paramPanel.setLayout(self.verticalLayout)
        self.scrollArea = QgsScrollArea()
        self.scrollArea.setWidget(self.paramPanel)
        self.scrollArea.setWidgetResizable(True)
        self.tabWidget.addTab(self.scrollArea, self.tr('Parameters'))

        self.txtHelp = QTextBrowser()

        html = None
        isText, algHelp = self._alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr(
                        '<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    self.tabWidget.addTab(self.txtHelp, 'Help')
                    self.reply = QgsNetworkAccessManager.instance().get(
                        QNetworkRequest(algHelp))
                    self.reply.finished.connect(self.requestFinished)
            except:
                pass

        self.verticalLayout2.addWidget(self.tabWidget)
        self.verticalLayout2.addWidget(self.buttonBox)
        self.setLayout(self.verticalLayout2)
        self.buttonBox.accepted.connect(self.okPressed)
        self.buttonBox.rejected.connect(self.cancelPressed)
        QMetaObject.connectSlotsByName(self)

        for wrapper in list(self.wrappers.values()):
            wrapper.postInitialize(list(self.wrappers.values()))
Example #26
0
    def handle_download(self):
        result_type_codes_download = [
            "logfiles",
            # non-groundwater codes
            "subgrid_map",
            "flow-aggregate",
            "id-mapping",
            # groundwater codes
            "results-3di",
            "aggregate-results-3di",
            "grid-admin",
        ]
        selection_model = self.dialog.downloadResultTableView.selectionModel()
        proxy_indexes = selection_model.selectedIndexes()
        if len(proxy_indexes) != 1:
            pop_up_info("Please select one result.")
            return
        proxy_selection_index = proxy_indexes[0]
        selection_index = self.dialog.download_proxy_model.mapToSource(
            proxy_selection_index)
        item = self.downloadable_results.rows[selection_index.row()]
        to_download = [
            r for r in item.results.value
            if r["result_type"]["code"] in result_type_codes_download
        ]
        to_download_urls = [dl["attachment_url"] for dl in to_download]
        logger.debug(item.name.value)

        # ask user where to store download
        directory = QFileDialog.getExistingDirectory(None,
                                                     "Choose a directory",
                                                     os.path.expanduser("~"))
        if not directory:
            return
        dir_name = get_valid_filename(item.name.value)
        self.download_directory = os.path.join(directory, dir_name)

        # For now, only work with empty directories that we create ourselves.
        # Because the files are downloaded and processed in chunks, we cannot
        # guarantee data integrity with existing files.
        if os.path.exists(self.download_directory):
            pop_up_info("The directory %s already exists." %
                        self.download_directory)
            return
        logger.info("Creating download directory.")
        os.mkdir(self.download_directory)

        logger.debug(self.download_directory)

        CHUNK_SIZE = 16 * 1024
        # Important note: QNetworkAccessManager is asynchronous, which means
        # the downloads are processed asynchronous using callbacks.
        for url in to_download_urls:
            request = QNetworkRequest(QUrl(url))
            request.setRawHeader(b"username", bytes(self.username, "utf-8"))
            request.setRawHeader(b"password", bytes(self.password, "utf-8"))
            request.setAttribute(USER_DOWNLOAD_DIRECTORY,
                                 self.download_directory)

            reply = self.network_manager.get(request)
            # Get replies in chunks, and process them
            reply.setReadBufferSize(CHUNK_SIZE)
            reply.readyRead.connect(
                self.on_single_download_ready_to_read_chunk)
            reply.finished.connect(self.on_single_download_finished)
        pop_up_info("Download started.")
Example #27
0
def getVideoLocationInfo(videoPath, dataFile=False):
    """ Get basic location info about the video """
    location = []

    try:
        if dataFile == False:
            p = _spawn([
                '-i', videoPath, '-ss', '00:00:00', '-to', '00:00:01', '-map',
                'data-re', '-f', 'data', '-'
            ])

            stdout_data, _ = p.communicate()

        ################
        else:
            global listOfMetadata
            stdout_data = listOfMetadata[0]
        ################

        if stdout_data == b'':
            return
        for packet in StreamParser(stdout_data):
            if isinstance(packet, UnknownElement):
                qgsu.showUserAndLogMessage(
                    "Error interpreting klv data, metadata cannot be read.",
                    "the parser did not recognize KLV data",
                    level=QGis.Warning)
                continue
            packet.MetadataList()
            frameCenterLat = packet.FrameCenterLatitude
            frameCenterLon = packet.FrameCenterLongitude
            loc = "-"

            if Reverse_geocoding_url != "":
                try:
                    url = QUrl(
                        Reverse_geocoding_url.format(str(frameCenterLat),
                                                     str(frameCenterLon)))
                    request = QNetworkRequest(url)
                    reply = QgsNetworkAccessManager.instance().get(request)
                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()
                    reply.finished.disconnect(loop.quit)
                    loop = None
                    result = reply.readAll()
                    data = json.loads(result.data())

                    if "village" in data["address"] and "state" in data[
                            "address"]:
                        loc = data["address"]["village"] + \
                            ", " + data["address"]["state"]
                    elif "town" in data["address"] and "state" in data[
                            "address"]:
                        loc = data["address"]["town"] + \
                            ", " + data["address"]["state"]
                    else:
                        loc = data["display_name"]

                except Exception:
                    qgsu.showUserAndLogMessage(
                        "",
                        "getVideoLocationInfo: failed to get address from reverse geocoding service.",
                        onlyLog=True)

            location = [frameCenterLat, frameCenterLon, loc]

            qgsu.showUserAndLogMessage(
                "",
                "Got Location: lon: " + str(frameCenterLon) + " lat: " +
                str(frameCenterLat) + " location: " + str(loc),
                onlyLog=True)

            break
        else:

            qgsu.showUserAndLogMessage(
                QCoreApplication.translate(
                    "QgsFmvUtils", "This video doesn't have Metadata ! : "))

    except Exception as e:
        qgsu.showUserAndLogMessage(
            QCoreApplication.translate("QgsFmvUtils",
                                       "Video info callback failed! : "),
            str(e))

    return location
Example #28
0
 def __init__(self, url, method='GET', **data):
     self.manager = QNetworkAccessManager()
     self.method = method
     self.url = QUrl(url)
     self.request = QNetworkRequest(self.url)
Example #29
0
def getVideoLocationInfo(videoPath,
                         islocal=False,
                         klv_folder=None,
                         klv_index=0):
    """ Get basic location info about the video """
    location = []
    try:
        if islocal:
            dataFile = os.path.join(klv_folder, "0.0.klv")
            f = open(dataFile, 'rb')
            stdout_data = f.read()
        else:
            p = _spawn([
                '-i', videoPath, '-ss', '00:00:00', '-to', '00:00:01', '-map',
                '0:d:' + str(klv_index), '-f', 'data', '-'
            ])

            stdout_data, _ = p.communicate()
            # qgsu.showUserAndLogMessage("Video Loc info raw result", stdout_data, onlyLog=True)
        if stdout_data == b'':
            # qgsu.showUserAndLogMessage("Error interpreting klv data, metadata cannot be read.", "the parser did not recognize KLV data", level=QGis.Warning)
            return
        for packet in StreamParser(stdout_data):
            if isinstance(packet, UnknownElement):
                qgsu.showUserAndLogMessage(
                    "Error interpreting klv data, metadata cannot be read.",
                    "the parser did not recognize KLV data",
                    level=QGis.Warning)
                continue
            packet.MetadataList()
            centerLat = packet.FrameCenterLatitude
            centerLon = packet.FrameCenterLongitude
            # Target maybe unavailable because of horizontal view
            if centerLat is None and centerLon is None:
                centerLat = packet.SensorLatitude
                centerLon = packet.SensorLongitude
            loc = "-"

            if Reverse_geocoding_url != "":
                try:
                    url = QUrl(
                        Reverse_geocoding_url.format(str(centerLat),
                                                     str(centerLon)))
                    request = QNetworkRequest(url)
                    reply = QgsNetworkAccessManager.instance().get(request)
                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()
                    reply.finished.disconnect(loop.quit)
                    loop = None
                    result = reply.readAll()
                    data = json.loads(result.data())

                    if "village" in data["address"] and "state" in data[
                            "address"]:
                        loc = data["address"]["village"] + \
                            ", " + data["address"]["state"]
                    elif "town" in data["address"] and "state" in data[
                            "address"]:
                        loc = data["address"]["town"] + \
                            ", " + data["address"]["state"]
                    else:
                        loc = data["display_name"]

                except Exception:
                    qgsu.showUserAndLogMessage(
                        "",
                        "getVideoLocationInfo: failed to get address from reverse geocoding service.",
                        onlyLog=True)

            location = [centerLat, centerLon, loc]

            qgsu.showUserAndLogMessage("",
                                       "Got Location: lon: " + str(centerLon) +
                                       " lat: " + str(centerLat) +
                                       " location: " + str(loc),
                                       onlyLog=True)

            break
        else:

            qgsu.showUserAndLogMessage(
                QCoreApplication.translate(
                    "QgsFmvUtils", "This video doesn't have Metadata ! : "))

    except Exception as e:
        qgsu.showUserAndLogMessage(
            QCoreApplication.translate("QgsFmvUtils",
                                       "Video info callback failed! : "),
            str(e))

    return location
Example #30
0
    def __init__(self, alg):
        super(AlgorithmDialogBase, self).__init__(iface.mainWindow())
        self.setupUi(self)

        self.feedback = AlgorithmDialogFeedback(self)
        self.feedback.progressChanged.connect(self.setPercentage)

        self.settings = QgsSettings()
        self.restoreGeometry(
            self.settings.value("/Processing/dialogBase", QByteArray()))

        self.executed = False
        self.mainWidget = None
        self.alg = alg

        # Rename OK button to Run
        self.btnRun = self.buttonBox.button(QDialogButtonBox.Ok)
        self.btnRun.setText(self.tr('Run'))

        self.btnClose = self.buttonBox.button(QDialogButtonBox.Close)

        self.setWindowTitle(self.alg.displayName())

        # desktop = QDesktopWidget()
        # if desktop.physicalDpiX() > 96:
        # self.txtHelp.setZoomFactor(desktop.physicalDpiX() / 96)

        algHelp = self.alg.shortHelp()
        if algHelp is None:
            self.textShortHelp.setVisible(False)
        else:
            self.textShortHelp.document().setDefaultStyleSheet(
                '''.summary { margin-left: 10px; margin-right: 10px; }
                                                    h2 { color: #555555; padding-bottom: 15px; }
                                                    a { text-decoration: none; color: #3498db; font-weight: bold; }
                                                    p { color: #666666; }
                                                    b { color: #333333; }
                                                    dl dd { margin-bottom: 5px; }'''
            )
            self.textShortHelp.setHtml(algHelp)

        self.textShortHelp.setOpenLinks(False)

        def linkClicked(url):
            webbrowser.open(url.toString())

        self.textShortHelp.anchorClicked.connect(linkClicked)

        isText, algHelp = self.alg.help()
        if algHelp is not None:
            algHelp = algHelp if isText else QUrl(algHelp)
            try:
                if isText:
                    self.txtHelp.setHtml(algHelp)
                else:
                    html = self.tr(
                        '<p>Downloading algorithm help... Please wait.</p>')
                    self.txtHelp.setHtml(html)
                    rq = QNetworkRequest(algHelp)
                    self.reply = QgsNetworkAccessManager.instance().get(rq)
                    self.reply.finished.connect(self.requestFinished)
            except Exception:
                self.tabWidget.removeTab(2)
        else:
            self.tabWidget.removeTab(2)

        self.showDebug = ProcessingConfig.getSetting(
            ProcessingConfig.SHOW_DEBUG_IN_DIALOG)
class QgsPluginInstallerInstallingDialog(QDialog, Ui_QgsPluginInstallerInstallingDialogBase):
    # ----------------------------------------- #

    def __init__(self, parent, plugin, stable=True):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.plugin = plugin
        self.mResult = ""
        self.progressBar.setRange(0, 0)
        self.progressBar.setFormat("%p%")
        self.labelName.setText(plugin["name"])
        self.buttonBox.clicked.connect(self.abort)

        self.url = QUrl(plugin["download_url_stable"] if stable else plugin["download_url_experimental"])
        self.redirectionCounter = 0

        fileName = plugin["filename"]
        tmpDir = QDir.tempPath()
        tmpPath = QDir.cleanPath(tmpDir + "/" + fileName)
        self.file = QFile(tmpPath)

        self.requestDownloading()

    def requestDownloading(self):
        self.request = QNetworkRequest(self.url)
        self.request.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.AttributeInitiatorClass), "QgsPluginInstallerInstallingDialog")
        authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
        if authcfg and isinstance(authcfg, str):
            if not QgsApplication.authManager().updateNetworkRequest(
                    self.request, authcfg.strip()):
                self.mResult = self.tr(
                    "Update of network request with authentication "
                    "credentials FAILED for configuration '{0}'").format(authcfg)
                self.request = None

        if self.request is not None:
            self.reply = QgsNetworkAccessManager.instance().get(self.request)
            self.reply.downloadProgress.connect(self.readProgress)
            self.reply.finished.connect(self.requestFinished)

            self.stateChanged(4)

    def exec_(self):
        if self.request is None:
            return QDialog.Rejected

        QDialog.exec_(self)

    # ----------------------------------------- #
    def result(self):
        return self.mResult

    # ----------------------------------------- #
    def stateChanged(self, state):
        messages = [
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Installing…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Resolving host name…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Connecting…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Host connected. Sending request…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Downloading data…"),
            self.tr("Idle"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Closing connection…"),
            self.tr("Error")
        ]
        self.labelState.setText(messages[state])

    # ----------------------------------------- #
    def readProgress(self, done, total):
        if total > 0:
            self.progressBar.setMaximum(total)
            self.progressBar.setValue(done)

    # ----------------------------------------- #
    def requestFinished(self):
        reply = self.sender()
        self.buttonBox.setEnabled(False)
        if reply.error() != QNetworkReply.NoError:
            self.mResult = reply.errorString()
            if reply.error() == QNetworkReply.OperationCanceledError:
                self.mResult += "<br/><br/>" + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.")
            self.reject()
            reply.deleteLater()
            return
        elif reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) in (301, 302):
            redirectionUrl = reply.attribute(QNetworkRequest.RedirectionTargetAttribute)
            self.redirectionCounter += 1
            if self.redirectionCounter > 4:
                self.mResult = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections")
                self.reject()
                reply.deleteLater()
                return
            else:
                if redirectionUrl.isRelative():
                    redirectionUrl = reply.url().resolved(redirectionUrl)
                # Fire a new request and exit immediately in order to quietly destroy the old one
                self.url = redirectionUrl
                self.requestDownloading()
                reply.deleteLater()
                return

        self.file.open(QFile.WriteOnly)
        self.file.write(reply.readAll())
        self.file.close()
        self.stateChanged(0)
        reply.deleteLater()
        pluginDir = qgis.utils.home_plugin_path
        tmpPath = self.file.fileName()
        # make sure that the parent directory exists
        if not QDir(pluginDir).exists():
            QDir().mkpath(pluginDir)
        # if the target directory already exists as a link, remove the link without resolving:
        QFile(pluginDir + str(QDir.separator()) + self.plugin["id"]).remove()
        try:
            unzip(str(tmpPath), str(pluginDir))  # test extract. If fails, then exception will be raised and no removing occurs
            # removing old plugin files if exist
            removeDir(QDir.cleanPath(pluginDir + "/" + self.plugin["id"]))  # remove old plugin if exists
            unzip(str(tmpPath), str(pluginDir))  # final extract.
        except:
            self.mResult = self.tr("Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:") + "\n" + pluginDir
            self.reject()
            return
        try:
            # cleaning: removing the temporary zip file
            QFile(tmpPath).remove()
        except:
            pass
        self.close()

    # ----------------------------------------- #
    def abort(self):
        if self.reply.isRunning():
            self.reply.finished.disconnect()
            self.reply.abort()
            del self.reply
        self.mResult = self.tr("Aborted by user")
        self.reject()
class QgsPluginInstallerInstallingDialog(QDialog, Ui_QgsPluginInstallerInstallingDialogBase):
    # ----------------------------------------- #

    def __init__(self, parent, plugin):
        QDialog.__init__(self, parent)
        self.setupUi(self)
        self.plugin = plugin
        self.mResult = ""
        self.progressBar.setRange(0, 0)
        self.progressBar.setFormat("%p%")
        self.labelName.setText(plugin["name"])
        self.buttonBox.clicked.connect(self.abort)

        self.url = QUrl(plugin["download_url"])
        self.redirectionCounter = 0

        fileName = plugin["filename"]
        tmpDir = QDir.tempPath()
        tmpPath = QDir.cleanPath(tmpDir + "/" + fileName)
        self.file = QFile(tmpPath)

        self.requestDownloading()

    def requestDownloading(self):
        self.request = QNetworkRequest(self.url)
        self.request.setAttribute(QNetworkRequest.Attribute(QgsNetworkRequestParameters.AttributeInitiatorClass), "QgsPluginInstallerInstallingDialog")
        authcfg = repositories.all()[self.plugin["zip_repository"]]["authcfg"]
        if authcfg and isinstance(authcfg, str):
            if not QgsApplication.authManager().updateNetworkRequest(
                    self.request, authcfg.strip()):
                self.mResult = self.tr(
                    "Update of network request with authentication "
                    "credentials FAILED for configuration '{0}'").format(authcfg)
                self.request = None

        if self.request is not None:
            self.reply = QgsNetworkAccessManager.instance().get(self.request)
            self.reply.downloadProgress.connect(self.readProgress)
            self.reply.finished.connect(self.requestFinished)

            self.stateChanged(4)

    def exec_(self):
        if self.request is None:
            return QDialog.Rejected

        QDialog.exec_(self)

    # ----------------------------------------- #
    def result(self):
        return self.mResult

    # ----------------------------------------- #
    def stateChanged(self, state):
        messages = [
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Installing…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Resolving host name…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Connecting…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Host connected. Sending request…"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Downloading data…"),
            self.tr("Idle"),
            QCoreApplication.translate('QgsPluginInstallerInstallingDialog', "Closing connection…"),
            self.tr("Error")
        ]
        self.labelState.setText(messages[state])

    # ----------------------------------------- #
    def readProgress(self, done, total):
        if total > 0:
            self.progressBar.setMaximum(total)
            self.progressBar.setValue(done)

    # ----------------------------------------- #
    def requestFinished(self):
        reply = self.sender()
        self.buttonBox.setEnabled(False)
        if reply.error() != QNetworkReply.NoError:
            self.mResult = reply.errorString()
            if reply.error() == QNetworkReply.OperationCanceledError:
                self.mResult += "<br/><br/>" + QCoreApplication.translate("QgsPluginInstaller", "If you haven't canceled the download manually, it might be caused by a timeout. In this case consider increasing the connection timeout value in QGIS options.")
            self.reject()
            reply.deleteLater()
            return
        elif reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) in (301, 302):
            redirectionUrl = reply.attribute(QNetworkRequest.RedirectionTargetAttribute)
            self.redirectionCounter += 1
            if self.redirectionCounter > 4:
                self.mResult = QCoreApplication.translate("QgsPluginInstaller", "Too many redirections")
                self.reject()
                reply.deleteLater()
                return
            else:
                if redirectionUrl.isRelative():
                    redirectionUrl = reply.url().resolved(redirectionUrl)
                # Fire a new request and exit immediately in order to quietly destroy the old one
                self.url = redirectionUrl
                self.requestDownloading()
                reply.deleteLater()
                return

        self.file.open(QFile.WriteOnly)
        self.file.write(reply.readAll())
        self.file.close()
        self.stateChanged(0)
        reply.deleteLater()
        pluginDir = qgis.utils.home_plugin_path
        tmpPath = self.file.fileName()
        # make sure that the parent directory exists
        if not QDir(pluginDir).exists():
            QDir().mkpath(pluginDir)
        # if the target directory already exists as a link, remove the link without resolving:
        QFile(pluginDir + str(QDir.separator()) + self.plugin["id"]).remove()
        try:
            unzip(str(tmpPath), str(pluginDir))  # test extract. If fails, then exception will be raised and no removing occurs
            # removing old plugin files if exist
            removeDir(QDir.cleanPath(pluginDir + "/" + self.plugin["id"]))  # remove old plugin if exists
            unzip(str(tmpPath), str(pluginDir))  # final extract.
        except:
            self.mResult = self.tr("Failed to unzip the plugin package. Probably it's broken or missing from the repository. You may also want to make sure that you have write permission to the plugin directory:") + "\n" + pluginDir
            self.reject()
            return
        try:
            # cleaning: removing the temporary zip file
            QFile(tmpPath).remove()
        except:
            pass
        self.close()

    # ----------------------------------------- #
    def abort(self):
        if self.reply.isRunning():
            self.reply.finished.disconnect()
            self.reply.abort()
            del self.reply
        self.mResult = self.tr("Aborted by user")
        self.reject()
class ConnectDockWidget(BASE, WIDGET):

    def __init__(self, parent=None, visible=False):
        super(ConnectDockWidget, self).__init__(parent)
        self.setupUi(self)

        self.loggedIn = False
        self.token = None

        self.progressBar.hide()

        self.setVisible(visible)

        self.setWindowIcon(QIcon(os.path.join(pluginPath, 'icons', 'connect.svg')))
        self.svgLogo.load(os.path.join(pluginPath, 'icons', 'connect-logo.svg'))

        self.lblSmallLogo.setPixmap(QPixmap(os.path.join(pluginPath, 'icons', 'connect.png')))
        self.lblSmallLogo.hide()

        btnOk = self.buttonBox.button(QDialogButtonBox.Ok)
        btnOk.setText('Login')

        # setup tab bar
        self.tabsContent.addTab('Knowledge')
        self.tabsContent.addTab('Data')
        self.tabsContent.addTab('Plugins')
        self.tabsContent.setDocumentMode(True)
        self.tabsContent.setDrawBase(False)
        self._toggleCategoriesSelector(True)
        self.tabsContent.setCurrentIndex(0)
        self.tabsContent.currentChanged.connect(self.tabChanged)

        self.buttonBox.helpRequested.connect(self.showHelp)
        self.buttonBox.accepted.connect(self.logIn)
        self.btnSignOut.clicked.connect(self.showLogin)

        self.labelLevel.linkActivated.connect(self.showLogin)
        self.leSearch.buttonClicked.connect(self.search)
        self.leSearch.returnPressed.connect(self.search)
        self.connectWidget.rememberStateChanged.connect(self.updateSettings)

        self.webView.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
        cssFile = os.path.join(pluginPath, "resources", "search.css")
        with open(cssFile) as f:
            content = f.read()

        self.css = content.replace("#PLUGIN_PATH#", QUrl.fromLocalFile(pluginPath).toString())

        self.webView.linkClicked.connect(self.linkClicked)

        for cat, cls in connect.categories.items():
            self.cmbContentType.addItem(cls[1], cat)

        settings = QSettings()
        settings.beginGroup(reposGroup)
        self.authId = settings.value(boundlessRepoName + '/authcfg', '')
        settings.endGroup()
        if self.authId not in QgsAuthManager.instance().configIds():
            self.authId = ''
            utils.setRepositoryAuth(self.authId)

        self._toggleSearchControls(True)
        self.showLogin()

    def showEvent(self, event):
        fillCredentials = pluginSetting("rememberCredentials")
        if self.authId != '' and fillCredentials and not self.loggedIn:
            authConfig = QgsAuthMethodConfig()
            if self.authId in QgsAuthManager.instance().configIds():
                QgsAuthManager.instance().loadAuthenticationConfig(self.authId, authConfig, True)
                username = authConfig.config('username')
                password = authConfig.config('password')
            else:
                self.authId = ''
                utils.setRepositoryAuth(self.authId)
                self._showMessage('Could not find Connect credentials in the database.',
                                  QgsMessageBar.WARNING)
                username = ''
                password = ''

            self.connectWidget.setLogin(username)
            self.connectWidget.setPassword(password)

        BASE.showEvent(self, event)

    def keyPressEvent(self, event):
        if self.stackedWidget.currentIndex() == 0:
            if event.key() in [Qt.Key_Return, Qt.Key_Enter]:
                self.logIn()

        BASE.keyPressEvent(self, event)

    def showLogin(self):
        self.stackedWidget.setCurrentIndex(0)
        self.webView.setVisible(False)
        self.webView.setHtml("")
        self.leSearch.setText("")
        self.tabsContent.setCurrentIndex(0)
        self.svgLogo.show()
        self.lblSmallLogo.hide()
        connect.resetToken()
        self.token = None

        fillCredentials = pluginSetting("rememberCredentials")
        if fillCredentials:
            self.connectWidget.setRemember(Qt.Checked)

            username = ""
            password = ""
            if self.authId != "":
                authConfig = QgsAuthMethodConfig()
                if self.authId in QgsAuthManager.instance().configIds():
                    QgsAuthManager.instance().loadAuthenticationConfig(self.authId, authConfig, True)
                    username = authConfig.config("username")
                    password = authConfig.config("password")
                self.connectWidget.setLogin(username)
                self.connectWidget.setPassword(password)
        else:
            self.connectWidget.setRemember(Qt.Unchecked)
            self.connectWidget.setLogin("")
            self.connectWidget.setPassword("")

    def showHelp(self):
        webbrowser.open_new("file://{}".format(os.path.join(pluginPath, "docs", "html", "index.html")))

    def linkClicked(self, url):
        name = url.toString()
        if name == "next":
            self.search(self.searchPage + 1)
        elif name == "previous":
            self.search(self.searchPage - 1)
        elif name.startswith("canvas"):
            content = self.searchResults[name]
            content.addToCanvas(self.roles)
        elif name.startswith("project"):
            content = self.searchResults[name]
            content.addToDefaultProject(self.roles)
        else:
            content = self.searchResults[name]
            content.open(self.roles)

    def logIn(self):
        if self.connectWidget.login().strip() == "" or self.connectWidget.password().strip() == "":
            self._showMessage("Please enter valid Connect credentials "
                              "to use plugin.")
            return

        setPluginSetting("rememberCredentials", self.connectWidget.remember())

        utils.addBoundlessRepository()

        self.request = QNetworkRequest(QUrl(authEndpointUrl))
        httpAuth = base64.b64encode(b"%s:%s" % (self.connectWidget.login().strip(), self.connectWidget.password().strip())).decode("ascii")
        self.request.setRawHeader('Authorization', 'Basic {}'.format(httpAuth))
        QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
        self.token = connect.getToken(self.connectWidget.login().strip(), self.connectWidget.password().strip())
        if self.token is None:
            QApplication.restoreOverrideCursor()
            QMessageBox.warning(self, "Error!", "Can not get token. Please check you credentials and endpoint URL in plugin settings.")
            return
        self.reply = QgsNetworkAccessManager.instance().get(self.request)
        self.reply.finished.connect(self.requestFinished)

    def search(self, page=0):
        if self.tabsContent.currentIndex() == 0:
            categories = self.cmbContentType.selectedData(Qt.UserRole)
            if len(categories) == 0:
                categories = list(connect.categories.keys())
            cat = ','.join(categories)
            self._findContent(cat, page)
        elif self.tabsContent.currentIndex() == 1:
            if oauth2_supported():
                self._findBasemaps()
        elif self.tabsContent.currentIndex() == 2:
            self._findPlugins()

        self.svgLogo.hide()
        self.lblSmallLogo.show()

    def _getSearchHtml(self, body):
        html = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
                              <html>
                              <head>
                              <style>
                              {}
                              </style>
                              </head>
                              <body>
                              {}
                              </body>
                              </html>'''.format(self.css, body)
        return html

    def _findContent(self, category, page=0):
        if self.token is None:
            self._showMessage("Seems you have no Connect token. Login with valid Connect credentials and try again.",
                              QgsMessageBar.WARNING)
            return

        text = self.leSearch.text().strip()
        self.searchPage = page
        try:
            self._toggleSearchProgress()
            results = execute(lambda: connect.search(text, category, self.searchPage, self.token))
            if results:
                self.searchResults = {r.url:r for r in results}
                body = "<ul>"
                for r in results:
                    body += "<li>%s</li>" % r.asHtmlEntry(self.roles)
                body += "</ul>"

                if len(results) == connect.RESULTS_PER_PAGE:
                    if self.searchPage == 0:
                        body += "<div class='pagination'><div class='next'><a href='next'>Next</a></div></div>"
                    else:
                        body += "<div class='pagination'><div class='prev'><a href='previous'>Prev</a></div><div class='next'><a href='next'>Next</a></div></div>"
                else:
                    if self.searchPage != 0:
                        body += "<div class='pagination'><div class='prev'><a href='previous'>Prev</a></div></div>"
            else:
                body = ""

            self.webView.setHtml(self._getSearchHtml(body))
            self.webView.setVisible(True)
            self._toggleSearchProgress(False)
        except Exception as e:
            self._toggleSearchProgress(False)
            self.webView.setHtml("")
            self._showMessage("There has been a problem performing the search:\n{}".format(str(e.args[0])),
                              QgsMessageBar.WARNING)

    def _findPlugins(self):
        if self.token is None:
            self._showMessage("Seems you have no Connect token. Login with valid Connect credentials and try again.",
                              QgsMessageBar.WARNING)
            return

        text = self.leSearch.text().strip()
        try:
            self._toggleSearchProgress()
            results = execute(lambda: connect.findAll(text, "PLUG", self.token))
            body = "<h1>{} results</h1><hr/>".format(len(results))
            if results:
                self.searchResults = {r.url:r for r in results}
                body += "<ul>"
                for r in results:
                    body += "<li>%s</li>" % r.asHtmlEntry(self.roles)
                body += "</ul>"

            self.webView.setHtml(self._getSearchHtml(body))
            self.webView.setVisible(True)
            self._toggleSearchProgress(False)
        except Exception as e:
            self._toggleSearchProgress(False)
            self.webView.setHtml("")
            self._showMessage("There has been a problem performing the search:\n{}".format(str(e.args[0])),
                              QgsMessageBar.WARNING)

    def _findBasemaps(self):
        if self.token is None:
            self._showMessage("Seems you have no Connect token. Login with valid Connect credentials and try again.",
                              QgsMessageBar.WARNING)
            return

        text = self.leSearch.text().strip()
        try:
            results = execute(lambda: connect.searchBasemaps(text, self.token))
            body = "<h1>{} results</h1><hr/>".format(len(results))
            if results:
                self.searchResults = {"canvas"+r.url:r for r in results}
                self.searchResults.update({"project"+r.url:r for r in results})
                body += "<ul>"
                for r in results:
                    body += "<li>%s</li>" % r.asHtmlEntry(self.roles)
                body += "</ul>"
            self.webView.setHtml(self._getSearchHtml(body))
            self.webView.setVisible(True)
        except Exception as e:
            self._toggleSearchProgress(False)
            self.webView.setHtml("")
            self._showMessage("There has been a problem performing the search:\n{}".format(str(e.args[0])),
                              QgsMessageBar.WARNING)

    def requestFinished(self):
        QApplication.restoreOverrideCursor()
        reply = self.sender()
        visible = True
        if reply.error() != QNetworkReply.NoError:
            if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 401:
                msg = 'Your credentials seem invalid.\n' \
                      'You will not be able to access any content.\n' \
                      'Please enter valid Connect credentials to use plugin.'
            else:
                msg = 'An error occurred when validating your ' \
                      'credentials. Server responded:\n{}.\n' \
                      'You will not be able to access any content.\n' \
                      'Please enter valid Connect credentials to use plugin'.format(reply.errorString())
            QMessageBox.warning(self, 'Error!', msg)
            return
        else:
            self.btnSignOut.setText("Logout")
            self.saveOrUpdateAuthId()
            self.roles = json.loads(str(reply.readAll()))

            # if this is first login ask if user wants to have basemap
            settings = QSettings()
            firstLogin = settings.value('boundlessconnect/firstLogin', True, bool)
            if firstLogin:
                settings.setValue('boundlessconnect/firstLogin', False)
                if oauth2_supported() and basemaputils.canAccessBasemap(self.roles):
                    ret = QMessageBox.question(self,
                                               self.tr('Base Maps'),
                                               self.tr('Would you like to add Boundless basemap '
                                                       'to your default project? This option can '
                                                       'be disabled at any time in the settings.'),
                                               QMessageBox.Yes | QMessageBox.No,
                                               QMessageBox.No)
                    if ret == QMessageBox.Yes:
                        if self.token is None:
                            self._showMessage("Seems you have no Connect token. Login with valid Connect credentials and try again.",
                                              QgsMessageBar.WARNING)
                            return

                        if self.installBaseMap():
                            pass

        execute(connect.loadPlugins)
        self.stackedWidget.setCurrentIndex(1)
        self.labelLevel.setVisible(visible)
        self.labelLevel.setText("Logged in as: <b>%s</b>" % self.connectWidget.login())

        self.loggedIn = True

        cat = ",".join(list(connect.categories.keys()))
        self._findContent(cat)

    def saveOrUpdateAuthId(self):
        if self.authId == '':
            authConfig = QgsAuthMethodConfig('Basic')
            self.authId = QgsAuthManager.instance().uniqueConfigId()
            authConfig.setId(self.authId)
            authConfig.setConfig('username', self.connectWidget.login().strip())
            authConfig.setConfig('password', self.connectWidget.password().strip())
            authConfig.setName('Boundless Connect Portal')

            authConfig.setUri(pluginSetting('repoUrl'))

            if QgsAuthManager.instance().storeAuthenticationConfig(authConfig):
                utils.setRepositoryAuth(self.authId)
            else:
                self._showMessage('Unable to save credentials.', QgsMessageBar.WARNING)
        else:
            authConfig = QgsAuthMethodConfig()
            QgsAuthManager.instance().loadAuthenticationConfig(self.authId, authConfig, True)
            authConfig.setConfig('username', self.connectWidget.login().strip())
            authConfig.setConfig('password', self.connectWidget.password().strip())
            QgsAuthManager.instance().updateAuthenticationConfig(authConfig)

        # also setup OAuth2 configuration if possible
        if oauth2_supported():
            endpointUrl = "{}/token/oauth?version={}".format(pluginSetting("connectEndpoint"), pluginSetting("apiVersion"))
            setup_oauth(self.connectWidget.login().strip(), self.connectWidget.password().strip(), endpointUrl)

    def tabChanged(self, index):
        if index == 0:
            self._toggleCategoriesSelector(True)
            self._toggleSearchControls(True)
            self.webView.setHtml("")
            categories = self.cmbContentType.selectedData(Qt.UserRole)
            if len(categories) == 0:
                categories = list(connect.categories.keys())
            cat = ','.join(categories)
            self._findContent(cat)
        elif index == 1:
            self._toggleCategoriesSelector(False)
            self._toggleSearchControls(oauth2_supported())
            self.webView.setHtml("")
            if oauth2_supported():
                self._findBasemaps()
        elif index == 2:
            self._toggleCategoriesSelector(False)
            self._toggleSearchControls(True)
            self.webView.setHtml("")
            self._findPlugins()

    def _toggleCategoriesSelector(self, visible):
        self.lblCategorySearch.setVisible(visible)
        self.cmbContentType.setVisible(visible)

    def _toggleSearchControls(self, enabled):
        self.leSearch.setEnabled(enabled)
        self.lblOAuthWarning.setVisible(not enabled)

    def installBaseMap(self):
        authcfg = get_oauth_authcfg()
        if authcfg is None:
            self._showMessage('Could not find a valid authentication configuration!',
                              QgsMessageBar.WARNING)
            return False

        authId = authcfg.id()
        mapBoxStreets = basemaputils.getMapBoxStreetsMap(self.token)

        if os.path.isfile(basemaputils.defaultProjectPath()):
            # default project already exists, make a backup copy
            backup = basemaputils.defaultProjectPath().replace(
                '.qgs', '-%s.qgs' % datetime.now().strftime('%Y-%m-%d-%H_%M_%S'))
            shutil.copy2(basemaputils.defaultProjectPath(), backup)
            self._showMessage("A backup copy of the previous default project "
                              "has been saved to {}".format(backup))

            msgBox = QMessageBox()
            msgBox.setIcon(QMessageBox.Question)
            msgBox.setText("A default project already exists.  Do you "
                           "wish to add the Boundless basemap to your "
                           "existing default project or create a new "
                           "default project?")
            btnAdd = msgBox.addButton("Add", QMessageBox.ActionRole)
            btnCreateNew = msgBox.addButton("Create New", QMessageBox.ActionRole)
            msgBox.exec_()
            if msgBox.clickedButton() == btnAdd:
                if not basemaputils.addToDefaultProject([mapBoxStreets], ["Mapbox Streets"], authId):
                    self._showMessage("Could not update default project with basemap!",
                                      QgsMessageBar.WARNING)
                    return False
            elif msgBox.clickedButton() == btnCreateNew:
                template = basemaputils.PROJECT_DEFAULT_TEMPLATE

                prj = basemaputils.createDefaultProject([mapBoxStreets], ["Mapbox Streets"],
                                                        template, authId)
                if prj is None or prj == '':
                    self._showMessage("Could not create a valid default project from the template '{}'!".format(template),
                                      QgsMessageBar.WARNING)
                    return False

                if not basemaputils.writeDefaultProject(prj):
                    self._showMessage("Could not write the default project on disk!",
                                      QgsMessageBar.WARNING)
                    return False
        else:
            # no default project, create one
            template = basemaputils.PROJECT_DEFAULT_TEMPLATE

            prj = basemaputils.createDefaultProject([mapBoxStreets], ["Mapbox Streets"],
                                               template, authId)
            if prj is None or prj == '':
                self._showMessage("Could not create a valid default project from the template '{}'!".format(template),
                                  QgsMessageBar.WARNING)
                return False

            if not basemaputils.writeDefaultProject(prj):
                self._showMessage("Could not write the default project on disk!",
                                  QgsMessageBar.WARNING)
                return False

        self._showMessage("Basemap added to the default project.")
        return True

    def updateSettings(self, state):
        if state == Qt.Checked:
            setPluginSetting("rememberCredentials", True)
        else:
            setPluginSetting("rememberCredentials", False)

    def _toggleSearchProgress(self, show=True):
        if show:
            self.progressBar.setRange(0, 0)
            self.progressBar.show()
        else:
            self.progressBar.setRange(0, 100)
            self.progressBar.reset()
            self.progressBar.hide()

    def _showMessage(self, message, level=QgsMessageBar.INFO):
        iface.messageBar().pushMessage(
            message, level, iface.messageTimeout())
Example #34
0
    def request(self,
                url,
                method="GET",
                body=None,
                headers=None,
                redirections=DEFAULT_MAX_REDIRECTS,
                connection_type=None):
        """
        Make a network request by calling QgsNetworkAccessManager.
        redirections argument is ignored and is here only for httplib2 compatibility.
        """
        self.msg_log(u'http_call request: {0}'.format(url))
        self.http_call_result = Response({
            'status': 0,
            'status_code': 0,
            'status_message': '',
            'text': '',
            'ok': False,
            'headers': {},
            'reason': '',
            'exception': None,
        })
        req = QNetworkRequest()
        # Avoid double quoting form QUrl
        if PYTHON_VERSION >= 3:
            url = urllib.parse.unquote(url)
        else:
            url = urllib2.unquote(url)
        req.setUrl(QUrl(url))

        if self.cookie is not None:
            if headers is not None:
                headers['Cookie'] = self.cookie
            else:
                headers = {'Cookie': self.cookie}

        if self.basicauth is not None:
            if headers is not None:
                headers['Authorization'] = self.basicauth
            else:
                headers = {'Authorization': self.basicauth}

        if headers is not None:
            # This fixes a wierd error with compressed content not being correctly
            # inflated.
            # If you set the header on the QNetworkRequest you are basically telling
            # QNetworkAccessManager "I know what I'm doing, please don't do any content
            # encoding processing".
            # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
            try:
                del headers['Accept-Encoding']
            except KeyError:
                pass
            for k, v in headers.items():
                if PYTHON_VERSION >= 3:
                    if isinstance(k, str):
                        k = k.encode('utf-8')
                    if isinstance(v, str):
                        v = v.encode('utf-8')
                req.setRawHeader(k, v)

        if self.authid:
            self.msg_log("Update request w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkRequest(req, self.authid)
        if self.reply is not None and self.reply.isRunning():
            self.reply.close()
        if method.lower() == 'delete':
            func = getattr(QgsNetworkAccessManager.instance(),
                           'deleteResource')
        else:
            func = getattr(QgsNetworkAccessManager.instance(), method.lower())
        # Calling the server ...
        # Let's log the whole call for debugging purposes:
        self.msg_log("Sending %s request to %s" %
                     (method.upper(), req.url().toString()))
        headers = {str(h): str(req.rawHeader(h)) for h in req.rawHeaderList()}
        for k, v in headers.items():
            self.msg_log("%s: %s" % (k, v))
        if method.lower() in ['post', 'put']:
            if PYTHON_VERSION >= 3:
                if isinstance(body, str):
                    body = body.encode('utf-8')
            self.reply = func(req, body)
        else:
            self.reply = func(req)
        if self.authid:
            self.msg_log("Update reply w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkReply(
                self.reply, self.authid)

        self.reply.sslErrors.connect(self.sslErrors)
        self.reply.finished.connect(self.replyFinished)

        # Call and block
        self.el = QEventLoop()
        self.reply.finished.connect(self.el.quit)
        self.reply.downloadProgress.connect(self.downloadProgress)

        # Catch all exceptions (and clean up requests)
        try:
            self.el.exec_()
            # Let's log the whole response for debugging purposes:
            self.msg_log("Got response %s %s from %s" % \
                        (self.http_call_result.status_code,
                         self.http_call_result.status_message,
                         self.reply.url().toString()))
            headers = {
                str(h): str(self.reply.rawHeader(h))
                for h in self.reply.rawHeaderList()
            }
            for k, v in headers.items():
                self.msg_log("%s: %s" % (k, v))
            if len(self.http_call_result.text) < 1024:
                self.msg_log("Payload :\n%s" % self.http_call_result.text)
            else:
                self.msg_log("Payload is > 1 KB ...")
        except Exception as e:
            raise e
        finally:
            if self.reply is not None:
                if self.reply.isRunning():
                    self.reply.close()
                self.msg_log("Deleting reply ...")
                self.reply.deleteLater()
                self.reply = None
            else:
                self.msg_log("Reply was already deleted ...")
        if not self.http_call_result.ok:
            if self.http_call_result.exception and not self.exception_class:
                raise self.http_call_result.exception
            else:
                raise self.exception_class(self.http_call_result.reason)
        return (self.http_call_result, self.http_call_result.text)
    def is_source_service_valid(self):
        res = False
        msg = {'text': '', 'level': Qgis.Warning}
        url = self.txt_service_endpoint.text().strip()
        if url:
            with OverrideCursor(Qt.WaitCursor):
                self.qgis_utils.status_bar_message_emitted.emit(
                    "Checking source service availability (this might take a while)...",
                    0)
                QCoreApplication.processEvents()
                if self.qgis_utils.is_connected(TEST_SERVER):

                    nam = QNetworkAccessManager()
                    request = QNetworkRequest(QUrl(url))
                    reply = nam.get(request)

                    loop = QEventLoop()
                    reply.finished.connect(loop.quit)
                    loop.exec_()

                    allData = reply.readAll()
                    response = QTextStream(allData, QIODevice.ReadOnly)
                    status = reply.attribute(
                        QNetworkRequest.HttpStatusCodeAttribute)
                    if status == 200:
                        try:
                            data = json.loads(response.readAll())
                            if 'id' in data and data[
                                    'id'] == SOURCE_SERVICE_EXPECTED_ID:
                                res = True
                                msg['text'] = QCoreApplication.translate(
                                    "SettingsDialog",
                                    "The tested service is valid to upload files!"
                                )
                                msg['level'] = Qgis.Info
                            else:
                                res = False
                                msg['text'] = QCoreApplication.translate(
                                    "SettingsDialog",
                                    "The tested upload service is not compatible: no valid 'id' found in response."
                                )
                        except json.decoder.JSONDecodeError as e:
                            res = False
                            msg['text'] = QCoreApplication.translate(
                                "SettingsDialog",
                                "Response from the tested service is not compatible: not valid JSON found."
                            )
                    else:
                        res = False
                        msg['text'] = QCoreApplication.translate(
                            "SettingsDialog",
                            "There was a problem connecting to the server. The server might be down or the service cannot be reached at the given URL."
                        )
                else:
                    res = False
                    msg['text'] = QCoreApplication.translate(
                        "SettingsDialog",
                        "There was a problem connecting to Internet.")

                self.qgis_utils.clear_status_bar_emitted.emit()
        else:
            res = False
            msg['text'] = QCoreApplication.translate(
                "SettingsDialog", "Not valid service URL to test!")

        return (res, msg)
Example #36
0
def do_request(manager, lat, lng, api_key):
    
    url = f'https://reverse.geocoder.ls.hereapi.com/6.2/reversegeocode.json?prox={lat}%2C{lng}%2C250&mode=retrieveAddresses&maxresults=1&gen=9&apiKey={api_key}'
    QgsMessageLog.logMessage(f'Making a request to {url}')
    req = QNetworkRequest(QUrl(url))
    manager.get(req)
    def request(self, url, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None, blocking=True):
        """
        Make a network request by calling QgsNetworkAccessManager.
        redirections argument is ignored and is here only for httplib2 compatibility.
        """
        self.msg_log(u'http_call request: {0}'.format(url))

        self.blocking_mode = blocking
        req = QNetworkRequest()
        # Avoid double quoting form QUrl
        url = urllib.parse.unquote(url)
        req.setUrl(QUrl(url))
        if headers is not None:
            # This fixes a wierd error with compressed content not being correctly
            # inflated.
            # If you set the header on the QNetworkRequest you are basically telling
            # QNetworkAccessManager "I know what I'm doing, please don't do any content
            # encoding processing".
            # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
            try:
                del headers['Accept-Encoding']
            except KeyError:
                pass
            for k, v in list(headers.items()):
                self.msg_log("Setting header %s to %s" % (k, v))
                req.setRawHeader(k, v)
        if self.authid:
            self.msg_log("Update request w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkRequest(req, self.authid)
        if self.reply is not None and self.reply.isRunning():
            self.reply.close()
        if method.lower() == 'delete':
            func = getattr(QgsNetworkAccessManager.instance(), 'deleteResource')
        else:
            func = getattr(QgsNetworkAccessManager.instance(), method.lower())
        # Calling the server ...
        # Let's log the whole call for debugging purposes:
        self.msg_log("Sending %s request to %s" % (method.upper(), req.url().toString()))
        self.on_abort = False
        headers = {str(h): str(req.rawHeader(h)) for h in req.rawHeaderList()}
        for k, v in list(headers.items()):
            self.msg_log("%s: %s" % (k, v))
        if method.lower() in ['post', 'put']:
            if isinstance(body, file):
                body = body.read()
            self.reply = func(req, body)
        else:
            self.reply = func(req)
        if self.authid:
            self.msg_log("Update reply w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkReply(self.reply, self.authid)

        # necessary to trap local timout manage by QgsNetworkAccessManager
        # calling QgsNetworkAccessManager::abortRequest
        QgsNetworkAccessManager.instance().requestTimedOut.connect(self.requestTimedOut)

        self.reply.sslErrors.connect(self.sslErrors)
        self.reply.finished.connect(self.replyFinished)
        self.reply.downloadProgress.connect(self.downloadProgress)

        # block if blocking mode otherwise return immediatly
        # it's up to the caller to manage listeners in case of no blocking mode
        if not self.blocking_mode:
            return (None, None)

        # Call and block
        self.el = QEventLoop()
        self.reply.finished.connect(self.el.quit)

        # Catch all exceptions (and clean up requests)
        try:
            self.el.exec_(QEventLoop.ExcludeUserInputEvents)
        except Exception as e:
            raise e

        if self.reply:
            self.reply.finished.disconnect(self.el.quit)

        # emit exception in case of error
        if not self.http_call_result.ok:
            if self.http_call_result.exception and not self.exception_class:
                raise self.http_call_result.exception
            else:
                raise self.exception_class(self.http_call_result.reason)

        return (self.http_call_result, self.http_call_result.content)
Example #38
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()))
Example #39
0
    def request(self,
                url,
                method="GET",
                body=None,
                headers=None,
                redirections=DEFAULT_MAX_REDIRECTS,
                connection_type=None,
                blocking=True):
        """
        Make a network request by calling QgsNetworkAccessManager.
        redirections argument is ignored and is here only for httplib2 compatibility.
        """
        self.msg_log(u'http_call request: {0}'.format(url))

        self.blocking_mode = blocking
        req = QNetworkRequest()
        # Avoid double quoting form QUrl
        url = urllib.parse.unquote(url)
        req.setUrl(QUrl(url))
        if headers is not None:
            # This fixes a wierd error with compressed content not being correctly
            # inflated.
            # If you set the header on the QNetworkRequest you are basically telling
            # QNetworkAccessManager "I know what I'm doing, please don't do any content
            # encoding processing".
            # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
            try:
                del headers['Accept-Encoding']
            except KeyError:
                pass
            for k, v in list(headers.items()):
                self.msg_log("Setting header %s to %s" % (k, v))
                if k and v:
                    req.setRawHeader(k.encode(), v.encode())
        if self.authid:
            self.msg_log("Update request w/ authid: {0}".format(self.authid))
            self.auth_manager().updateNetworkRequest(req, self.authid)
        if self.reply is not None and self.reply.isRunning():
            self.reply.close()
        if method.lower() == 'delete':
            func = getattr(QgsNetworkAccessManager.instance(),
                           'deleteResource')
        else:
            func = getattr(QgsNetworkAccessManager.instance(), method.lower())
        # Calling the server ...
        # Let's log the whole call for debugging purposes:
        self.msg_log("Sending %s request to %s" %
                     (method.upper(), req.url().toString()))
        self.on_abort = False
        headers = {str(h): str(req.rawHeader(h)) for h in req.rawHeaderList()}
        for k, v in list(headers.items()):
            self.msg_log("%s: %s" % (k, v))
        if method.lower() in ['post', 'put']:
            if isinstance(body, io.IOBase):
                body = body.read()
            if isinstance(body, str):
                body = body.encode()
            if isinstance(body, dict):
                body = str(json.dumps(body)).encode(encoding='utf-8')
            self.reply = func(req, body)
        else:
            self.reply = func(req)
        if self.authid:
            self.msg_log("Update reply w/ authid: {0}".format(self.authid))
            self.auth_manager().updateNetworkReply(self.reply, self.authid)

        QgsNetworkAccessManager.instance().setTimeout(int(self.timeout) * 1000)

        # necessary to trap local timeout manage by QgsNetworkAccessManager
        # calling QgsNetworkAccessManager::abortRequest
        QgsNetworkAccessManager.instance().requestTimedOut.connect(
            self.requestTimedOut)

        self.reply.sslErrors.connect(self.sslErrors)
        self.reply.finished.connect(self.replyFinished)
        self.reply.downloadProgress.connect(self.downloadProgress)

        # block if blocking mode otherwise return immediatly
        # it's up to the caller to manage listeners in case of no blocking mode
        if not self.blocking_mode:
            return (None, None)

        # Call and block
        self.el = QEventLoop()
        self.reply.finished.connect(self.el.quit)

        # Catch all exceptions (and clean up requests)
        try:
            self.el.exec_(QEventLoop.ExcludeUserInputEvents)
        except Exception as e:
            raise e

        if self.reply:
            self.reply.finished.disconnect(self.el.quit)

        # emit exception in case of error
        if not self.http_call_result.ok:
            if self.http_call_result.exception and not self.exception_class:
                raise self.http_call_result.exception
            else:
                raise self.exception_class(self.http_call_result.reason)

        return (self.http_call_result, self.http_call_result.content)
Example #40
0
    def upload_files(self, layer, field_index, features):
        """
        Upload given features' source files to remote server and return a dict
        formatted as changeAttributeValues expects to update 'datos' attribute
        to a remote location.
        """
        if not QSettings().value(
                'Asistente-LADM_COL/sources/document_repository', False, bool):
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "The source files were not uploaded to the document repository because you have that option unchecked. You can still upload the source files later using the 'Upload Pending Source Files' menu."
                ), Qgis.Info, 10)
            return dict()

        # Test if we have Internet connection and a valid service
        dlg = self.qgis_utils.get_settings_dialog()
        res, msg = dlg.is_source_service_valid()

        if not res:
            msg['text'] = QCoreApplication.translate(
                "SourceHandler",
                "No file could be uploaded to the document repository. You can do it later from the 'Upload Pending Source Files' menu. Reason: {}"
            ).format(msg['text'])
            self.message_with_duration_emitted.emit(
                msg['text'], Qgis.Info,
                20)  # The data is still saved, so always show Info msg
            return dict()

        file_features = [
            feature for feature in features if not feature[field_index] == NULL
            and os.path.isfile(feature[field_index])
        ]
        total = len(features)
        not_found = total - len(file_features)

        upload_dialog = UploadProgressDialog(len(file_features), not_found)
        upload_dialog.show()
        count = 0
        upload_errors = 0
        new_values = dict()

        for feature in file_features:
            data_url = feature[field_index]
            file_name = os.path.basename(data_url)

            nam = QNetworkAccessManager()
            #reply.downloadProgress.connect(upload_dialog.update_current_progress)

            multiPart = QHttpMultiPart(QHttpMultiPart.FormDataType)
            textPart = QHttpPart()
            textPart.setHeader(QNetworkRequest.ContentDispositionHeader,
                               QVariant("form-data; name=\"driver\""))
            textPart.setBody(QByteArray().append('Local'))

            filePart = QHttpPart()
            filePart.setHeader(
                QNetworkRequest.ContentDispositionHeader,
                QVariant("form-data; name=\"file\"; filename=\"{}\"".format(
                    file_name)))
            file = QFile(data_url)
            file.open(QIODevice.ReadOnly)

            filePart.setBodyDevice(file)
            file.setParent(
                multiPart
            )  # we cannot delete the file now, so delete it with the multiPart

            multiPart.append(filePart)
            multiPart.append(textPart)

            service_url = '/'.join([
                QSettings().value(
                    'Asistente-LADM_COL/sources/service_endpoint',
                    DEFAULT_ENDPOINT_SOURCE_SERVICE),
                SOURCE_SERVICE_UPLOAD_SUFFIX
            ])
            request = QNetworkRequest(QUrl(service_url))
            reply = nam.post(request, multiPart)
            #reply.uploadProgress.connect(upload_dialog.update_current_progress)
            reply.error.connect(self.error_returned)
            multiPart.setParent(reply)

            # We'll block execution until we get response from the server
            loop = QEventLoop()
            reply.finished.connect(loop.quit)
            loop.exec_()

            response = reply.readAll()
            data = QTextStream(response, QIODevice.ReadOnly)
            content = data.readAll()

            if content is None:
                self.log.logMessage(
                    "There was an error uploading file '{}'".format(data_url),
                    PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            try:
                response = json.loads(content)
            except json.decoder.JSONDecodeError:
                self.log.logMessage(
                    "Couldn't parse JSON response from server for file '{}'!!!"
                    .format(data_url), PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            if 'error' in response:
                self.log.logMessage(
                    "STATUS: {}. ERROR: {} MESSAGE: {} FILE: {}".format(
                        response['status'], response['error'],
                        response['message'], data_url), PLUGIN_NAME,
                    Qgis.Critical)
                upload_errors += 1
                continue

            reply.deleteLater()

            if 'url' not in response:
                self.log.logMessage(
                    "'url' attribute not found in JSON response for file '{}'!"
                    .format(data_url), PLUGIN_NAME, Qgis.Critical)
                upload_errors += 1
                continue

            url = self.get_file_url(response['url'])
            new_values[feature.id()] = {field_index: url}

            count += 1
            upload_dialog.update_total_progress(count)

        if not_found > 0:
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} records {} not uploaded to the document repository because {} file path is NULL or it couldn't be found in the local disk!"
                ).format(
                    not_found, total,
                    QCoreApplication.translate("SourceHandler", "was")
                    if not_found == 1 else QCoreApplication.translate(
                        "SourceHandler", "were"),
                    QCoreApplication.translate("SourceHandler", "its")
                    if not_found == 1 else QCoreApplication.translate(
                        "SourceHandler", "their")), Qgis.Info, 0)
        if len(new_values):
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} files {} uploaded to the document repository and {} remote location stored in the database!"
                ).format(
                    len(new_values), total,
                    QCoreApplication.translate("SourceHandler", "was")
                    if len(new_values) == 1 else QCoreApplication.translate(
                        "SourceHandler", "were"),
                    QCoreApplication.translate("SourceHandler", "its")
                    if len(new_values) == 1 else QCoreApplication.translate(
                        "SourceHandler", "their")), Qgis.Info, 0)
        if upload_errors:
            self.message_with_duration_emitted.emit(
                QCoreApplication.translate(
                    "SourceHandler",
                    "{} out of {} files could not be uploaded to the document repository because of upload errors! See log for details."
                ).format(upload_errors, total), Qgis.Info, 0)

        return new_values