Skip to content

Commit

Permalink
Merge pull request #58 from heremaps/dev
Browse files Browse the repository at this point in the history
Prepare version 1.9.9
  • Loading branch information
minff authored Mar 12, 2024
2 parents a3e88dc + 9151e5a commit 7fe865a
Show file tree
Hide file tree
Showing 51 changed files with 1,052 additions and 336 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Version 1.9.9 (2024-03-12)

#### Bug Fixes

* Updated Platform IML servers
* Set single layering mode as default
* Improved authorization
* Improved stability
* Deprecated Datahub servers
* Fixed OpenGL outdated driver error
* Show confirm dialog before installing dependencies

## Version 1.9.8 (2023-07-24)

#### Bug Fixes
Expand Down
12 changes: 12 additions & 0 deletions RELEASENOTE.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Release Notes

## Version 1.9.9 (2024-03-12)

🐛 FIXES 🐛

* Updated Platform IML servers
* Set single layering mode as default
* Improved authorization
* Improved stability
* Deprecated Datahub servers
* Fixed OpenGL outdated driver error
* Show confirm dialog before installing dependencies

## Version 1.9.8 (2023-07-24)

🐛 FIXES 🐛
Expand Down
3 changes: 2 additions & 1 deletion XYZHubConnector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
__copyright__ = "Copyright 2019, HERE Europe B.V."

__license__ = "MIT"
__version__ = "1.9.8"
__version__ = "1.9.9"
__maintainer__ = "Minh Nguyen"
__email__ = "[email protected]"
__status__ = "Development"
Expand All @@ -23,6 +23,7 @@ def classFactory(iface):
from . import config

config.load_external_lib()

from .plugin import XYZHubConnector

return XYZHubConnector(iface)
6 changes: 4 additions & 2 deletions XYZHubConnector/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import os
import sys
import site

from qgis.core import QgsApplication

Expand All @@ -34,8 +35,9 @@


def load_external_lib():
if EXTERNAL_LIB_DIR not in sys.path:
sys.path.insert(0, EXTERNAL_LIB_DIR)
site.addsitedir(EXTERNAL_LIB_DIR)
# if EXTERNAL_LIB_DIR not in sys.path:
# sys.path.insert(0, EXTERNAL_LIB_DIR)


def unload_external_lib():
Expand Down
16 changes: 9 additions & 7 deletions XYZHubConnector/metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
name=HERE Maps for QGIS
qgisMinimumVersion=3.0
description=Connect QGIS to Interactive Map Layers in the HERE Platform (https://platform.here.com) and your personal spaces in HERE Data Hub.
version=1.9.8
version=1.9.9
author=HERE Europe B.V.
[email protected]

Expand Down Expand Up @@ -42,13 +42,15 @@ experimental=False
# deprecated flag (applies to the whole plugin, not just a single version)
deprecated=False

changelog=Version 1.9.8 (2023-07-24)
changelog=Version 1.9.9 (2024-03-12)

🐛 FIXES 🐛
* Supports Here Platform login for MacOS
* Fixes issues with login and expired token
* Do not store Here Platform email and token into project files
* Fixes issue that some features are not displayed
* Improves UX and stability
* Updated Platform IML servers
* Set single layering mode as default
* Improved authorization
* Improved stability
* Deprecated Datahub servers
* Fixed OpenGL outdated driver error
* Show confirm dialog before installing dependencies

* .. more details on Github repos
59 changes: 28 additions & 31 deletions XYZHubConnector/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from qgis.core import QgsProject, QgsApplication
from qgis.core import Qgis, QgsMessageLog

from qgis.PyQt.QtCore import QCoreApplication, Qt
from qgis.PyQt.QtCore import QCoreApplication, Qt, QThreadPool
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction
from qgis.PyQt.QtWidgets import QProgressBar
Expand All @@ -36,6 +36,7 @@
make_fun_args,
parse_exception_obj,
ChainInterrupt,
WorkerFun,
)

from .xyz_qgis.loader import (
Expand Down Expand Up @@ -63,8 +64,8 @@
from .xyz_qgis.layer import tile_utils, XYZLayer
from .xyz_qgis.layer.layer_props import QProps


from .xyz_qgis.network import NetManager, net_handler
from .xyz_qgis.network import net_handler
from .xyz_qgis.network.network import NetManager
from .xyz_qgis.network.net_utils import CookieUtils, PlatformSettings
from .xyz_qgis.iml.loader import (
IMLTileLayerLoader,
Expand All @@ -75,7 +76,7 @@
IMLEditSyncController,
)
from .xyz_qgis.iml.loader.iml_auth_loader import HomeProjectNotFound, AuthenticationError
from .xyz_qgis.iml.network import IMLNetworkManager
from .xyz_qgis.iml.network.network import IMLNetworkManager
from .xyz_qgis.iml.models import IMLServerTokenConfig

from .xyz_qgis import basemap
Expand Down Expand Up @@ -112,8 +113,14 @@ def __init__(self, iface):
self.web_menu = "&{name}".format(name=config.PLUGIN_FULL_NAME)
self.hasGuiInitialized = False
self.init_modules()
self.init_in_thread()
self.obj = self

def init_in_thread(self):
self.pool = QThreadPool()
fn = WorkerFun(utils.is_here_system, self.pool)
fn.call(make_qt_args())

def initGui(self):
"""startup"""

Expand Down Expand Up @@ -250,9 +257,7 @@ def init_modules(self):

# token
self.token_config = IMLServerTokenConfig(config.USER_PLUGIN_DIR + "/token.ini", parent)
self.token_config.set_default_servers(
dict(NetManager.API_URL, PLATFORM_PRD="PLATFORM_PRD")
)
self.token_config.set_default_servers(dict(PLATFORM_PRD="PLATFORM_PRD"))
self.token_model = self.token_config.get_token_model()
self.server_model = self.token_config.get_server_model()

Expand Down Expand Up @@ -416,6 +421,7 @@ def cb_handle_error_msg(self, e):
return
elif isinstance(e0, net_handler.NetworkUnauthorized):
# error during list/spaces request
# error during tile request when max retry reached (should not occured)
if not self.handle_net_err(e0):
self.show_err_msgbar(
e0,
Expand All @@ -440,6 +446,7 @@ def cb_handle_error_msg(self, e):
elif isinstance(e0, AuthenticationError):
if isinstance(e0.error, net_handler.NetworkError):
# network error during layer loader, handled by loader, do not handle here
# e.g. 403 get_project
self.show_err_msgbar(
e0, "Please select valid HERE Platform credential and try again"
)
Expand All @@ -459,7 +466,7 @@ def handle_net_err(self, err):
# too many errors, handled by doing nothing
return True
# clear auth
if status in [401, 403]:
if status in [401]:
if conn_info.is_platform_server() and conn_info.is_user_login():
self.network_iml.clear_auth(conn_info)
return
Expand Down Expand Up @@ -487,24 +494,14 @@ def show_net_err(self, err):
pair = (status, reason) if status else (err, err_str)
status_msg = "{0!s}: {1!s}\n".format(*pair)
msg = status_msg + "There was a problem connecting to the server"
if status in [401, 403]:
instruction_msg = (
(
"Please input valid token with correct permissions."
"\n"
"Token is generated via "
"<a href='https://xyz.api.here.com/token-ui/'>"
"https://xyz.api.here.com/token-ui/"
"</a> "
)
if not conn_info.is_platform_server()
else (
"Please input valid Platform app credentials."
if not conn_info.is_user_login()
else "Please retry to login with valid Platform user credentials."
)
)
msg = status_msg + "Authentication failed" "\n\n" + instruction_msg
if status == 401:
stats_final_msg = "Authentication failed"
instruction_msg = "Please use valid credentials"
msg = status_msg + stats_final_msg + "\n\n" + instruction_msg
elif status == 403:
stats_final_msg = "No access"
instruction_msg = "Please request access to the layer"
msg = status_msg + stats_final_msg + "\n\n" + instruction_msg
ret = exec_warning_dialog("Network Error", msg, detail)
return True

Expand Down Expand Up @@ -825,10 +822,10 @@ def _get_lst_reloading_con(self):
for qnode in self.iter_visible_xyz_node():
if qnode.nodeType() == qnode.NodeLayer:
layer = qnode.layer()
xlayer_id = get_customProperty_str(layer, QProps.UNIQUE_ID)
xlayer_id = QProps.get_iid(layer)
is_editable = layer.isEditable()
else:
xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
xlayer_id = QProps.get_iid(qnode)
is_editable = None
if xlayer_id in editing_xid:
continue
Expand Down Expand Up @@ -990,7 +987,7 @@ def init_layer_loader(self, qnode):
def init_all_layer_loader(self):
cnt = 0
for qnode in self.iter_update_all_xyz_node():
xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
xlayer_id = QProps.get_iid(qnode)
con = self.con_man.get_loader(xlayer_id)
if con:
continue
Expand All @@ -1013,7 +1010,7 @@ def cb_qnode_visibility_changed(self, qnode):
if is_xyz_supported_layer(vlayer):
vlayer.reload()
return
xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
xlayer_id = QProps.get_iid(qnode)
con = self.con_man.get_interactive_loader(xlayer_id)
if con:
con.stop_loading()
Expand All @@ -1025,7 +1022,7 @@ def cb_qnodes_deleting(self, parent, i0, i1):
for i in range(i0, i1 + 1):
qnode = lst[i]
if is_parent_root and is_xyz_supported_node(qnode):
xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID)
xlayer_id = QProps.get_iid(qnode)
self.pending_delete_qnodes.setdefault(key, list()).append(xlayer_id)
self.con_man.remove_persistent_loader(xlayer_id)
# is possible to handle vlayer delete here
Expand Down
2 changes: 1 addition & 1 deletion XYZHubConnector/xyz_qgis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
__copyright__ = "Copyright 2019, HERE Europe B.V."

__license__ = "MIT"
__version__ = "1.9.8"
__version__ = "1.9.9"
__maintainer__ = "Minh Nguyen"
__email__ = "[email protected]"
__status__ = "Development"
41 changes: 39 additions & 2 deletions XYZHubConnector/xyz_qgis/common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
###############################################################################

import os

from qgis.PyQt.QtCore import QSettings
from typing import Iterable

from ... import __version__ as version

Expand All @@ -28,6 +27,9 @@ class Config:
EXTERNAL_LIB_DIR = os.path.join(PLUGIN_DIR, "external")
PYTHON_LOG_FILE = os.path.join(USER_DIR, PLUGIN_NAME, "python.log")

def __init__(self):
self._is_here_system = None

def set_config(self, config):
for k, v in config.items():
setattr(self, k, v)
Expand All @@ -39,6 +41,41 @@ def get_external_os_lib(self):
return lib_path

def get_plugin_setting(self, key):
from qgis.PyQt.QtCore import QSettings

key_prefix = "xyz_qgis/settings"
key_ = f"{key_prefix}/{key}"
return QSettings().value(key_)

def _check_here_system(self):
import socket
from .crypter import decrypt_text

socket.setdefaulttimeout(1)

def _check_host(host: str) -> bool:
is_host_reachable = False
try:
ip = socket.gethostbyname(host)
is_host_reachable = len(ip.split(".")) == 4
except:
pass
return is_host_reachable

def _check_fqdn(hosts: Iterable[str]) -> bool:
fqdn = socket.getfqdn()
return any(host in fqdn for host in hosts)

host1 = decrypt_text("Vi5tWQcgFl88Wzg=")
host2 = decrypt_text("XiRtWQcgFl88Wzg=")

is_here_domain = _check_host(host1) or _check_host(host2) or _check_fqdn([host1, host2])
return is_here_domain

def is_here_system(self):
if self._is_here_system is None:
try:
self._is_here_system = self._check_here_system()
except Exception as e:
print(e)
return self._is_here_system
23 changes: 23 additions & 0 deletions XYZHubConnector/xyz_qgis/common/crypter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import base64
from itertools import cycle

CRYPTER_STRING = "7JC1bRsq_4UCTZZkoRO5_zEtd48P1lvTvA9xlI_T8WqilSU5FXS51gEawfvsIKvIinE"


def encrypt_text(text):
return xor_crypt_string(text, key=CRYPTER_STRING, encode=True)


def decrypt_text(text):
return xor_crypt_string(text, key=CRYPTER_STRING, decode=True)


def xor_crypt_string(data: str, key="xor_string", encode=False, decode=False):
bdata = data.encode("utf-8") if isinstance(data, str) else data
if decode:
bdata = base64.b64decode(bdata)
xored = bytes(x ^ y for x, y in zip(bdata, cycle(key.encode("utf-8"))))
out = xored
if encode:
out = base64.b64encode(xored)
return out.decode("utf-8").strip()
Loading

0 comments on commit 7fe865a

Please sign in to comment.