forked from CEN38/plugin_gn_tools
init plugin
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
#! python3 # noqa: E265
|
||||
from .provider import GnToolsProvider # noqa: F401
|
||||
from .login import GetLogin
|
||||
from .widget import ParamWidget, LoadingImport
|
||||
from .draw import RectangleFeatureTool
|
||||
from .gbif import ImportDataGbif
|
||||
from .status import PivotStatus
|
||||
from .filter_synthese import GetFilterFromAPI
|
||||
@@ -0,0 +1,104 @@
|
||||
# Import PyQt libs
|
||||
from PyQt5.QtCore import (
|
||||
pyqtSignal,
|
||||
Qt,
|
||||
)
|
||||
from PyQt5.QtGui import QColor
|
||||
# Import PyQgis libs
|
||||
from qgis.core import (
|
||||
QgsRectangle,
|
||||
QgsPointXY,
|
||||
QgsWkbTypes,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsCoordinateTransform,
|
||||
)
|
||||
from qgis.gui import (
|
||||
QgsMapTool,
|
||||
QgsMapMouseEvent,
|
||||
QgsRubberBand,
|
||||
)
|
||||
|
||||
|
||||
|
||||
class RectangleFeatureTool(QgsMapTool):
|
||||
signal = pyqtSignal()
|
||||
def __init__(self, project, canvas):
|
||||
super().__init__(canvas)
|
||||
self.project = project
|
||||
self.canvas = canvas
|
||||
|
||||
# initiate variable to calculate the extent
|
||||
self.start_point = None
|
||||
self.end_point = None
|
||||
self.new_extent = None
|
||||
|
||||
# flag to check if the left mouse button was pressed
|
||||
self.is_left_button_pressed = False
|
||||
# create a rubber line object
|
||||
# to display the geometry of the dragged object on the canvas
|
||||
self.rubber_band = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry)
|
||||
self.rubber_band.setColor(QColor(255, 0, 0, 50))
|
||||
self.rubber_band.setWidth(2)
|
||||
|
||||
# Mouse button pressed.
|
||||
def canvasPressEvent(self, event: QgsMapMouseEvent):
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.start_point = self.toMapCoordinates(event.pos())
|
||||
self.end_point = self.start_point
|
||||
self.is_left_button_pressed = True
|
||||
|
||||
# The cursor moves across the screen.
|
||||
def canvasMoveEvent(self, event: QgsMapMouseEvent):
|
||||
# if the left mouse button is pressed
|
||||
if self.is_left_button_pressed:
|
||||
self.end_point = self.toMapCoordinates(event.pos())
|
||||
# draw a rectangle on the canvas
|
||||
self.showRect(self.start_point, self.end_point)
|
||||
|
||||
# The mouse button is released.
|
||||
def canvasReleaseEvent(self, event: QgsMapMouseEvent):
|
||||
# if the left mouse button was released
|
||||
if event.button() == Qt.LeftButton:
|
||||
if event.type() == 3:
|
||||
# get the rectangle created from the click point and
|
||||
# left mouse button release points
|
||||
self.new_extent = self.rectangle()
|
||||
self.signal.emit()
|
||||
# toggle the flag, the left mouse button is no longer held down
|
||||
self.is_left_button_pressed = False
|
||||
self.rubber_band.reset() # remove rubber band from canvas
|
||||
sourceCrs = QgsCoordinateReferenceSystem(self.project.crs())
|
||||
destCrs = QgsCoordinateReferenceSystem(4326)
|
||||
tr = QgsCoordinateTransform(sourceCrs, destCrs, self.project)
|
||||
|
||||
# Draw the rectangle on the canvas
|
||||
def showRect(self, startPoint, endPoint):
|
||||
# Reset the last drawn rectangle
|
||||
self.rubber_band.reset(QgsWkbTypes.PolygonGeometry)
|
||||
# Make sure the mouse has moved
|
||||
if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
|
||||
return
|
||||
|
||||
# Create the rectangle
|
||||
point1 = QgsPointXY(startPoint.x(), startPoint.y())
|
||||
point2 = QgsPointXY(startPoint.x(), endPoint.y())
|
||||
point3 = QgsPointXY(endPoint.x(), endPoint.y())
|
||||
point4 = QgsPointXY(endPoint.x(), startPoint.y())
|
||||
|
||||
self.rubber_band.addPoint(point1, False)
|
||||
self.rubber_band.addPoint(point2, False)
|
||||
self.rubber_band.addPoint(point3, False)
|
||||
self.rubber_band.addPoint(point4, True) # true to update canvas
|
||||
self.rubber_band.show()
|
||||
|
||||
def rectangle(self):
|
||||
if self.start_point is None or self.end_point is None:
|
||||
return None
|
||||
elif self.start_point.x() == self.end_point.x() or self.start_point.y() == self.end_point.y():
|
||||
return None
|
||||
return QgsRectangle(self.start_point, self.end_point)
|
||||
|
||||
def deactivate(self):
|
||||
# unload the map tool on the mouse
|
||||
QgsMapTool.deactivate(self)
|
||||
self.deactivated.emit()
|
||||
@@ -0,0 +1,227 @@
|
||||
|
||||
# Standard
|
||||
import json
|
||||
|
||||
# PyQt
|
||||
from qgis.core import QgsAuthMethodConfig, QgsDataSourceUri
|
||||
from qgis.PyQt.QtCore import QByteArray, QJsonDocument, QObject, QUrl, pyqtSignal, Qt
|
||||
from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
from qgis.PyQt.QtWidgets import QAction, QMessageBox, QDialog, QApplication
|
||||
|
||||
|
||||
# Project
|
||||
from gn_tools.__about__ import (
|
||||
__orb_tax_url__
|
||||
)
|
||||
|
||||
class GetFilterFromAPI(QDialog):
|
||||
finished_params = pyqtSignal()
|
||||
"""
|
||||
Create a filter, specific to GeoNature ZH API and fetch all the features corresponding.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
network_manager=None
|
||||
):
|
||||
super().__init__()
|
||||
print("enfin !")
|
||||
self.domain_url = parent.domain_url
|
||||
self.tax_url = self.domain_url if parent.src_name == 'GéoNature' else __orb_tax_url__
|
||||
if self.tax_url[-1] != '/':
|
||||
self.tax_url += '/'
|
||||
self.network_manager = network_manager
|
||||
self.auth = parent.dlg.mAuthConfigSelect
|
||||
self.is_connect = parent.dlg.is_connect
|
||||
self.dlg = parent.dlg_syn
|
||||
self.parent = parent
|
||||
|
||||
self.cookie = (self.network_manager.cookieJar()
|
||||
.cookiesForUrl(QUrl(self.domain_url))[0]
|
||||
)
|
||||
|
||||
# PyQt5 - Version
|
||||
# PyQt6 - Version
|
||||
# QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
||||
self._pending_downloads = 0
|
||||
|
||||
# self.dlg.send_to_gn.
|
||||
self.dlg.send_to_gn.setText(
|
||||
self.dlg.send_to_gn.text() + '<br><br><a href="{url}">{url}</a>'.format(url=self.domain_url)
|
||||
)
|
||||
self.dlg.send_to_gn.setStyleSheet(
|
||||
"border: 1px solid; border-color:blue; font-weight:bold"
|
||||
)
|
||||
|
||||
self.dlg.send_to_gn.setOpenExternalLinks(True)
|
||||
self.params = {}
|
||||
self.get_jdd()
|
||||
|
||||
if self.parent.src_name == 'GéoNature':
|
||||
self.get_phylog()
|
||||
else:
|
||||
self.self.dlg.regne.deselectAllOptions()
|
||||
self.self.dlg.regne.clear()
|
||||
|
||||
self.dlg.buttonBox.accepted.connect(self.accept)
|
||||
self.dlg.buttonBox.rejected.connect(self.reject)
|
||||
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
|
||||
def handle_finished(self, reply):
|
||||
self._pending_downloads -= 1
|
||||
# If reply is an error or reply is a redirection, login is not accepted
|
||||
print(reply.attribute(
|
||||
QNetworkRequest.HttpStatusCodeAttribute
|
||||
))
|
||||
print(reply.error(),' : ',reply.dtype)
|
||||
self.network_manager.cookieStatus = reply.attribute(
|
||||
QNetworkRequest.HttpStatusCodeAttribute
|
||||
)
|
||||
QApplication.restoreOverrideCursor()
|
||||
if (
|
||||
reply.error() != QNetworkReply.NoError
|
||||
or self.network_manager.cookieStatus != 200
|
||||
):
|
||||
# Error code 299 means the logins are invalid
|
||||
# Redirection not equal to 200 means a redirection happened
|
||||
if reply.dtype == 'JDD':
|
||||
self.dlg.jdd_box.setDisabled(True)
|
||||
self.dlg.jdd_box.clear()
|
||||
elif reply.dtype in ['PHYLOG','TAX_TREE']:
|
||||
self.dlg.regne.setDisabled(True)
|
||||
self.dlg.regne.clear()
|
||||
|
||||
|
||||
if reply.error() == 0:
|
||||
msg = QMessageBox()
|
||||
msg.warning(
|
||||
None,
|
||||
self.tr("Warning"),
|
||||
self.tr(
|
||||
"Houston, we've got a problem ... \n\n L'utilisateur ou le mot de passe est invalide !"
|
||||
), # noqa: E501
|
||||
)
|
||||
else:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
else:
|
||||
data_request = reply.readAll().data().decode()
|
||||
data = json.loads(data_request)
|
||||
self.params[reply.dtype] = data
|
||||
self.close()
|
||||
|
||||
if self.pending_downloads == 1 :
|
||||
self.get_taxon_tree()
|
||||
|
||||
if self.pending_downloads == 0:
|
||||
self.set_params_to_widget()
|
||||
self.finished_params.emit()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
|
||||
def get_jdd(self):
|
||||
self._pending_downloads += 1
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
self.dlg.jdd_box.setEnabled(True)
|
||||
url_api = self.domain_url + 'api/meta/datasets?'
|
||||
if self.parent.src_name == 'GéoNature':
|
||||
url_api += 'orderby=dataset_shortname'
|
||||
request_type = 'POST'
|
||||
elif self.parent.src_name == "Biodiv'AuRA":
|
||||
url_api += 'orderby=dataset_name'
|
||||
request_type = 'GET'
|
||||
url = QUrl(url_api)
|
||||
self.send_request(url,type_request=request_type,type_param='JDD')
|
||||
|
||||
|
||||
def get_phylog(self):
|
||||
self._pending_downloads += 2
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
self.dlg.regne.setEnabled(True)
|
||||
if self.parent.src_name == 'GéoNature':
|
||||
url_api = self.tax_url + 'api/taxhub/api/taxref/regnewithgroupe2'
|
||||
if self.parent.src_name == "Biodiv'AuRA":
|
||||
url_api = self.tax_url + 'api/taxref/regnewithgroupe2'
|
||||
url = QUrl(url_api)
|
||||
self.send_request(url,type_request='GET',type_param='PHYLOG')
|
||||
|
||||
|
||||
def get_taxon_tree(self):
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
|
||||
if self.parent.src_name == 'GéoNature':
|
||||
url_api = self.tax_url + 'api/synthese/taxons_tree'
|
||||
url = QUrl(url_api)
|
||||
self.send_request(url,type_request='GET',type_param='TAX_TREE')
|
||||
else:
|
||||
self._pending_downloads -= 1
|
||||
self.set_params_to_widget()
|
||||
self.finished_params.emit()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
|
||||
def send_request(self,url,type_request,type_param):
|
||||
print(url)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
request.setHeader(QNetworkRequest.CookieHeader, self.cookie)
|
||||
if type_request == 'GET':
|
||||
reply = self.network_manager.get(request)
|
||||
elif type_request == 'POST':
|
||||
doc = QJsonDocument({})
|
||||
reply = self.network_manager.post(request,doc.toJson())
|
||||
reply.dtype = type_param
|
||||
reply.finished.connect(lambda: self.handle_finished(reply))
|
||||
|
||||
|
||||
def set_params_to_widget(self):
|
||||
if 'JDD' in self.params.keys():
|
||||
jdd_items = [i['dataset_shortname'] for i in self.params['JDD']]
|
||||
self.dlg.jdd_box.addItems(jdd_items)
|
||||
|
||||
if 'PHYLOG' in self.params.keys():
|
||||
rgn_items = [i for i in self.params['PHYLOG'].keys()]
|
||||
self.dlg.regne.addItems(rgn_items)
|
||||
|
||||
# self.dlg.jdd_box.setCheckedItems(items)
|
||||
print('END loading params ...')
|
||||
|
||||
|
||||
def accept(self):
|
||||
params = {
|
||||
'id_dataset':[ i['id_dataset']
|
||||
for i in self.params['JDD']
|
||||
if i['dataset_shortname'] in self.dlg.jdd_box.checkedItems()
|
||||
] if 'JDD' in self.params.keys() else [],
|
||||
'cd_ref_parent': [ i['cd_ref']
|
||||
for i in self.params['TAX_TREE']
|
||||
if i['nom_regne'] in self.dlg.regne.checkedItems()
|
||||
] if 'PHYLOG' in self.params.keys() else [],
|
||||
'date_min' : None if self.dlg.date_min.isNull()
|
||||
else self.dlg.date_min.date().toString('yyyy-MM-dd'),
|
||||
'date_max' : None if self.dlg.date_max.isNull()
|
||||
else self.dlg.date_max.date().toString('yyyy-MM-dd'),
|
||||
}
|
||||
self.parent.syn_params = {
|
||||
i : params[i] for i in params if params[i]
|
||||
}
|
||||
|
||||
|
||||
def reject(self):
|
||||
self.clear_widgets()
|
||||
QApplication.restoreOverrideCursor()
|
||||
print("Rejected")
|
||||
|
||||
|
||||
def clear_widgets(self):
|
||||
self.dlg.jdd_box.deselectAllOptions()
|
||||
self.dlg.regne.deselectAllOptions()
|
||||
self.dlg.date_min.clear()
|
||||
self.dlg.date_max.clear()
|
||||
@@ -0,0 +1,205 @@
|
||||
# Import basic libs
|
||||
import json
|
||||
import time
|
||||
# Import PyQt libs
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QUrl, Qt, QVariant
|
||||
from PyQt5.QtGui import QColor
|
||||
from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply
|
||||
from PyQt5.QtWidgets import QDialog, QPushButton, QApplication, QVBoxLayout, QHBoxLayout, QButtonGroup, QCheckBox, QLabel
|
||||
# Import PyQgis libs
|
||||
from qgis.utils import iface
|
||||
from qgis.core import QgsProject, QgsFeature, QgsDataSourceUri, QgsRectangle, QgsNetworkAccessManager, QgsVectorLayer, QgsPointXY, QgsWkbTypes, QgsMapLayerProxyModel, QgsGeometry, QgsCoordinateReferenceSystem, QgsCoordinateTransform, QgsField
|
||||
from qgis.gui import QgsMapTool, QgsMapMouseEvent, QgsRubberBand, QgsMapLayerComboBox
|
||||
|
||||
|
||||
class GetTaxrefId(QObject):
|
||||
finished_dl = pyqtSignal()
|
||||
"""Get multiples informations from a getcapabilities request.
|
||||
List all layers available, get the maximal extent of all the Wfs' data."""
|
||||
|
||||
def __init__(self, network_manager=None, project=None, layer=None, field_name=None, field_rank=None):
|
||||
super().__init__()
|
||||
self.network_manager = network_manager
|
||||
self.project = project
|
||||
self.layer = layer
|
||||
self.field_name = field_name
|
||||
self.field_rank = field_rank
|
||||
self._pending_downloads = 0
|
||||
|
||||
self.ids = []
|
||||
self.names = []
|
||||
self.rank = []
|
||||
|
||||
for obs in self.layer.getFeatures():
|
||||
self.ids.append(obs.id())
|
||||
self.names.append(obs[self.field_name])
|
||||
self.rank.append(obs[self.field_rank])
|
||||
self._pending_downloads = len(self.names)
|
||||
self._iterate_names = 0
|
||||
self.download(self.ids[self._iterate_names], self.names[self._iterate_names], self.rank[self._iterate_names])
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
@property
|
||||
def iterate_names(self):
|
||||
return self._iterate_names
|
||||
|
||||
def download(self, feature_id, nom, rank):
|
||||
if rank.lower() == 'stateofmatter':
|
||||
self._iterate_names += 1
|
||||
self.download(self.ids[self._iterate_names], self.names[self._iterate_names], self.rank[self._iterate_names])
|
||||
else:
|
||||
if rank.lower() == 'complex' or rank.lower() == 'hybrid':
|
||||
rank = 'species'
|
||||
elif rank.lower() == 'epifamily' or rank.lower() == 'section':
|
||||
rank = 'genus'
|
||||
elif rank.lower() == 'subtribe':
|
||||
rank = 'subfamily'
|
||||
url = "https://api.checklistbank.org/nameusage/search?content=SCIENTIFIC_NAME&datasetKey=2008&facet=datasetKey&facet=rank&facet=issue&facet=status&facet=nomStatus&facet=nameType&facet=field&facet=authorship&facet=authorshipYear&facet=extinct&facet=environment&facet=origin&limit=50&offset=0&q={nom}&rank={rank}&type=PREFIX".format(nom=nom.split("(")[0], rank=rank.lower())
|
||||
print(url)
|
||||
request = QNetworkRequest(QUrl(url))
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
reply = self.network_manager.get(request)
|
||||
reply.finished.connect(lambda: self.handle_finished(reply, feature_id))
|
||||
self._iterate_names += 1
|
||||
|
||||
|
||||
def handle_finished(self, reply, feature_id):
|
||||
self._pending_downloads -= 1
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
if reply.error() == 403:
|
||||
print("Service down")
|
||||
else:
|
||||
data_request = reply.readAll().data().decode()
|
||||
if data_request != "":
|
||||
res = json.loads(data_request)
|
||||
if "result" in res:
|
||||
taxref_id = res["result"][0]["id"]
|
||||
taxref_name = res["result"][0]["usage"]["label"]
|
||||
self.layer.startEditing()
|
||||
self.layer.changeAttributeValue(feature_id, self.layer.fields().indexFromName("cd_nom"), taxref_id)
|
||||
self.layer.changeAttributeValue(feature_id, self.layer.fields().indexFromName("nom_scien"), taxref_name)
|
||||
self.layer.commitChanges()
|
||||
self.layer.triggerRepaint()
|
||||
if self.pending_downloads == 0:
|
||||
self.project.addMapLayer(self.layer)
|
||||
self.finished_dl.emit()
|
||||
else:
|
||||
self.download(self.ids[self._iterate_names], self.names[self._iterate_names], self.rank[self._iterate_names])
|
||||
|
||||
|
||||
class ImportDataGbif(QObject):
|
||||
finished_dl = pyqtSignal()
|
||||
"""Get multiples informations from a getcapabilities request.
|
||||
List all layers available, get the maximal extent of all the Wfs' data."""
|
||||
|
||||
def __init__(self, network_manager=None, project=None, geom=None, ):
|
||||
super().__init__()
|
||||
|
||||
self._pending_downloads = 0
|
||||
self._pending_pages = 1
|
||||
self.network_manager = network_manager
|
||||
self.project = project
|
||||
self.layer = self.new_layer()
|
||||
self.geom = geom
|
||||
|
||||
self.new_features = []
|
||||
|
||||
self.max_obs = 0
|
||||
self.total_pages = 0
|
||||
|
||||
self.download()
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
@property
|
||||
def pending_pages(self):
|
||||
return self._pending_pages
|
||||
|
||||
def new_layer(self):
|
||||
geom_type = "Point"
|
||||
new_layer = QgsVectorLayer(geom_type + "?crs=epsg:4326", "GBIF", "memory")
|
||||
new_layer.startEditing()
|
||||
new_layer.addAttribute(QgsField("id", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("cd_nom", QVariant.Int, "integer", 10))
|
||||
new_layer.addAttribute(QgsField("niveau", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("nom", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("nom_scien", QVariant.String, "string", 100000))
|
||||
new_layer.addAttribute(QgsField("observat", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("date", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("projet", QVariant.String, "string", 254))
|
||||
new_layer.addAttribute(QgsField("effectif", QVariant.Int, "integer", 10))
|
||||
new_layer.addAttribute(QgsField("url", QVariant.String, "string", 254))
|
||||
new_layer.commitChanges()
|
||||
new_layer.triggerRepaint()
|
||||
return new_layer
|
||||
|
||||
def download(self):
|
||||
url = "https://api.gbif.org/v1/occurrence/search?advanced=false&geometry={polygon}&offset={offset}&limit=1000".format(
|
||||
offset=self.pending_pages, polygon=self.geom.asWkt())
|
||||
url = QUrl(url)
|
||||
self.nb_request = 1
|
||||
print(url)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
reply = self.network_manager.get(request)
|
||||
reply.finished.connect(lambda: self.handle_finished(reply))
|
||||
self._pending_downloads += 1
|
||||
|
||||
def handle_finished(self, reply):
|
||||
self._pending_downloads -= 1
|
||||
if reply.error() != QNetworkReply.NoError:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
if reply.error() == 403:
|
||||
print("Service down")
|
||||
else:
|
||||
data_request = reply.readAll().data().decode()
|
||||
if self.pending_downloads == 0:
|
||||
|
||||
res = json.loads(data_request)
|
||||
self.max_obs = res["count"]
|
||||
self.total_pages = int(self.max_obs/20) + 1
|
||||
for obs in res["results"]:
|
||||
new_geom = QgsGeometry.fromPointXY(QgsPointXY(obs["decimalLongitude"], obs["decimalLatitude"]))
|
||||
new_feature = QgsFeature(self.layer.fields())
|
||||
new_feature.setGeometry(new_geom)
|
||||
new_feature.setAttribute(0, str(obs["key"]))
|
||||
new_feature.setAttribute(1, 0)
|
||||
new_feature.setAttribute(2, obs["taxonRank"])
|
||||
if obs["taxonRank"].lower() in ['kingdom', 'phylum', 'order', 'family', 'genus', 'species']:
|
||||
new_feature.setAttribute(3, obs[obs["taxonRank"].lower()])
|
||||
|
||||
else:
|
||||
new_feature.setAttribute(3, obs["scientificName"])
|
||||
new_feature.setAttribute(4, "")
|
||||
new_feature.setAttribute(5, "")
|
||||
new_feature.setAttribute(6, str(obs["eventDate"]))
|
||||
# new_feature.setAttribute(7, obs["_datasetKey"]["title"])
|
||||
new_feature.setAttribute(7, obs["datasetName"] if "datasetName" in obs.keys() else None )
|
||||
new_feature.setAttribute(8, 1)
|
||||
new_feature.setAttribute(9, "https://www.gbif.org/fr/occurrence/" + str(obs["key"]))
|
||||
self.new_features.append(new_feature)
|
||||
|
||||
if self.nb_request == 10:
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
if self.pending_pages < self.total_pages:
|
||||
self._pending_pages += 300
|
||||
self.nb_request += 1
|
||||
self.download()
|
||||
else:
|
||||
# Add the new feature to the temporary layer
|
||||
self.layer.startEditing()
|
||||
self.layer.dataProvider().addFeatures(self.new_features)
|
||||
self.layer.updateExtents()
|
||||
self.layer.commitChanges()
|
||||
self.layer.triggerRepaint()
|
||||
|
||||
GetTaxrefId(self.network_manager, self.project, self.layer, "nom", "niveau")
|
||||
self.finished_dl.emit()
|
||||
@@ -0,0 +1,173 @@
|
||||
|
||||
# Standard
|
||||
import json
|
||||
|
||||
# PyQt
|
||||
from qgis.core import QgsAuthMethodConfig, QgsDataSourceUri
|
||||
from qgis.PyQt.QtCore import QByteArray, QJsonDocument, QObject, QUrl, pyqtSignal
|
||||
from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
from qgis.PyQt.QtWidgets import QAction, QMessageBox, QDialog
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
# from PyQt6.QtCore import Qt
|
||||
# from PyQt6.QtWidgets import QApplication
|
||||
|
||||
# Project
|
||||
from gn_tools.__about__ import __login_url__
|
||||
|
||||
|
||||
class GetLogin(QDialog):
|
||||
finished_login = pyqtSignal()
|
||||
"""
|
||||
Create a filter, specific to GeoNature ZH API and fetch all the features corresponding.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
network_manager=None,
|
||||
params=None
|
||||
):
|
||||
super().__init__()
|
||||
print("enfin !")
|
||||
self.domain_url = parent.domain_url
|
||||
self.network_manager = network_manager
|
||||
self.auth = parent.dlg.mAuthConfigSelect
|
||||
self.is_connect = parent.dlg.is_connect
|
||||
self.params = params
|
||||
print(self.auth.configId())
|
||||
# self.zhs = None
|
||||
# self.json_filter = {}
|
||||
# self.total_zh = 0
|
||||
|
||||
# PyQt5 - Version
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
# PyQt6 - Version
|
||||
# QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor)
|
||||
self._pending_downloads = 0
|
||||
self.check_password()
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
def handle_finished(self, reply):
|
||||
self._pending_downloads -= 1
|
||||
QApplication.restoreOverrideCursor()
|
||||
# If reply is an error or reply is a redirection, login is not accepted
|
||||
print(reply.attribute(
|
||||
QNetworkRequest.HttpStatusCodeAttribute
|
||||
))
|
||||
print('Login : ',reply.error())
|
||||
self.network_manager.cookieStatus = reply.attribute(
|
||||
QNetworkRequest.HttpStatusCodeAttribute
|
||||
)
|
||||
if (
|
||||
reply.error() != QNetworkReply.NoError
|
||||
or self.network_manager.cookieStatus != 200
|
||||
):
|
||||
# Error code 299 means the logins are invalid
|
||||
# Redirection not equal to 200 means a redirection happened
|
||||
if reply.error() == 0:
|
||||
self.is_connect.setText("Aie !")
|
||||
msg = QMessageBox()
|
||||
msg.warning(
|
||||
None,
|
||||
self.tr("Warning"),
|
||||
self.tr(
|
||||
"Houston, we've got a problem ... \n\n L'utilisateur ou le mot de passe est invalide !"
|
||||
), # noqa: E501
|
||||
)
|
||||
elif reply.error() == 3:
|
||||
msg = QMessageBox()
|
||||
msg.warning(
|
||||
None,
|
||||
self.tr("Warning"),
|
||||
self.tr(
|
||||
"GéoNature's URL not found, add it to the plugin settings"
|
||||
), # noqa: E501
|
||||
)
|
||||
self.close()
|
||||
self.parent.iface.showOptionsDialog(
|
||||
currentPage="mOptionsPage{}".format(__title__)
|
||||
)
|
||||
self.parent.create_project_from_gn()
|
||||
else:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
else:
|
||||
self.cookies = self.network_manager.cookieJar()
|
||||
self.is_connect.setText("Good Job !")
|
||||
|
||||
# If the authenfication configuration already exists,
|
||||
# modify it with the new values
|
||||
# self.manager_config.setConfigMap(
|
||||
# {
|
||||
# "password": self.usr,
|
||||
# "username": self.pwd,
|
||||
# }
|
||||
# )
|
||||
# self.manager.storeAuthenticationConfig(
|
||||
# self.manager_config, True
|
||||
# )
|
||||
# delete sensitive informations... even if it's in the database now...
|
||||
self.network_manager.accepted = True
|
||||
# Add the cookie created with the login to the request
|
||||
self.network_manager.setCookieJar(self.cookies)
|
||||
# self.network_manager.setCookiesFromUrl(self.cookies,self.domain_url)
|
||||
self.close()
|
||||
|
||||
if self.pending_downloads == 0:
|
||||
self.finished_login.emit()
|
||||
|
||||
return self.network_manager
|
||||
|
||||
|
||||
def get_param_connect(self):
|
||||
if self.params:
|
||||
self.usr = self.params["usr"]
|
||||
self.pwd = self.params["pwd"]
|
||||
return True
|
||||
elif self.auth.configId():
|
||||
authCfg = self.auth.configId()
|
||||
quri = QgsDataSourceUri()
|
||||
quri.setParam("authcfg", authCfg)
|
||||
quri.setParam("url", self.domain_url)
|
||||
self.usr = quri.uri().split("user='")[1].split("' ",1)[0]
|
||||
self.pwd = quri.uri().split("password='")[1].split("' ",1)[0]
|
||||
return True
|
||||
else :
|
||||
return False
|
||||
|
||||
|
||||
def check_password(self):
|
||||
# Test if the user wrote something
|
||||
if self.auth.configId() or self.params:
|
||||
is_connect = self.get_param_connect()
|
||||
url = QUrl(self.domain_url + __login_url__)
|
||||
print(self.usr)
|
||||
data_json = {
|
||||
"login": (
|
||||
self.usr
|
||||
),
|
||||
"password": (
|
||||
self.pwd
|
||||
),
|
||||
}
|
||||
print(url)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
document = QJsonDocument(data_json)
|
||||
print(document.toJson())
|
||||
reply = self.network_manager.post(request, document.toJson())
|
||||
reply.finished.connect(lambda: self.handle_finished(reply))
|
||||
self._pending_downloads += 1
|
||||
else:
|
||||
msg = QMessageBox()
|
||||
msg.warning(
|
||||
None,
|
||||
self.tr("Warning"),
|
||||
self.tr(
|
||||
"GéoNature's Auth not found, add it to the plugin settings"
|
||||
), # noqa: E501
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
#! python3 # noqa: E265
|
||||
|
||||
"""
|
||||
Processing provider module.
|
||||
"""
|
||||
|
||||
# PyQGIS
|
||||
from qgis.core import QgsProcessingProvider
|
||||
from qgis.PyQt.QtCore import QCoreApplication
|
||||
from qgis.PyQt.QtGui import QIcon
|
||||
|
||||
# project
|
||||
from gn_tools.__about__ import (
|
||||
__icon_path__,
|
||||
__title__,
|
||||
__version__,
|
||||
)
|
||||
|
||||
# ############################################################################
|
||||
# ########## Classes ###############
|
||||
# ##################################
|
||||
|
||||
|
||||
class GnToolsProvider(QgsProcessingProvider):
|
||||
"""Processing provider class."""
|
||||
|
||||
def loadAlgorithms(self):
|
||||
"""Loads all algorithms belonging to this provider."""
|
||||
pass
|
||||
|
||||
def id(self) -> str:
|
||||
"""Unique provider id, used for identifying it. This string should be unique, \
|
||||
short, character only string, eg "qgis" or "gdal". \
|
||||
This string should not be localised.
|
||||
|
||||
:return: provider ID
|
||||
:rtype: str
|
||||
"""
|
||||
return "gn_tools"
|
||||
|
||||
def name(self) -> str:
|
||||
"""Returns the provider name, which is used to describe the provider
|
||||
within the GUI. This string should be short (e.g. "Lastools") and localised.
|
||||
|
||||
:return: provider name
|
||||
:rtype: str
|
||||
"""
|
||||
return __title__
|
||||
|
||||
def longName(self) -> str:
|
||||
"""Longer version of the provider name, which can include
|
||||
extra details such as version numbers. E.g. "Lastools LIDAR tools". This string should be localised. The default
|
||||
implementation returns the same string as name().
|
||||
|
||||
:return: provider long name
|
||||
:rtype: str
|
||||
"""
|
||||
return self.tr("{} - Tools".format(__title__))
|
||||
|
||||
def icon(self) -> QIcon:
|
||||
"""QIcon used for your provider inside the Processing toolbox menu.
|
||||
|
||||
:return: provider icon
|
||||
:rtype: QIcon
|
||||
"""
|
||||
return QIcon(str(__icon_path__))
|
||||
|
||||
def tr(self, message: str) -> str:
|
||||
"""Get the translation for a string using Qt translation API.
|
||||
|
||||
:param message: String for translation.
|
||||
:type message: str, QString
|
||||
|
||||
:returns: Translated version of message.
|
||||
:rtype: str
|
||||
"""
|
||||
# noinspection PyTypeChecker,PyArgumentList,PyCallByClass
|
||||
return QCoreApplication.translate(self.__class__.__name__, message)
|
||||
|
||||
def versionInfo(self) -> str:
|
||||
"""Version information for the provider, or an empty string if this is not \
|
||||
applicable (e.g. for inbuilt Processing providers). For plugin based providers, \
|
||||
this should return the plugin’s version identifier.
|
||||
|
||||
:return: version
|
||||
:rtype: str
|
||||
"""
|
||||
return __version__
|
||||
@@ -0,0 +1,469 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
# import requests
|
||||
# import numpy as np
|
||||
# import pandas as pd
|
||||
# import os
|
||||
# Standard
|
||||
import json
|
||||
|
||||
from qgis.core import QgsGeometry, QgsProject, QgsJsonUtils, QgsVectorLayer
|
||||
# PyQt
|
||||
from qgis.PyQt.QtCore import (
|
||||
QUrl,
|
||||
pyqtSignal,
|
||||
QJsonDocument,
|
||||
Qt,
|
||||
QTextCodec
|
||||
)
|
||||
from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
from qgis.PyQt.QtWidgets import (
|
||||
QAction,
|
||||
QMessageBox,
|
||||
QDialog,
|
||||
QApplication
|
||||
)
|
||||
from gn_tools.__about__ import __api_cd_sta__
|
||||
|
||||
def get_status(lst,con):
|
||||
sql = """
|
||||
SELECT
|
||||
t.cd_nom,
|
||||
t.cd_ref,
|
||||
t.regne,
|
||||
t.phylum,
|
||||
t.classe,
|
||||
t.ordre,
|
||||
t.famille,
|
||||
t.group1_inpn,
|
||||
t.group2_inpn,
|
||||
t.group3_inpn,
|
||||
t.nom_vern,
|
||||
t.nom_complet,
|
||||
t.nom_valide,
|
||||
t.lb_nom,
|
||||
--s.*
|
||||
s.cd_sig,
|
||||
s.rq_statut,
|
||||
s.code_statut,
|
||||
s.cd_type_statut,
|
||||
s.label_statut,
|
||||
s.niveau_admin,
|
||||
s.full_citation,
|
||||
s.doc_url
|
||||
FROM taxonomie.taxref t
|
||||
JOIN taxonomie.v_bdc_status s USING (cd_nom)
|
||||
WHERE t.cd_nom IN {cd_nom}
|
||||
;""".format(cd_nom = tuple(lst))
|
||||
return pd.read_sql_query(sql,con)
|
||||
|
||||
def get_type_status(con):
|
||||
sql = """
|
||||
SELECT * FROM taxonomie.bdc_statut_type
|
||||
;"""
|
||||
return pd.read_sql_query(sql,con)
|
||||
|
||||
def get_api_status(api,cd_nom:int):
|
||||
res = requests.api.get('%s/%i'%(api,cd_nom))
|
||||
if res.status_code == 200:
|
||||
return res.json()
|
||||
else :
|
||||
raise('Error : %i\tcd_nom : %i'%(res.status_code,cd_nom))
|
||||
|
||||
def get_taxon_status(lst,api):
|
||||
from datetime import datetime as dt
|
||||
init = dt.now()
|
||||
st = [get_api_status(api,x) for x in lst] # TOO LONG
|
||||
print(dt.now()-init)
|
||||
phylo = {
|
||||
'cd_ref':[x['cd_ref'] for x in st],
|
||||
'nom_valide':[x['nom_valide'] if 'nom_valide' in x.keys() else None for x in st],
|
||||
'nom_vernac':[x['nom_vern'] if 'nom_vern' in x.keys() else None for x in st],
|
||||
'regne':[x['regne'] if 'regne' in x.keys() else None for x in st],
|
||||
'group1_inp':[x['group1_inpn'] if 'group1_inpn' in x.keys() else None for x in st],
|
||||
'group2_inp':[x['group2_inp'] if 'group2_inp' in x.keys() else None for x in st],
|
||||
'group3_inpn':[x['group3_inpn'] for x in st],
|
||||
'classe':[x['classe'] if 'classe' in x.keys() else None for x in st],
|
||||
'ordre':[x['ordre'] if 'ordre' in x.keys() else None for x in st],
|
||||
'famille':[x['famille'] if 'famille' in x.keys() else None for x in st]}
|
||||
cd_status = {
|
||||
'AL':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['AL']['text'].values() for v in val['values'] ]
|
||||
if 'AL' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'BERN':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['BERN']['text'].values() for v in val['values'] ]
|
||||
if 'BERN' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'BONN':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['BONN']['text'].values() for v in val['values'] ]
|
||||
if 'BONN' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'DH':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['DH']['text'].values() for v in val['values'] ]
|
||||
if 'DH' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'DO':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['DO']['text'].values() for v in val['values'] ]
|
||||
if 'DO' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'LRE':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['LRE']['text'].values() for v in val['values'] ]
|
||||
if 'LRE' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'LRM':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['LRM']['text'].values() for v in val['values'] ]
|
||||
if 'LRM' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'LRN':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['LRN']['text'].values() for v in val['values'] ]
|
||||
if 'LRN' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'LRR':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['LRR']['text'].values() for v in val['values'] ]
|
||||
if 'LRR' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'PAPNAT':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['PAPNAT']['text'].values() for v in val['values'] ]
|
||||
if 'PAPNAT' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'PD':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['PD']['text'].values() for v in val['values'] ]
|
||||
if 'PD' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'PNA':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['PNA']['text'].values() for v in val['values'] ]
|
||||
if 'PNA' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'PR':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['PR']['text'].values() for v in val['values'] ]
|
||||
if 'PR' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'REGL':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['REGL']['text'].values() for v in val['values'] ]
|
||||
if 'REGL' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'REGLII':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['REGLII']['text'].values() for v in val['values'] ]
|
||||
if 'REGLII' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'REGLLUTTE':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['REGLLUTTE']['text'].values() for v in val['values'] ]
|
||||
if 'REGLLUTTE' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'REGLSO':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['REGLSO']['text'].values() for v in val['values'] ]
|
||||
if 'REGLSO' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'SCAP NAT':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['SCAP NAT']['text'].values() for v in val['values'] ]
|
||||
if 'SCAP NAT' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'SCAP REG':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['SCAP REG']['text'].values() for v in val['values'] ]
|
||||
if 'SCAP REG' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'SENSNAT':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['SENSNAT']['text'].values() for v in val['values'] ]
|
||||
if 'SENSNAT' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'ZDET':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['ZDET']['text'].values() for v in val['values'] ]
|
||||
if 'ZDET' in x['status'].keys() else None
|
||||
for x in st
|
||||
],
|
||||
'exPNA':[
|
||||
[val['values'][v]['code_statut']
|
||||
for val in x['status']['exPNA']['text'].values() for v in val['values'] ]
|
||||
if 'exPNA' in x['status'].keys() else None
|
||||
for x in st
|
||||
]
|
||||
}
|
||||
return pd.DataFrame({**phylo,**cd_status})
|
||||
|
||||
|
||||
def filter_bio_geo(df,zone_bio):
|
||||
idNotBioGeo = []
|
||||
# Filtre du dommaine biogeographique sur la plaine Rhodanienne et Alpine
|
||||
test_rhod = df.rq_statut.str.contains('rhodanienne : Non déterminante')
|
||||
test_alpi = df.rq_statut.str.contains('Alpine : Non déterminante')
|
||||
|
||||
if zone_bio == 'rhod':
|
||||
idNotBioGeo = df[test_rhod].index
|
||||
elif zone_bio == 'alpi':
|
||||
idNotBioGeo = df[test_alpi].index
|
||||
elif zone_bio == 'all':
|
||||
idNotBioGeo = df[test_rhod&test_alpi].index
|
||||
|
||||
if not idNotBioGeo.empty:
|
||||
df.drop(idNotBioGeo, inplace=True)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
def form_territoire(df,terr):
|
||||
is_dep = df.cd_sig.str.contains('INSEED')
|
||||
is_38 = df.cd_sig=='INSEED38'
|
||||
|
||||
if terr == 'isere':
|
||||
filter_id = df[is_dep&(~is_38)].index
|
||||
df.drop(filter_id,inplace=True)
|
||||
elif terr == 'platiere':
|
||||
lst_stat = df[is_dep&(~is_38)].cd_type_statut.unique()
|
||||
# is_lst = df.cd_type_statut.isin(lst_stat)
|
||||
df.loc[is_dep&(~is_38),'cd_type_statut'] = ( df[is_dep&(~is_38)]
|
||||
.cd_type_statut + '_' + df[is_dep&(~is_38)].cd_sig.str.strip('INSEED')
|
||||
)
|
||||
df.loc[is_38,'cd_type_statut'] = ( df[is_38]
|
||||
.cd_type_statut + '_38'
|
||||
)
|
||||
|
||||
return df
|
||||
|
||||
|
||||
dict_dep = {
|
||||
'38':'Isère',
|
||||
'42':'Loire',
|
||||
'07':'Ardèche',
|
||||
'26':'Drôme',
|
||||
}
|
||||
|
||||
|
||||
class PivotStatus(QDialog):
|
||||
finished_dl = pyqtSignal()
|
||||
"""
|
||||
Create a filter, specific to GeoNature ZH API and fetch all the features corresponding.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
network_manager=None,
|
||||
layer=None,
|
||||
cd_nom=None
|
||||
):
|
||||
super().__init__()
|
||||
print(parent.dlg.tab)
|
||||
self.dlg = parent.dlg
|
||||
self.src_name = parent.src_name
|
||||
self.domain_url = parent.domain_url
|
||||
self.network_manager = network_manager
|
||||
self.layer = layer
|
||||
self.cd_nom = cd_nom
|
||||
self.url_api = self.domain_url + __api_cd_sta__
|
||||
|
||||
# QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
self.multi_dep = True
|
||||
|
||||
self.cookie = (self.network_manager.cookieJar()
|
||||
.cookiesForUrl(QUrl(self.domain_url))[0]
|
||||
)
|
||||
self._pending_downloads = 0
|
||||
self.import_status()
|
||||
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
|
||||
def import_status(self):
|
||||
idx = self.layer.fields().indexOf(self.cd_nom)
|
||||
unique_cd = self.layer.uniqueValues(idx)
|
||||
print(len(unique_cd))
|
||||
self.res = {}
|
||||
self.get_status(unique_cd)
|
||||
|
||||
|
||||
def get_status(self,cd_nom):
|
||||
self._pending_downloads += 1
|
||||
url = QUrl(
|
||||
self.url_api
|
||||
+ '?fields=status&cd_nom='
|
||||
+ ','.join(map(str,cd_nom))
|
||||
)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
request.setHeader(QNetworkRequest.CookieHeader, self.cookie)
|
||||
reply = self.network_manager.get(request)
|
||||
reply.finished.connect(lambda: self.import_finished(reply))
|
||||
|
||||
|
||||
def import_finished(self, reply):
|
||||
self._pending_downloads -= 1
|
||||
print(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute))
|
||||
|
||||
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
else:
|
||||
data_request = reply.readAll().data().decode()
|
||||
data = json.loads(data_request)
|
||||
|
||||
self.layer_type = self.layer.wkbType().name
|
||||
self.layer_crs = self.layer.crs()
|
||||
|
||||
bdc = self.v_bdc_status(data)
|
||||
bdc_cd = self._v_bdc_(data,'code')
|
||||
bdc_lab = self._v_bdc_(data,'label')
|
||||
|
||||
self.add_new_layer(bdc)
|
||||
self.add_new_layer(bdc_cd)
|
||||
self.add_new_layer(bdc_lab)
|
||||
|
||||
# remak_data = {
|
||||
# "features" :[
|
||||
# {
|
||||
# "geometry":
|
||||
# json.loads(
|
||||
# QgsGeometry.unaryUnion([
|
||||
# g.geometry() for g in self.layer.getFeatures()
|
||||
# if g.attribute(name_cd_nom) == i['cd_ref']
|
||||
# ]).asJson()
|
||||
# ),
|
||||
# "properties" : i ,
|
||||
# "type": "Feature"
|
||||
# }
|
||||
# for i in data['items']
|
||||
# ],
|
||||
# "type": "FeatureCollection",
|
||||
# "geom_type": "Multi"+layer_type
|
||||
# }
|
||||
# fcString = json.dumps(remak_data)
|
||||
# codec = QTextCodec.codecForName("UTF-8")
|
||||
# fields = QgsJsonUtils.stringToFields(fcString, codec)
|
||||
# feats = QgsJsonUtils.stringToFeatureList(fcString, fields, codec)
|
||||
|
||||
# vl = QgsVectorLayer(remak_data['geom_type'], lay_status_name, "memory")
|
||||
# if vl.sourceCrs() != layer_crs:
|
||||
# print('Changed crs !')
|
||||
# # crs = vl.crs()
|
||||
# # crs.createFromId(self.api['geometry_srid'])
|
||||
# vl.setCrs(layer_crs)
|
||||
|
||||
# dp = vl.dataProvider()
|
||||
# dp.addAttributes(fields)
|
||||
# vl.updateFields()
|
||||
# dp.addFeatures(feats)
|
||||
# vl.updateExtents()
|
||||
|
||||
if self.pending_downloads == 0:
|
||||
self.finished_dl.emit()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
|
||||
def v_bdc_status(self,data):
|
||||
return {
|
||||
"features" :[
|
||||
{
|
||||
"properties" : {**{
|
||||
ii:i[ii]
|
||||
for ii in i if ii != 'status'
|
||||
},
|
||||
**ii
|
||||
},
|
||||
"type": "Feature"
|
||||
}
|
||||
for i in data['items']
|
||||
for ii in i['status']
|
||||
],
|
||||
"type": "FeatureCollection",
|
||||
"geom_type": "No geometry",
|
||||
"layer_name": 'Status - ' + self.layer.name()
|
||||
}
|
||||
|
||||
def _v_bdc_(self,data,type_status):
|
||||
dtype = 'code_statut' if type_status=='code' else 'label_statut'
|
||||
return {
|
||||
"features" :[
|
||||
{
|
||||
"geometry": json.loads(
|
||||
QgsGeometry.unaryUnion([
|
||||
g.geometry() for g in self.layer.getFeatures()
|
||||
if g.attribute(self.cd_nom) == i['cd_ref']
|
||||
]).asJson()
|
||||
),
|
||||
"properties" : {
|
||||
**{
|
||||
ii:i[ii]
|
||||
for ii in i if ii != 'status'
|
||||
}, **{
|
||||
ii['cd_type_statut'] + '_' + ii['cd_sig'].strip('INSEED')
|
||||
if self.multi_dep and 'INSEED' in ii['cd_sig']
|
||||
else ii['cd_type_statut'] : ii[dtype]
|
||||
for ii in i['status']
|
||||
}
|
||||
},
|
||||
"type": "Feature"
|
||||
}
|
||||
for i in data['items']
|
||||
],
|
||||
"type": "FeatureCollection",
|
||||
"geom_type": self.layer_type if "Multi" in self.layer_type else "Multi" + self.layer_type,
|
||||
"layer_name": 'Status %s - '%type_status + self.layer.name()
|
||||
}
|
||||
|
||||
def add_new_layer(self,data):
|
||||
geom_type = data['geom_type']
|
||||
layername = data['layer_name']
|
||||
|
||||
fcString = json.dumps(data)
|
||||
codec = QTextCodec.codecForName("UTF-8")
|
||||
fields = QgsJsonUtils.stringToFields(fcString, codec)
|
||||
feats = QgsJsonUtils.stringToFeatureList(fcString, fields, codec)
|
||||
|
||||
vl = QgsVectorLayer(geom_type, layername, "memory")
|
||||
if vl.sourceCrs() != self.layer_crs:
|
||||
print('Changed crs !')
|
||||
# crs = vl.crs()
|
||||
# crs.createFromId(self.api['geometry_srid'])
|
||||
vl.setCrs(self.layer_crs)
|
||||
|
||||
dp = vl.dataProvider()
|
||||
dp.addAttributes(fields)
|
||||
vl.updateFields()
|
||||
dp.addFeatures(feats)
|
||||
vl.updateExtents()
|
||||
|
||||
QgsProject.instance().addMapLayer(vl)
|
||||
@@ -0,0 +1,441 @@
|
||||
|
||||
# Standard
|
||||
import json
|
||||
|
||||
# PyQt
|
||||
from qgis.core import (
|
||||
QgsAuthMethodConfig,
|
||||
QgsDataSourceUri,QgsVectorLayer,
|
||||
QgsJsonUtils,
|
||||
QgsProject,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsCoordinateTransform
|
||||
)
|
||||
from qgis.PyQt.QtCore import (
|
||||
QByteArray,
|
||||
QJsonDocument,
|
||||
QObject,
|
||||
QUrl,
|
||||
pyqtSignal,
|
||||
QTextCodec,
|
||||
Qt
|
||||
)
|
||||
from qgis.PyQt.QtNetwork import QNetworkReply, QNetworkRequest
|
||||
from qgis.PyQt.QtWidgets import QAction, QMessageBox, QDialog, QApplication
|
||||
|
||||
# from PyQt5.QtCore import Qt
|
||||
# from PyQt5.QtWidgets import QApplication
|
||||
# from PyQt6.QtCore import Qt
|
||||
# from PyQt6.QtWidgets import QApplication
|
||||
# Project
|
||||
from gn_tools.__about__ import (
|
||||
__api_sn_web__,
|
||||
__api_sn_exp__,
|
||||
__api_lst_ex__,
|
||||
__exept_export__,
|
||||
)
|
||||
# from gn_tools.processing import ImportDataGbif
|
||||
from .gbif import ImportDataGbif
|
||||
|
||||
dict_exp = []
|
||||
|
||||
class ParamWidget(QDialog):
|
||||
finished_dl = pyqtSignal()
|
||||
"""
|
||||
Create a filter, specific to GeoNature ZH API and fetch all the features corresponding.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
network_manager=None
|
||||
):
|
||||
super().__init__()
|
||||
print(parent.dlg.tab)
|
||||
self.dlg = parent.dlg
|
||||
self.src_name = parent.src_name
|
||||
self.domain_url = parent.domain_url
|
||||
self.network_manager = network_manager
|
||||
|
||||
# self.zhs = None
|
||||
# self.json_filter = {}
|
||||
# self.total_zh = 0
|
||||
|
||||
self._pending_downloads = 0
|
||||
if self.src_name == 'GBIF':
|
||||
self.dlg.source_import.addItems(['Synthèse GBIF'])
|
||||
self.dlg.source_import.currentTextChanged.connect(
|
||||
self.print_change
|
||||
)
|
||||
else :
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
self.cookie = (network_manager.cookieJar()
|
||||
.cookiesForUrl(QUrl(self.domain_url))[0]
|
||||
)
|
||||
self.send_tab_import()
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
|
||||
def send_tab_import(self):
|
||||
if self.src_name == 'GBIF':
|
||||
self.dlg.source_import.addItems(['Synthèse GBIF'])
|
||||
self.dlg.source_import.currentTextChanged.connect(
|
||||
self.print_change
|
||||
)
|
||||
|
||||
else :
|
||||
self.dlg.source_import.clear()
|
||||
request = self.get_api(api=__api_lst_ex__)
|
||||
reply = self.network_manager.get(request)
|
||||
reply.finished.connect(lambda: self.import_finished(reply))
|
||||
|
||||
# reply_exp
|
||||
# dict_exp = {i for i in exp_all if exp_all[i].geometry_srid and 'sinp' not in exp_all[i].label.lower}
|
||||
# lst_exp = [i.label for i in dict_exp]
|
||||
# # self.dlg.source_import.setText(self.tr("Choose source data"))
|
||||
# self.dlg.source_import.addItems(lst_exp)
|
||||
# self.dlg.source_import.currentTextChanged.connect(
|
||||
# self.print_change
|
||||
# )
|
||||
|
||||
def import_finished(self, reply):
|
||||
self._pending_downloads -= 1
|
||||
QApplication.restoreOverrideCursor()
|
||||
print(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute))
|
||||
|
||||
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
else:
|
||||
self.lst_exp = ['Synthèse taxons']
|
||||
if self.src_name == 'GéoNature':
|
||||
data_request = reply.readAll().data().decode()
|
||||
data = json.loads(data_request)
|
||||
items = data['items']
|
||||
self.dlg.dict_exp = [i for i in items if i['geometry_srid'] ]
|
||||
if len(__exept_export__) > 0:
|
||||
for j in __exept_export__ :
|
||||
self.dlg.dict_exp = [i for i in self.dlg.dict_exp if j not in i['label'].lower()]
|
||||
|
||||
self.lst_exp += [i['label'] for i in self.dlg.dict_exp]
|
||||
|
||||
self.dlg.source_import.addItems(self.lst_exp)
|
||||
self.dlg.source_import.currentTextChanged.connect(
|
||||
self.print_change
|
||||
)
|
||||
|
||||
if self.pending_downloads == 0:
|
||||
self.finished_dl.emit()
|
||||
|
||||
|
||||
|
||||
def print_change(self):
|
||||
print(self.dlg.source_import.currentIndex())
|
||||
|
||||
|
||||
def get_api(self,api=None,apiFilter=None):
|
||||
self._pending_downloads += 1
|
||||
# Function launched two times, one to check zh number the other to dl them
|
||||
url_api = self.domain_url
|
||||
if api:
|
||||
url_api += str(api)
|
||||
url = QUrl(url_api)
|
||||
print(url)
|
||||
|
||||
# Define request properties (cookie, header)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
request.setHeader(QNetworkRequest.CookieHeader, self.cookie)
|
||||
|
||||
if apiFilter:
|
||||
doc = QJsonDocument(self.json_filter)
|
||||
else:
|
||||
doc = QJsonDocument({})
|
||||
|
||||
return request
|
||||
# data_request = reply.readAll().data().decode()
|
||||
# print('tom')
|
||||
# print(data_request)
|
||||
|
||||
# return json.loads(data_request)
|
||||
|
||||
# print(data)
|
||||
|
||||
|
||||
class LoadingImport(QDialog):
|
||||
finished_dl = pyqtSignal()
|
||||
"""
|
||||
Create a filter, specific to GeoNature ZH API and fetch all the features corresponding.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
network_manager=None
|
||||
):
|
||||
super().__init__()
|
||||
print(parent.dlg.tab)
|
||||
self.dlg = parent.dlg
|
||||
self.syn_params = parent.syn_params
|
||||
self.source = self.dlg.source_import.currentText()
|
||||
self.src_name = parent.src_name
|
||||
self.domain_url = parent.domain_url
|
||||
self.network_manager = network_manager
|
||||
self.cookie = (network_manager.cookieJar()
|
||||
.cookiesForUrl(QUrl(self.domain_url))[0]
|
||||
) if self.src_name != 'GBIF' else None
|
||||
self.rectangle = parent.rectangle
|
||||
self.syn_params = parent.syn_params
|
||||
self.project = parent.project
|
||||
|
||||
# self.zhs = None
|
||||
# self.json_filter = {}
|
||||
# self.total_zh = 0
|
||||
|
||||
QApplication.setOverrideCursor(Qt.WaitCursor)
|
||||
self._pending_downloads = 0
|
||||
self.run()
|
||||
|
||||
|
||||
@property
|
||||
def pending_downloads(self):
|
||||
return self._pending_downloads
|
||||
|
||||
|
||||
def run(self,items=None):
|
||||
self._pending_downloads += 1
|
||||
|
||||
self.api = None
|
||||
|
||||
if self.source == 'Synthèse taxons':
|
||||
url_api = self.domain_url + __api_sn_web__
|
||||
self.transform_bouds(4326)
|
||||
url_api += '?limit=800000'
|
||||
|
||||
if self.src_name == 'GéoNature':
|
||||
geo_param = {
|
||||
"geoIntersection": {
|
||||
"type": "Feature",
|
||||
"properties": {},
|
||||
"geometry": json.loads(self.rectangle.asJson())
|
||||
}
|
||||
} if self.rectangle else {}
|
||||
|
||||
elif self.src_name == "Biodiv'AuRA":
|
||||
geo_param = {
|
||||
"geoIntersection": self.rectangle.asWkt(),
|
||||
"with_areas":False
|
||||
} if self.rectangle else {}
|
||||
|
||||
json_param = {
|
||||
"modif_since_validation": False,
|
||||
**geo_param,
|
||||
**self.syn_params
|
||||
}
|
||||
doc = QJsonDocument(
|
||||
json_param
|
||||
)
|
||||
print(doc.toJson())
|
||||
|
||||
elif self.source == 'Synthèse taxons export':
|
||||
url_api = self.domain_url + __api_sn_exp__
|
||||
url_api += '?export_format=geojson'
|
||||
if self.src_name == 'GéoNature':
|
||||
lst_id_synth = [
|
||||
i['properties']['id_synthese']
|
||||
for i in items['features']
|
||||
]
|
||||
elif self.src_name == "Biodiv'AuRA":
|
||||
lst_id_synth = [
|
||||
j['id']
|
||||
for i in items['features']
|
||||
for j in i['properties']['observations']
|
||||
]
|
||||
|
||||
doc = QJsonDocument(lst_id_synth)
|
||||
|
||||
elif self.source == 'Synthèse GBIF':
|
||||
ImportDataGbif(
|
||||
self.network_manager, self.project, self.rectangle
|
||||
)
|
||||
|
||||
# self.close()
|
||||
return QApplication.restoreOverrideCursor()
|
||||
# self.cookie = None
|
||||
# url_api = self.domain_url
|
||||
# url_api += '?advanced=false&geometry={polygon}&offset={offset}'.format(
|
||||
# offset=1, polygon=self.rectangle.asWkt())
|
||||
|
||||
elif self.source in [i['label'] for i in self.dlg.dict_exp]:
|
||||
self.api = [i for i in self.dlg.dict_exp if i['label'] == self.source][0]
|
||||
url_api = self.domain_url + 'api/exports/api/%i'%self.api['id']
|
||||
self.transform_bouds(self.api['geometry_srid'])
|
||||
|
||||
url_api += '?limit=0'
|
||||
if self.rectangle :
|
||||
url_api += "&geometry=" + str(self.rectangle.asWkt())
|
||||
|
||||
url = QUrl(url_api)
|
||||
print(url)
|
||||
# print('crs rect : ',self.rectangle.sourceCrs())
|
||||
|
||||
# Define request properties (cookie, header)
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
|
||||
if self.cookie:
|
||||
request.setHeader(QNetworkRequest.CookieHeader, self.cookie)
|
||||
|
||||
if 'Synthèse taxons' in self.source :
|
||||
reply = self.network_manager.post(request,doc.toJson())
|
||||
else:
|
||||
reply = self.network_manager.get(request)
|
||||
reply.finished.connect(lambda: self.loading_finished(reply))
|
||||
|
||||
|
||||
def loading_finished(self,reply):
|
||||
self._pending_downloads -= 1
|
||||
print(reply.attribute(QNetworkRequest.HttpStatusCodeAttribute))
|
||||
|
||||
if reply.attribute(QNetworkRequest.HttpStatusCodeAttribute) != 200:
|
||||
print(f"code: {reply.error()} message: {reply.errorString()}")
|
||||
else:
|
||||
data_request = reply.readAll().data().decode()
|
||||
data = json.loads(data_request)
|
||||
|
||||
items = data['items'] if 'items' in data.keys() else data
|
||||
|
||||
if self.source == 'Synthèse taxons':
|
||||
self.source = 'Synthèse taxons export'
|
||||
self.run(items)
|
||||
return
|
||||
|
||||
items_point,items_poly,items_line = self.filter_gn_geom(items)
|
||||
|
||||
if items_point['features']:
|
||||
self.addMapLayer(items_point,items_point['geom_type'])
|
||||
if items_poly['features']:
|
||||
self.addMapLayer(items_poly,items_poly['geom_type'])
|
||||
if items_line['features']:
|
||||
self.addMapLayer(items_line,items_line['geom_type'])
|
||||
|
||||
|
||||
if self.pending_downloads == 0:
|
||||
self.finished_dl.emit()
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
print("END")
|
||||
|
||||
def filter_gn_geom(self,items):
|
||||
nb_items = len(items['features'])
|
||||
print('total_count : ',nb_items)
|
||||
items_poly = {"features":[],"type": "FeatureCollection","geom_type": "MultiPolygon"}
|
||||
items_line = {"features":[],"type": "FeatureCollection","geom_type": "MultiLine"}
|
||||
items_point = {
|
||||
"features":[i for i in items['features'] if 'point' in i['geometry']['type'].lower()],
|
||||
"type": "FeatureCollection",
|
||||
"geom_type": "Point"
|
||||
}
|
||||
len_data = len(items_point['features'])
|
||||
if nb_items> len_data:
|
||||
items_poly = {
|
||||
"features":[i for i in items['features'] if 'polygon' in i['geometry']['type'].lower()],
|
||||
"type": "FeatureCollection",
|
||||
"geom_type": "MultiPolygon"
|
||||
}
|
||||
len_data += len(items_poly['features'])
|
||||
if nb_items> len_data:
|
||||
items_line = {
|
||||
"features":[i for i in items['features'] if 'line' in i['geometry']['type'].lower()],
|
||||
"type": "FeatureCollection",
|
||||
"geom_type": "MultiLineString"
|
||||
}
|
||||
len_data += len(items_line['features'])
|
||||
return items_point,items_poly,items_line
|
||||
|
||||
|
||||
# def filter_biodiv_geom(self,items):
|
||||
# items_point = {
|
||||
# "features":[ {
|
||||
# 'geometry' : i['geometry'],
|
||||
# 'properties': j
|
||||
# }
|
||||
# for i in items['features'] if 'point' in i['geometry']['type'].lower()
|
||||
# for j in i['properties']['observations']
|
||||
# ],
|
||||
# "type": "FeatureCollection",
|
||||
# "geom_type": "Point"
|
||||
# }
|
||||
# items_poly = {
|
||||
# "features":[ {
|
||||
# 'geometry' : i['geometry'],
|
||||
# 'properties': j
|
||||
# }
|
||||
# for i in items['features'] if 'polygon' in i['geometry']['type'].lower()
|
||||
# for j in i['properties']['observations']
|
||||
# ],
|
||||
# "type": "FeatureCollection",
|
||||
# "geom_type": "MultiPolygon"
|
||||
# }
|
||||
# items_line = {
|
||||
# "features":[ {
|
||||
# 'geometry' : i['geometry'],
|
||||
# 'properties': j
|
||||
# }
|
||||
# for i in items['features'] if 'line' in i['geometry']['type'].lower()
|
||||
# for j in i['properties']['observations']
|
||||
# ],
|
||||
# "type": "FeatureCollection",
|
||||
# "geom_type": "MultiLineString"
|
||||
# }
|
||||
# return items_point,items_poly,items_line
|
||||
|
||||
|
||||
def addMapLayer(self,data,geom_type):
|
||||
|
||||
mon_layer = ' - '.join([self.src_name[:6], self.source])
|
||||
|
||||
fcString = json.dumps(data)
|
||||
|
||||
codec = QTextCodec.codecForName("UTF-8")
|
||||
fields = QgsJsonUtils.stringToFields(fcString, codec)
|
||||
feats = QgsJsonUtils.stringToFeatureList(fcString, fields, codec)
|
||||
|
||||
if self.api:
|
||||
crs_api = QgsCoordinateReferenceSystem(self.api['geometry_srid'])
|
||||
else :
|
||||
crs_api = QgsCoordinateReferenceSystem(4326)
|
||||
vl = QgsVectorLayer(geom_type, mon_layer, "memory")
|
||||
|
||||
if vl.sourceCrs() != crs_api:
|
||||
print('Changed crs !')
|
||||
# crs = vl.crs()
|
||||
# crs.createFromId(self.api['geometry_srid'])
|
||||
vl.setCrs(crs_api)
|
||||
|
||||
dp = vl.dataProvider()
|
||||
dp.addAttributes(fields)
|
||||
vl.updateFields()
|
||||
dp.addFeatures(feats)
|
||||
vl.updateExtents()
|
||||
|
||||
if dp.errors():
|
||||
msg = QMessageBox()
|
||||
msg.warning(
|
||||
None,
|
||||
self.tr("Warning"),
|
||||
self.tr(
|
||||
"Houston, we've got a problem ... \n\n %s !"%str(dp.errors())
|
||||
), # noqa: E501
|
||||
)
|
||||
QgsProject.instance().addMapLayer(vl)
|
||||
|
||||
|
||||
def transform_bouds(self,crs):
|
||||
sourceCrs = QgsCoordinateReferenceSystem(4326)
|
||||
destCrs = QgsCoordinateReferenceSystem(crs)
|
||||
if sourceCrs != destCrs:
|
||||
tr = QgsCoordinateTransform(sourceCrs, destCrs, self.project)
|
||||
self.rectangle.transform(tr)
|
||||
Reference in New Issue
Block a user