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
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
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
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
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
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']
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]
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' )
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()
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)
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()))
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.")
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
def __init__(self, url, method='GET', **data): self.manager = QNetworkAccessManager() self.method = method self.url = QUrl(url) self.request = QNetworkRequest(self.url)
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
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())
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)
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)
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()))
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)
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