# -*- coding: utf-8 -*- """ /*************************************************************************** Copie A QGIS plugin Permet la copie d'une table dans une base PostGis ------------------- begin : 2015-04-13 git sha : $Format:%H$ copyright : (C) 2015 by Guillaume COSTES - CEN Rhône-Alpes email : guillaume.costes@espaces-naturels.fr ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ """ from __future__ import absolute_import #from PyQt4.QtCore import * #from PyQt4.QtGui import * from qgis.PyQt.QtCore import QSettings from qgis.PyQt.QtWidgets import QAction, QMenu, QDialog, QMessageBox from qgis.PyQt.QtGui import QIcon from PyQt5.QtCore import * from PyQt5.QtGui import * from qgis.core import QgsDataSourceUri from builtins import str from builtins import object from qgis.core import * from qgis.gui import * # Initialize Qt resources from file resources.py from . import resources_rc # Import the code for the dialog from .copie_dialog import CopieDialog import os.path from .PythonSQL import * import psycopg2 import psycopg2.extras import base64 #import socket import os #import sys class Copie(object): """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'Copie_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = CopieDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Copie') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'Copie') self.toolbar.setObjectName(u'Copie') # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('Copie', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/Copie/table_copie.png' self.add_action( icon_path, text=self.tr(u'Copie'), callback=self.run, parent=self.iface.mainWindow()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&Copie'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar def run(self): """Run method that performs all the real work""" layer = self.iface.activeLayer() if layer == None : #self.iface.messageBar().pushMessage(u"Vous devez sélectionner une table !", level=QgsMessageBar.WARNING, duration=5) self.iface.messageBar().pushMessage("Ooops", u"Vous devez sélectionner une table !", level=Qgis.Warning, duration=5) else : # Récupération des sources de la couche active list_sources = layer.source().split(" ") # dbname source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] # schema source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] # tablename source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] if source_db != sigdb: #self.iface.messageBar().pushMessage(u"Un référentiel ne peut être copié, utilisez les filtres !", level=QgsMessageBar.CRITICAL, duration=10) self.iface.messageBar().pushMessage("Ooops", u"Vous ne pouvez copier des couches que dans sigXX", level=Qgis.Critical, duration=5) else : first_conn = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=first_cnx password=" + password) first_cur = first_conn.cursor(cursor_factory = psycopg2.extras.DictCursor) first_cur.execute("SELECT mdp_w, login_w FROM pg_catalog.pg_user t1, admin_sig.vm_users_sig t2 WHERE t2.oid = t1.usesysid AND (login_w = '" + os_user + "' OR login_w = '" + os_user + "')") res_ident = first_cur.fetchone() mdp = base64.b64decode(str(res_ident[0])).decode('utf-8') user = res_ident[1] con = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory = psycopg2.extras.DictCursor) first_conn.close() # Creation de la liste des schemas de la base de donnees SQL = """WITH list_schema AS ( SELECT catalog_name, schema_name FROM information_schema.schemata WHERE schema_name <> 'information_schema' AND schema_name !~ E'^pg_' ORDER BY schema_name ) SELECT string_agg(schema_name,',') FROM list_schema GROUP BY catalog_name""" cur.execute(SQL) list_brut = str(next(cur)) list = list_brut [2:-3] listItems = list.split(",") con.close() self.dlg.schema.clear() self.dlg.schema.addItems(listItems) self.dlg.schema.setCurrentIndex(-1) # Pour ne pas commencer la liste au premier schema self.dlg.table_source.setText(source_schema + "." + source_tablename) # Affiche le nom de la table source # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result: #******************************debut script********************************* first_conn = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=first_cnx password=" + password) first_cur = first_conn.cursor(cursor_factory = psycopg2.extras.DictCursor) first_cur.execute("SELECT mdp_w, login_w FROM pg_catalog.pg_user t1, admin_sig.vm_users_sig t2 WHERE t2.oid = t1.usesysid AND (login_w = '" + os_user + "' OR login_w = '" + os_user + "')") res_ident = first_cur.fetchone() mdp = base64.b64decode(str(res_ident[0])).decode('utf-8') user = res_ident[1] con = psycopg2.connect("host=" + host + " port=" + port + " dbname="+dbname+" user=" + user + " password=" + mdp) cur = con.cursor(cursor_factory = psycopg2.extras.DictCursor) first_conn.close() # Récupération de la couche active layer = self.iface.activeLayer() # Récupération des sources de la couche active list_sources = layer.source().split(" ") # dbname source_db = [s for s in list_sources if "dbname" in s][0].split("'")[1] # schema source_schema = [s for s in list_sources if "table" in s][0].split('"')[1] # tablename source_tablename = [s for s in list_sources if "table" in s][0].split('"')[3] if self.dlg.schema.currentIndex() == -1 : QMessageBox.warning(None, "Oups :", "Veuillez choisir un dossier de destination.") return schema = self.dlg.schema.currentText() if self.dlg.table_destination.text() == '' : QMessageBox.warning(None, "Oups :", "Veuillez choisir un nom de destination.") return if self.dlg.annee.text() == 'aaaa' or self.dlg.annee.text() == '': tablename = schema + "_" + self.dlg.table_destination.text().lower() else : tablename = schema + "_" + self.dlg.table_destination.text().lower() + "_" + self.dlg.annee.text() tablename_qgis = tablename[1:] # Permet d'enlever le "_", ajouter a la premiere etape, dans qgis if self.dlg.table_vide.isChecked() == 1 : SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename + " LIMIT 0;" else : SQL_table = "CREATE TABLE " + schema + "." + tablename + " AS SELECT * FROM " + source_schema + "." + source_tablename SQL_pkey = "ALTER TABLE " + schema + "." + tablename + " ADD CONSTRAINT " + tablename + "_pkey" + " PRIMARY KEY (gid)" SQL_sequence_01 = "CREATE SEQUENCE " + schema + "." + tablename + "_gid_seq" + " INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 CACHE 1;" SQL_sequence_02 = "ALTER TABLE " + schema + "." + tablename + " ALTER COLUMN gid SET DEFAULT nextval(\'" + schema + "." + tablename + "_gid_seq\'::regclass);" SQL_sequence_03 = "SELECT setval(\'" + schema + "." + tablename + "_gid_seq\'::regclass, (SELECT max(gid) AS max_gid FROM " + schema + "." + tablename + "));" SQL_sequence_04 = "ALTER SEQUENCE " + schema + "." + tablename + "_gid_seq" + " OWNED BY " + schema + "." + tablename + ".gid;" SQL_trigger_area_m2 = "CREATE TRIGGER area_m2" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_m2();" SQL_trigger_area_ha = "CREATE TRIGGER area_ha" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.area_ha();" SQL_trigger_length_m = "CREATE TRIGGER length_m" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_m();" SQL_trigger_length_km = "CREATE TRIGGER length_km" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.length_km();" SQL_trigger_coordonnees = "CREATE TRIGGER coordonnees" + tablename + " BEFORE INSERT OR UPDATE ON " + schema + "." + tablename + " FOR EACH ROW EXECUTE PROCEDURE ref.coordonnees();" cur.execute(SQL_table) cur.execute(SQL_pkey) cur.execute(SQL_sequence_01) cur.execute(SQL_sequence_02) cur.execute(SQL_sequence_03) cur.execute(SQL_sequence_04) if layer.wkbType() == QgsWkbTypes.PointGeometry : cur.execute(SQL_trigger_coordonnees) if layer.wkbType() == QgsWkbTypes.LineGeometry : cur.execute(SQL_trigger_length_m) cur.execute(SQL_trigger_length_km) if layer.wkbType() == QgsWkbTypes.PolygonGeometry : cur.execute(SQL_trigger_area_m2) cur.execute(SQL_trigger_area_ha) con.commit() ### Affichage de la table uri = QgsDataSourceUri() # set host name, port, database name, username and password uri.setConnection(host ,port ,dbname ,user ,mdp) # set database schema, table name, geometry column and optionaly subset (WHERE clause) uri.setDataSource(schema, tablename, geom) layer = self.iface.addVectorLayer(uri.uri(), tablename_qgis, "postgres") con.commit() con.close() #self.iface.messageBar().pushMessage("Table \"" + source_schema + "." + source_tablename + u"\" copiée dans \"" + schema + "." + tablename + "\"." , level=QgsMessageBar.INFO, duration=10) self.iface.messageBar().pushMessage("Bravo!", "Table \"" + source_schema + "." + source_tablename + u"\" copiée dans \"" + schema + "." + tablename + "\".", level=Qgis.Success, duration=5) pass