def checkParameterValues(self, parameters, context): # Check if run migrations is checked run_migrations = self.parameterAsBool(parameters, self.RUN_MIGRATIONS, context) if not run_migrations: msg = tr("You must use the checkbox to do the upgrade !") return False, msg if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString(parameters, self.CONNECTION_NAME, context) metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) if not connection: raise QgsProcessingException( tr("The connection {} does not exist.").format( connection_name)) if SCHEMA in connection.schemas(): override = self.parameterAsBool(parameters, self.RUN_MIGRATIONS, context) if not override: msg = tr( "The schema {} already exists in the database {} ! " "If you really want to remove and recreate the schema (and remove its data)," " use the checkbox.").format(SCHEMA, connection_name) return False, msg return super().checkParameterValues(parameters, context)
def add_flatten_dataset_table(self): """ Add a flatten dataset table with all links and contacts. """ connections, message = connections_list() if not connections: LOGGER.critical(message) self.set_html_content('PgMetadata', message) return if len(connections) > 1: dialog = QInputDialog() dialog.setComboBoxItems(connections) dialog.setWindowTitle(tr("Database")) dialog.setLabelText(tr("Choose the database to add the catalog")) if not dialog.exec_(): return connection_name = dialog.textValue() else: connection_name = connections[0] metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) locale = QgsSettings().value("locale/userLocale", QLocale().name()) locale = locale.split('_')[0].lower() uri = QgsDataSourceUri(connection.uri()) uri.setTable(f'(SELECT * FROM pgmetadata.export_datasets_as_flat_table(\'{locale}\'))') uri.setKeyColumn('uid') layer = QgsVectorLayer(uri.uri(), '{} - {}'.format(tr("Catalog"), connection_name), 'postgres') QgsProject.instance().addMapLayer(layer)
def shortHelpString(self): msg = tr( "When you are running the plugin for the first time on a new database, you need to install the " "database schema.") msg += '\n\n' msg += tr("It will erase and/or create the schema '{}'.").format(SCHEMA) msg += '\n\n' msg += self.parameters_help_string() return msg
def export_dock_content(self, output_format: OutputFormats): """ Export the current displayed metadata sheet to the given format. """ layer_name = iface.activeLayer().name() file_path = os.path.join( self.settings.value("UI/lastFileNameWidgetDir"), '{name}.{ext}'.format(name=layer_name, ext=output_format.value['ext'])) output_file = QFileDialog.getSaveFileName( self, tr("Save File as {format}").format( format=output_format.value['label']), file_path, "{label} (*.{ext})".format( label=output_format.value['label'], ext=output_format.value['ext'], )) if output_file[0] == '': return self.settings.setValue("UI/lastFileNameWidgetDir", os.path.dirname(output_file[0])) if output_format == OutputFormats.Pdf: printer = QPrinter() printer.setOutputFormat(QPrinter.PdfFormat) printer.setPageMargins(20, 20, 20, 20, QPrinter.Millimeter) printer.setOutputFileName(output_file[0]) self.viewer.print(printer) iface.messageBar().pushSuccess( tr("Export PDF"), tr("The metadata has been exported as PDF successfully")) elif output_format in [OutputFormats.Html, OutputFormats.Dcat]: if output_format == OutputFormats.Html: data_str = self.viewer.page().currentFrame().toHtml() else: sql = self.sql_for_layer(self.current_datasource_uri, output_format=OutputFormats.Dcat) data = self.current_connection.executeSql(sql) with open(resources_path('xml', 'dcat.xml')) as xml_file: xml_template = xml_file.read() locale = QgsSettings().value("locale/userLocale", QLocale().name()) locale = locale.split('_')[0].lower() xml = parseString( xml_template.format(locale=locale, content=data[0][0])) data_str = xml.toprettyxml() file_writer = open(output_file[0], "w") file_writer.write(data_str) file_writer.close() iface.messageBar().pushSuccess( tr("Export") + ' ' + output_format.value['label'], tr("The metadata has been exported as {format} successfully"). format(format=output_format.value['label']))
def shortHelpString(self): short_help = tr( 'This algorithm will create a new QGIS project file for PgMetadata administration purpose.') short_help += '\n\n' short_help += tr( 'The generated QGIS project must then be opened by the administrator ' 'to create the needed metadata by using QGIS editing capabilities.') short_help += '\n\n' short_help += self.parameters_help_string() return short_help
def initAlgorithm(self, config): connections, _ = connections_list() if connections: connection_name = connections[0] else: connection_name = '' label = tr("Connection to the PostgreSQL database") tooltip = tr( "The database where the schema '{}' is installed.").format(SCHEMA) if Qgis.QGIS_VERSION_INT >= 31400: param = QgsProcessingParameterProviderConnection( self.CONNECTION_NAME, label, "postgres", defaultValue=connection_name, optional=False, ) else: param = QgsProcessingParameterString( self.CONNECTION_NAME, label, defaultValue=connection_name, optional=False, ) param.setMetadata({ "widget_wrapper": { "class": "processing.gui.wrappers_postgis.ConnectionWidgetWrapper" } }) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) param = QgsProcessingParameterBoolean( self.RUN_MIGRATIONS, tr("Use this checkbox to upgrade."), defaultValue=False, ) tooltip = tr( "For security reason, we ask that you explicitly use this checkbox." ) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) self.addOutput( QgsProcessingOutputString(self.DATABASE_VERSION, tr("Database version")))
def initAlgorithm(self, config): connections, _ = connections_list() if connections: connection_name = connections[0] else: connection_name = '' label = tr("Connection to the PostgreSQL database") tooltip = tr("The database where the schema '{}' will be installed.").format(SCHEMA) if Qgis.QGIS_VERSION_INT >= 31400: param = QgsProcessingParameterProviderConnection( self.CONNECTION_NAME, label, "postgres", defaultValue=connection_name, optional=False, ) else: param = QgsProcessingParameterString( self.CONNECTION_NAME, label, defaultValue=connection_name, optional=False, ) param.setMetadata( { "widget_wrapper": { "class": "processing.gui.wrappers_postgis.ConnectionWidgetWrapper" } } ) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) param = QgsProcessingParameterBoolean( self.OVERRIDE, tr("Erase the schema {} ?").format(SCHEMA), defaultValue=False, ) tooltip = tr("** Be careful ** This will remove data in the schema !") if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) self.addOutput( QgsProcessingOutputString(self.DATABASE_VERSION, tr("Database version")) )
def initAlgorithm(self, config): connections, _ = connections_list() if connections: connection_name = connections[0] else: connection_name = '' label = tr("Connection to the PostgreSQL database") tooltip = tr("The database where the schema '{}' is installed.").format(SCHEMA) if Qgis.QGIS_VERSION_INT >= 31400: param = QgsProcessingParameterProviderConnection( self.CONNECTION_NAME, label, "postgres", defaultValue=connection_name, optional=False, ) else: param = QgsProcessingParameterString( self.CONNECTION_NAME, label, defaultValue=connection_name, optional=False, ) param.setMetadata( { "widget_wrapper": { "class": "processing.gui.wrappers_postgis.ConnectionWidgetWrapper" } } ) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) # target project file param = QgsProcessingParameterFileDestination( self.PROJECT_FILE, tr('QGIS project file to create'), defaultValue='', optional=False, fileFilter='QGS project (*.qgs)', ) tooltip = tr("The destination file where to create the QGIS project.").format(SCHEMA) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param)
def initAlgorithm(self, config): connections, _ = connections_list() if connections: connection_name = connections[0] else: connection_name = '' label = tr("Connection to the PostgreSQL database") tooltip = tr("The database where the schema '{}' has been installed." ).format(SCHEMA) if Qgis.QGIS_VERSION_INT >= 31400: param = QgsProcessingParameterProviderConnection( self.CONNECTION_NAME, label, "postgres", defaultValue=connection_name, optional=False, ) else: param = QgsProcessingParameterString( self.CONNECTION_NAME, label, defaultValue=connection_name, optional=False, ) param.setMetadata({ "widget_wrapper": { "class": "processing.gui.wrappers_postgis.ConnectionWidgetWrapper" } }) if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param) param = QgsProcessingParameterBoolean( self.RESET, tr("Reset HTML templates"), defaultValue=False, ) tooltip = tr( "** Be careful ** This will reset existing HTML templates !") if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param)
def shortHelpString(self): msg = tr( "When the plugin is upgraded, a database upgrade may be available as well. The database " "migration must be applied as well on the existing database.") msg += '\n\n' msg += self.parameters_help_string() return msg
def processAlgorithm(self, parameters, context, feedback): if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString( parameters, self.CONNECTION_NAME, context) # Write the file out again project_file = self.parameterAsString(parameters, self.PROJECT_FILE, context) metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) # Read in the template file template_file = resources_path('projects', 'pg_metadata_administration.qgs') with open(template_file, 'r') as fin: file_data = fin.read() # Replace the database connection information file_data = file_data.replace("service='pgmetadata'", connection.uri()) with open(project_file, 'w') as fout: fout.write(file_data) add_connection(connection_name) msg = tr('QGIS Administration project has been successfully created from the database connection') msg += ': {}'.format(connection_name) feedback.pushInfo(msg) return {}
def connections_list() -> tuple: """ List of available connections to PostgreSQL database. """ migrate_from_global_variables_to_pgmetadata_section() metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection_names = settings_connections_names() if not connection_names: message = tr( "You must use the 'Set Connections' algorithm in the Processing toolbox. The plugin must be " "aware about the database to use. Multiple databases can be set.") return (), message connections = list() for name in connection_names.split(';'): try: metadata.findConnection(name) except QgsProviderConnectionException: # Todo, we must log something pass else: connections.append(name) return connections, None
def shortHelpString(self): short_help = tr( 'This algorithm will enable different databases where to look for metadata.' ) short_help += '\n\n' short_help += self.parameters_help_string() return short_help
def processAlgorithm(self, parameters, context, feedback): metadata = QgsProviderRegistry.instance().providerMetadata('postgres') if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString(parameters, self.CONNECTION_NAME, context) connection = metadata.findConnection(connection_name) if not connection: raise QgsProcessingException( tr("The connection {} does not exist.").format( connection_name)) sql = "SELECT pgmetadata.refresh_dataset_calculated_fields();" try: connection.executeSql(sql) except QgsProviderConnectionException as e: feedback.reportError(str(e)) add_connection(connection_name) results = {} return results
def checkParameterValues(self, parameters, context): # Check if the target project file ends with qgs project_file = self.parameterAsString(parameters, self.PROJECT_FILE, context) if not project_file.endswith('.qgs'): return False, tr('The QGIS project file name must end with extension ".qgs"') return super().checkParameterValues(parameters, context)
def default_html_content_not_installed(self): """ When PgMetadata is not installed correctly or not at all. """ message = "<p>" message += tr("The 'pgmetadata' schema is not installed or configured.") message += "</p>" message += "<p>" message += tr( "Either install PgMetadata on a database (Processing → Database → Installation of the " "database structure) or make the link to an existing PgMetadata database (Processing → " "Administration → Set connections to database)." ) message += "</p>" message += "<p>" message += tr( "Visit the documentation on <a href=\"https://docs.3liz.org/qgis-pgmetadata-plugin/\">" "docs.3liz.org</a> to check how to setup PgMetadata." ) message += "</p>" self.set_html_content('PgMetadata', message)
def processAlgorithm(self, parameters, context, feedback): metadata = QgsProviderRegistry.instance().providerMetadata('postgres') if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString(parameters, self.CONNECTION_NAME, context) connection = metadata.findConnection(connection_name) if not connection: raise QgsProcessingException( tr("The connection {} does not exist.").format( connection_name)) for template in ["contact", "link", "main"]: feedback.pushInfo(tr('Reset {}.html').format(template)) sql = ("DELETE FROM pgmetadata.html_template " "WHERE section = '{}'").format(template) try: connection.executeSql(sql) except QgsProviderConnectionException as e: feedback.reportError(str(e)) html_file = resources_path("html", "{}.html".format(template)) with open(html_file, "r") as f: sql = ( "INSERT INTO pgmetadata.html_template (section, content) " "VALUES ('{section}', '{value}');".format(section=template, value=f.read())) try: connection.executeSql(sql) except QgsProviderConnectionException as e: feedback.reportError(str(e)) add_connection(connection_name) results = {} return results
def processAlgorithm(self, parameters, context, feedback): metadata = QgsProviderRegistry.instance().providerMetadata('postgres') names = list(metadata.connections().keys()) databases = self.parameterAsEnums(parameters, self.DATABASES, context) database_names = [names[i] for i in databases] reset_connections() for database in database_names: feedback.pushDebugInfo(tr("Setting up : {}").format(database)) add_connection(database) return {}
def checkParameterValues(self, parameters, context): if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString(parameters, self.CONNECTION_NAME, context) metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) if not connection: raise QgsProcessingException( tr("The connection {} does not exist.").format( connection_name)) reset = self.parameterAsBool(parameters, self.RESET, context) if not reset: msg = tr("You must use the checkbox to do the reset !") return False, msg return super().checkParameterValues(parameters, context)
def fetchResults(self, search, context, feedback): if len(search) < 3: # Let's limit the number of request sent to the server return connections, message = connections_list() if not connections: self.logMessage(message, Qgis.Critical) for connection in connections: if not check_pgmetadata_is_installed(connection): self.logMessage( tr('PgMetadata is not installed on {}').format(connection), Qgis.Critical) continue self.fetch_result_single_database(search, connection)
def database_version( connection: QgsAbstractDatabaseProviderConnection) -> str: """ Get database version. """ sql = ("SELECT version " "FROM {}.qgis_plugin " "WHERE status = 1 " "ORDER BY version_date DESC " "LIMIT 1;").format(SCHEMA) try: data = connection.executeSql(sql) except QgsProviderConnectionException as e: raise QgsProcessingException(str(e)) db_version = None for row in data: db_version = row[0] if not db_version: error_message = tr("No version has been found in the database !") raise QgsProcessingException(error_message) return db_version
def fetch_result_single_database(self, search: str, connection_name: str): """ Fetch tables in the given database for a search. """ connection = self.metadata.findConnection(connection_name) if not connection: self.logMessage( tr("The global variable {}_connection_name is not correct."). format(SCHEMA), Qgis.Critical) # Search items from pgmetadata.dataset sql = " SELECT concat(d.title, ' (', d.table_name, '.', d.schema_name, ')') AS displayString," sql += " d.schema_name, d.table_name, d.geometry_type, title" sql += " FROM pgmetadata.dataset d" sql += " INNER JOIN pgmetadata.v_valid_dataset v" sql += " ON concat(v.table_name, '.', v.schema_name) = concat(d.table_name, '.', d.schema_name)" sql += " WHERE concat(d.title, ' ', d.abstract, ' ', d.table_name) ILIKE '%{}%'".format( search) sql += " LIMIT 100" try: data = connection.executeSql(sql) except QgsProviderConnectionException as e: self.logMessage(str(e), Qgis.Critical) return if not data: return for item in data: result = QgsLocatorResult() result.filter = self result.displayString = item[0] result.icon = icon_for_geometry_type(item[3]) result.userData = { 'name': item[4], 'connection': connection_name, 'schema': item[1], 'table': item[2], } self.resultFetched.emit(result)
def initAlgorithm(self, config): # Get existing connections metadata = QgsProviderRegistry.instance().providerMetadata('postgres') names = list(metadata.connections().keys()) existing_connections = [] for i, name in enumerate(names): if name in connections_list()[0]: existing_connections.append(i) param = QgsProcessingParameterEnum( self.DATABASES, 'List of databases to look for metadata', options=names, defaultValue=existing_connections, ) param.setAllowMultiple(True) tooltip = tr("PgMetadata can be installed on different databases.") if Qgis.QGIS_VERSION_INT >= 31600: param.setHelp(tooltip) else: param.tooltip_3liz = tooltip self.addParameter(param)
def group(self): return tr('Database')
def group(self): return tr('Administration')
def displayName(self): return tr('Set connections to databases')
def displayName(self): return tr("Installation of the database structure")
def displayName(self): return tr('Create metadata administration project')
def displayName(self): return tr("Upgrade the database structure")
def processAlgorithm(self, parameters, context, feedback): if Qgis.QGIS_VERSION_INT >= 31400: connection_name = self.parameterAsConnectionName( parameters, self.CONNECTION_NAME, context) else: connection_name = self.parameterAsString(parameters, self.CONNECTION_NAME, context) metadata = QgsProviderRegistry.instance().providerMetadata('postgres') connection = metadata.findConnection(connection_name) connection: QgsAbstractDatabaseProviderConnection if not connection: raise QgsProcessingException( tr("The connection {} does not exist.").format( connection_name)) if not connection.tableExists(SCHEMA, 'qgis_plugin'): raise QgsProcessingException( tr("The table {}.{} does not exist. You must first create the database structure." ).format(SCHEMA, 'qgis_plugin')) db_version = self.database_version(connection) feedback.pushInfo("Current database version '{}'.".format(db_version)) # Get plugin version plugin_version = version() if plugin_version in ["master", "dev"]: migrations = available_migrations(000000) last_migration = migrations[-1] plugin_version = (last_migration.replace("upgrade_to_", "").replace(".sql", "").strip()) feedback.reportError( tr("Be careful, running the migrations on a development branch!" )) feedback.reportError( tr("Latest available migration is {}").format(plugin_version)) else: feedback.pushInfo( tr("Plugin's version is {}").format(plugin_version)) results = {self.DATABASE_VERSION: plugin_version} # Return if nothing to do if db_version == plugin_version: feedback.pushInfo( tr("The database version and the plugin version are the same, version {}. There isn't any " "upgrade to do.").format(plugin_version)) return results db_version_integer = format_version_integer(db_version) sql_files = available_migrations(db_version_integer) # Loop sql files and run SQL code for sf in sql_files: sql_file = os.path.join(plugin_path(), "install/sql/upgrade/{}".format(sf)) with open(sql_file, "r") as f: sql = f.read() if len(sql.strip()) == 0: feedback.pushInfo("* " + sf + " -- " + tr("SKIPPING, EMPTY FILE")) continue try: connection.executeSql(sql) except QgsProviderConnectionException as e: raise QgsProcessingException(str(e)) new_db_version = (sf.replace("upgrade_to_", "").replace(".sql", "").strip()) self.update_database_version(connection, new_db_version) feedback.pushInfo( "Database version {} -- OK !".format(new_db_version)) self.vacuum_all_tables(connection, feedback) self.update_database_version(connection, plugin_version) feedback.pushInfo( "Database upgraded to the current plugin version {}!".format( plugin_version)) add_connection(connection_name) return results