Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepare version 1.9.9 #58

Merged
merged 42 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c8a24e0
refactor IMLNetworkManager import
minff Sep 17, 2023
bbf8c4f
add china platform url + commit encoded url + test
minff Sep 7, 2023
189b4f7
ui: show different platform servers if here system detected
minff Sep 15, 2023
1848872
ui: set default similarity_threshold to 0 (single layering)
minff Sep 27, 2023
7fe4c17
correct prepare fields logic + refactor fields similarity to int 0-100
minff Sep 27, 2023
b5fb5bb
try not clear auth for 403
minff Sep 28, 2023
ed0b16e
less network log
minff Sep 28, 2023
22c25a4
treat all iml layer as livemap for editing flow
minff Oct 3, 2023
1cd50b6
handle layer destroy gracefully without dangling layer
minff Oct 8, 2023
2356dae
better handle 401 error by increasing max retry
minff Oct 10, 2023
bb4db8c
bump version 1.9.9
minff Oct 10, 2023
070c0bb
try to raise rendering error
minff Sep 28, 2023
0f6a738
slow: try to handle OGR error due to mismatch fields
minff Oct 9, 2023
e68b392
debug fields parser
minff Oct 10, 2023
deaf38e
test: add subtest info for test_render_layer
minff Oct 10, 2023
b16983e
fix parser
minff Oct 10, 2023
64b5677
update test util
minff Oct 13, 2023
5ce5763
fixed test parser
minff Oct 13, 2023
f769599
refactor test parser
minff Oct 13, 2023
994b2a1
make test_render_layer work for similarity_threshold=0 (single fields…
minff Oct 13, 2023
8f64078
update Dict type hint
minff Oct 13, 2023
017a519
raise NetworkUnauthorized only for 401
minff Feb 12, 2024
edaf829
deprecated datahub server
minff Feb 26, 2024
c40d25e
refactor network
minff Feb 26, 2024
64d844c
correct clear auth
minff Feb 26, 2024
f4c0838
check here system in thread to avoid blocking UI
minff Feb 26, 2024
a693bc8
use addsitedir
minff Feb 26, 2024
932f73b
update changelog version 1.9.9
minff Feb 26, 2024
edb074a
cleanup network error message
minff Feb 29, 2024
32747ad
draft: try to make layer id unique, rename to iid
minff Feb 29, 2024
7558bdf
improve install deps script (pip) + try QtWebEngineWidgets (not working)
minff Mar 6, 2024
7fc96c7
use qml, QtWebEngine and QtQuick again
minff Mar 7, 2024
05e3813
update build script for win
minff Mar 7, 2024
bd120cf
Fix error since QGIS 3.36.0+: Failed to create OpenGL context for for…
minff Mar 7, 2024
7567d06
fix apply_token
minff Mar 11, 2024
f6cdf2b
update build script for alpha version, folder suffix
minff Mar 8, 2024
8a9a3ae
test crypter with custom env variable
minff Mar 8, 2024
a0cdda9
improve check domain logic
minff Mar 8, 2024
a1594a2
fix qml dependencies on mac
minff Mar 11, 2024
753cccc
fix qml on mac
minff Mar 12, 2024
9ef5cc9
cleanup
minff Mar 12, 2024
9151e5a
update changelog version 1.9.9
minff Mar 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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__ = "huyminh.nguyen@here.com"
__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=huyminh.nguyen@here.com

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__ = "huyminh.nguyen@here.com"
__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
Loading