Esempio n. 1
0
    def testFetchBadUrl(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(QUrl('http://x'))
        fetcher.finished.connect(self.contentLoaded)
        while not self.loaded:
            app.processEvents()

        r = fetcher.reply()
        assert r.error() != QNetworkReply.NoError
Esempio n. 2
0
    def testFetchUrlContent(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) + '/qgis_local_server/index.html'))
        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
Esempio n. 3
0
    def testFetchEncodedContent(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) + '/encoded_html.html'))
        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 chr(6040) in html
Esempio n. 4
0
    def testFetchEncodedContent(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(
            QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) +
                 '/encoded_html.html'))
        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 chr(6040) in html
    def testFetchUrlContent(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(
            QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) +
                 '/qgis_local_server/index.html'))
        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
Esempio n. 6
0
    def testDoubleFetch(self):
        fetcher = QgsNetworkContentFetcher()
        self.loaded = False
        fetcher.fetchContent(QUrl('http://www.qgis.org/'))
        # double fetch - this should happen before previous request finishes
        fetcher.fetchContent(QUrl('http://localhost:' + str(TestQgsNetworkContentFetcher.port) + '/qgis_local_server/index.html'))
        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
Esempio n. 7
0
class VersionChecker:

    def __init__(self, dialog: QDialog, url):
        """ Update the dialog when versions has been fetched. """
        self.dialog = dialog
        self.url = url
        self.fetcher = None
        self.json = None

    def fetch(self):
        """ Fetch the JSON file and call the function when it's finished. """
        self.fetcher = QgsNetworkContentFetcher()
        self.fetcher.finished.connect(self.request_finished)
        self.fetcher.fetchContent(QUrl(self.url))

    def request_finished(self):
        """ Dispatch the answer to update the GUI. """
        content = self.fetcher.contentAsString()
        if not content:
            return

        # Update the UI
        released_versions = json.loads(content)
        self.update_lwc_releases(released_versions)
        self.update_lwc_selector(released_versions)

        # Cache the file
        content += '\n'
        folder = lizmap_user_folder()
        with open(os.path.join(folder, "released_versions.json"), "w") as output:
            output.write(content)

    def update_lwc_selector(self, released_versions: dict):
        """ Update LWC selector showing outdated versions. """
        for i, json_version in enumerate(released_versions):
            if not json_version['maintained']:
                index = self.dialog.combo_lwc_version.findData(LwcVersions(json_version['branch']))
                text = self.dialog.combo_lwc_version.itemText(index)

                if i == 0:
                    # If it's the first item in the list AND not maintained, then it's the next LWC version
                    new_text = text + ' - ' + tr('Next')
                else:
                    new_text = text + ' - ' + tr('Not maintained')
                self.dialog.combo_lwc_version.setItemText(index, new_text)

    def update_lwc_releases(self, released_versions: dict):
        """ Update labels about latest releases. """
        template = (
            '<a href="https://github.com/3liz/lizmap-web-client/releases/tag/{tag}">'
            '{tag}   -    {date}'
            '</a>')

        i = 0
        for json_version in released_versions:
            qdate = QDate.fromString(
                json_version['latest_release_date'],
                "yyyy-MM-dd")
            date_string = qdate.toString(QLocale().dateFormat(QLocale.ShortFormat))
            if json_version['maintained']:
                if i == 0:
                    text = template.format(
                        tag=json_version['latest_release_version'],
                        date=date_string,
                    )
                    self.dialog.lwc_version_latest.setText(text)
                elif i == 1:
                    text = template.format(
                        tag=json_version['latest_release_version'],
                        date=date_string,
                    )
                    self.dialog.lwc_version_oldest.setText(text)
                i += 1
Esempio n. 8
0
class AutoSuggest(QObject):

    def __init__(self, geturl_func, parseresult_func, parent = None):
        QObject.__init__(self, parent)
        self.geturl_func = geturl_func
        self.parseresult_func = parseresult_func
        
        self.editor = parent
        self.networkFetcher = QgsNetworkContentFetcher()

        self.selectedObject = None
        self.isUnloaded = False

        self.popup = QTreeWidget(parent)
        #self.popup.setColumnCount(2)
        self.popup.setColumnCount(1)
        self.popup.setUniformRowHeights(True)
        self.popup.setRootIsDecorated(False)
        self.popup.setEditTriggers(QTreeWidget.NoEditTriggers)
        self.popup.setSelectionBehavior(QTreeWidget.SelectRows)
        self.popup.setFrameStyle(QFrame.Box | QFrame.Plain)
        self.popup.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        self.popup.header().hide()
        self.popup.installEventFilter(self)
        self.popup.setMouseTracking(True)

        #self.connect(self.popup, SIGNAL("itemClicked(QTreeWidgetItem*, int)"),
        #             self.doneCompletion)
        self.popup.itemClicked.connect( self.doneCompletion )

        self.popup.setWindowFlags(Qt.Popup)
        self.popup.setFocusPolicy(Qt.NoFocus)
        self.popup.setFocusProxy(parent)

        self.timer = QTimer(self)
        self.timer.setSingleShot(True)
        self.timer.setInterval(500)
        #self.connect(self.timer, SIGNAL("timeout()"), self.autoSuggest)
        self.timer.timeout.connect( self.autoSuggest )
        
        #self.connect(self.editor, SIGNAL("textEdited(QString)"), self.timer, SLOT("start()"))
        #self.editor.textEdited.connect( self.timer.start )
        self.editor.textEdited.connect( self.timer.start )
        #self.editor.textChanged.connect( self.timer.start )

        #self.connect(self.networkManager, SIGNAL("finished(QNetworkReply*)"),
        #             self.handleNetworkData)
        self.networkFetcher.finished.connect( self.handleNetworkData )

    def eventFilter(self, obj, ev):
        if obj != self.popup:
            return False

        if ev.type() == QEvent.MouseButtonPress:
            self.popup.hide()
            self.editor.setFocus()
            return True

        if ev.type() == QEvent.KeyPress:
            consumed = False
            key = ev.key()
            if key == Qt.Key_Enter or key == Qt.Key_Return:
                self.doneCompletion()
                consumed = True

            elif key == Qt.Key_Escape:
                self.editor.setFocus()
                self.popup.hide()
                consumed = True

            elif key in (Qt.Key_Up, Qt.Key_Down, Qt.Key_Home, Qt.Key_End,
                         Qt.Key_PageUp, Qt.Key_PageDown):
                pass

            else:
                self.editor.setFocus()
                self.editor.event(ev)
                self.popup.hide()

            return consumed

        return False

    def showCompletion(self, rows):
        # Rows is an iterable of tuples like [("text",object1),("text2", object2),...]
        pal = self.editor.palette()
        color = pal.color(QPalette.Disabled, QPalette.WindowText)

        self.popup.setUpdatesEnabled(False)
        self.popup.clear()
        if rows is None or len( rows ) < 1:
            return

        for row in rows:
            item = QTreeWidgetItem(self.popup)
            item.setText(0, row[0])
            #item.setText(1, hit['type'])
            item.setTextAlignment(1, Qt.AlignRight)
            item.setForeground(1, color)
            item.setData(2, Qt.UserRole, (row[1],)) # Try immutable py obj #http://stackoverflow.com/questions/9257422/how-to-get-the-original-python-data-from-qvariant

        self.popup.setCurrentItem(self.popup.topLevelItem(0))
        self.popup.resizeColumnToContents(0)
        #self.popup.resizeColumnToContents(1)
        self.popup.adjustSize()
        self.popup.setUpdatesEnabled(True)

        h = self.popup.sizeHintForRow(0) * min(15, len(rows)) + 3
        w = max(self.popup.width(), self.editor.width())
        self.popup.resize(w, h)

        self.popup.move(self.editor.mapToGlobal(QPoint(0, self.editor.height())))
        self.popup.setFocus()
        self.popup.show()

    def doneCompletion(self):
        self.timer.stop()
        self.popup.hide()
        self.editor.setFocus()
        item = self.popup.currentItem()
        if item:
            self.editor.setText(item.text(0) )
            obj =  item.data(2, Qt.UserRole) #.toPyObject()
            self.selectedObject = obj[0]
            e = QKeyEvent(QEvent.KeyPress, Qt.Key_Enter, Qt.NoModifier)
            QApplication.postEvent(self.editor, e)
            e = QKeyEvent(QEvent.KeyRelease, Qt.Key_Enter, Qt.NoModifier)
            QApplication.postEvent(self.editor, e)

    def preventSuggest(self):
        self.timer.stop()

    def autoSuggest(self):
        term = self.editor.text()
        if term:
            qurl = self.geturl_func( term )
            if qurl:
                # TODO: Cancel existing requests: http://qt-project.org/forums/viewthread/18073
                self.networkFetcher.fetchContent(qurl)  # QUrl(url)))

    def handleNetworkData(self):
        reply = self.networkFetcher.reply()
        if reply:
            if reply.error() == QNetworkReply.NoError:
                content = self.networkFetcher.contentAsString()
                rows = self.parseresult_func( content )
                self.showCompletion( rows )
            else:
                QgsApplication.messageLog().logMessage(
                'Server returned: ' + reply.error(), __package__
            )

    def unload( self ):
        # Avoid processing events after QGIS shutdown has begun
        self.popup.removeEventFilter(self)
        self.isUnloaded = True
Esempio n. 9
0
class DfConfig(QtCore.QObject):

    df_con_error = QtCore.pyqtSignal()
    df_settings_warning = QtCore.pyqtSignal()
    loaded = QtCore.pyqtSignal()

    def __init__(self, settings):
        super(DfConfig, self).__init__()
        self.settings = settings
        self.cached_df_qlr_filename = None
        self.allowed_df_services = {}
        self.df_qlr_file = None
        self.background_category = None
        self.categories = None

        # Network
        self._services_network_fetcher = QgsNetworkContentFetcher()
        self._qlr_network_fetcher = QgsNetworkContentFetcher()
        self._services_network_fetcher.finished.connect(
            self._handle_services_response)
        self._qlr_network_fetcher.finished.connect(self._handle_qlr_response)

    def begin_load(self):
        self.cached_df_qlr_filename = (
            self.settings.value("cache_path") +
            hashlib.md5(self.settings.value("token").encode()).hexdigest() +
            "_dataforsyning_data.qlr")
        self.allowed_df_services = {}
        if self.settings.is_set():
            try:
                self._request_services()
            except Exception as e:
                log_message(traceback.format_exc())
                self.df_con_error.emit()
                self.background_category = None
                self.categories = []
            self.debug_write_allowed_services()
        else:
            self.df_settings_warning.emit()
            self.background_category = None
            self.categories = []

    def _request_services(self):
        url_to_get = self.insert_token(DF_SERVICES_URL)
        self._services_network_fetcher.fetchContent(QUrl(url_to_get))

    def _handle_services_response(self):
        network_reply = self._services_network_fetcher.reply()

        if network_reply.error():
            self.background_category = None
            self.categories = []
            self.df_con_error.emit()
            log_message(
                f"Network error getting services from df. Error code : " +
                str(network_reply.error()))
            return
        response = str(network_reply.readAll(), "utf-8")
        doc = QtXml.QDomDocument()
        doc.setContent(response)
        service_types = doc.documentElement().childNodes()
        i = 0
        allowed = {}
        allowed["any_type"] = {"services": []}
        while i < service_types.count():
            service_type = service_types.at(i)
            service_type_name = service_type.nodeName()
            allowed[service_type_name] = {"services": []}
            services = service_type.childNodes()
            j = 0
            while j < services.count():
                service = services.at(j)
                service_name = service.nodeName()
                allowed[service_type_name]["services"].append(service_name)
                allowed["any_type"]["services"].append(service_name)
                j = j + 1
            i = i + 1
        self.allowed_df_services = allowed
        if not allowed["any_type"]["services"]:
            self.df_con_error.emit()
            log_message(
                f"Dataforsyningen returned an empty list of allowed services for token: {self.settings.value('token')}"
            )
        # Go on and get QLR
        self._get_qlr_file()

    def _get_qlr_file(self):
        local_file_exists = os.path.exists(self.cached_df_qlr_filename)
        if local_file_exists:
            local_file_time = datetime.datetime.fromtimestamp(
                os.path.getmtime(self.cached_df_qlr_filename))
            use_cached = local_file_time > datetime.datetime.now(
            ) - FILE_MAX_AGE
            if use_cached:
                # Skip requesting remote qlr
                self._load_config_from_cached_df_qlr()
                return
        # Get qlr from DF
        self._request_df_qlr_file()

    def _request_df_qlr_file(self):
        url_to_get = self.settings.value("df_qlr_url")
        self._qlr_network_fetcher.fetchContent(QUrl(url_to_get))

    def _handle_qlr_response(self):
        network_reply = self._qlr_network_fetcher.reply()

        if network_reply.error():
            log_message("No contact to the configuration at " +
                        self.settings.value("df_qlr_url") + ". Error code : " +
                        str(network_reply.error()))
        else:
            response = str(network_reply.readAll(), "utf-8")
            response = self.insert_token(response)
            self.write_cached_df_qlr(response)
        # Now load and use it
        self._load_config_from_cached_df_qlr()

    def _load_config_from_cached_df_qlr(self):
        self.df_qlr_file = QlrFile(self._read_cached_df_qlr())
        self.background_category, self.categories = self.get_df_categories()
        self.loaded.emit()

    def get_categories(self):
        return self.categories

    def get_background_category(self):
        return self.background_category

    def get_maplayer_node(self, id):
        return self.df_qlr_file.get_maplayer_node(id)

    def get_df_categories(self):
        df_categories = []
        df_background_category = None
        groups_with_layers = self.df_qlr_file.get_groups_with_layers()
        for group in groups_with_layers:
            df_category = {"name": group["name"], "selectables": []}
            for layer in group["layers"]:
                if self.user_has_access(layer["service"]):
                    df_category["selectables"].append({
                        "type": "layer",
                        "source": "df",
                        "name": layer["name"],
                        "id": layer["id"],
                    })
            if len(df_category["selectables"]) > 0:
                df_categories.append(df_category)
                if group["name"] == "Baggrundskort":
                    df_background_category = df_category
        return df_background_category, df_categories

    def user_has_access(self, service_name):
        return service_name in self.allowed_df_services["any_type"]["services"]

    def get_custom_categories(self):
        return []

    def _read_cached_df_qlr(self):
        # return file(unicode(self.cached_df_qlr_filename)).read()
        f = QFile(self.cached_df_qlr_filename)
        f.open(QIODevice.ReadOnly)
        return f.readAll()

    def write_cached_df_qlr(self, contents):
        """We only call this function IF we have a new version downloaded"""
        # Remove old versions file
        for filename in glob.glob(
                self.settings.value("cache_path") +
                "*_dataforsyning_data.qlr"):
            os.remove(filename)

        # Write new version
        with codecs.open(self.cached_df_qlr_filename, "w", "utf-8") as f:
            f.write(contents)

    def debug_write_allowed_services(self):
        try:
            debug_filename = (self.settings.value("cache_path") +
                              self.settings.value("username") + ".txt")
            if os.path.exists(debug_filename):
                os.remove(debug_filename)
            with codecs.open(debug_filename, "w", "utf-8") as f:
                f.write(
                    json.dumps(
                        self.allowed_df_services["any_type"]["services"],
                        indent=2).replace("[", "").replace("]", ""))
        except Exception:
            pass

    def insert_token(self, text):
        result = text
        replace_vars = {}
        replace_vars["df_token"] = self.settings.value("token")
        for i, j in replace_vars.items():
            result = result.replace("{{" + str(i) + "}}", str(j))
        return result