Load one or all database nodes for a server

With a given connection, it is now possible to specify the number of
database nodes for a server: Only one node with the explicit given
database can be loaded or all databases on the server. This is realized
by an extra parameter for the database connection in the tree model and
connection dialog.
This commit is contained in:
Lea Laux 2020-12-08 16:42:42 +01:00 committed by KDV Admin
parent 3ad999f90d
commit ee5ba1eafe
4 changed files with 109 additions and 13 deletions

View File

@ -118,6 +118,28 @@ class ConnectionStore:
if connection_parameter_dictionary["Username"] == connection_parameter_dictionary_for_check["Username"] \ if connection_parameter_dictionary["Username"] == connection_parameter_dictionary_for_check["Username"] \
and connection_parameter_dictionary["Host"] == connection_parameter_dictionary_for_check["Host"] \ and connection_parameter_dictionary["Host"] == connection_parameter_dictionary_for_check["Host"] \
and connection_parameter_dictionary["Port"] == connection_parameter_dictionary_for_check["Port"]: and connection_parameter_dictionary["Port"] == connection_parameter_dictionary_for_check["Port"]:
# If the two dictionaries contain a parameter for loading all databases, check them for their equality.
# If they are not equal, the given connection has changed.
if "Load All" in connection_parameter_dictionary \
and "Load All" in connection_parameter_dictionary_for_check:
if connection_parameter_dictionary["Load All"] \
!= connection_parameter_dictionary_for_check["Load All"]:
return False
# If only one dictionary has a key for "Load All", there is a change in the connection parameters.
elif "Load All" in connection_parameter_dictionary \
or "Load All" in connection_parameter_dictionary_for_check:
return False
# If load all in the check dictionary is False and if the databases are not the same, the connection has
# changed, because only one database is used. One database is not a universal enter point in this case.
if "Load All" in connection_parameter_dictionary_for_check \
and connection_parameter_dictionary_for_check["Load All"] is False \
and connection_parameter_dictionary["Database"] \
!= connection_parameter_dictionary_for_check["Database"]:
return False
return True return True
# If a duplicate is not found, this else branch is active. # If a duplicate is not found, this else branch is active.
@ -217,5 +239,22 @@ class ConnectionStore:
except IndexError: except IndexError:
return None return None
def get_connection_load_all_information(self, host, database, port, username):
"""
Get the load all information of one connection defined by its host, database, port and username.
"""
# Find in all current parameters the one with the correct host, database, port and username.
for parameters in self.connection_parameters_yaml:
if host == parameters["Host"] and database == parameters["Database"] and port == parameters["Port"] \
and username == parameters["Username"]:
# Try to get the parameter for loading all databases. This parameter could not exist in the dictionary.
try:
return parameters["Load All"]
except KeyError:
return False
global_connection_store = ConnectionStore() global_connection_store = ConnectionStore()

View File

@ -199,7 +199,7 @@ class ServerNode(AbstractBaseNode):
Create a class for server nodes based on the class AbstractBaseNode. Create a class for server nodes based on the class AbstractBaseNode.
""" """
def __init__(self, name, host, user, port, database="postgres", timeout=1000): def __init__(self, name, host, user, port, database="postgres", timeout=1000, load_all_databases=True):
# Use the database postgres, because this database should definitely exist on a database server and is used as # Use the database postgres, because this database should definitely exist on a database server and is used as
# entry point here. # entry point here.
super().__init__(name, host, user, database, port, timeout) super().__init__(name, host, user, database, port, timeout)
@ -212,8 +212,16 @@ class ServerNode(AbstractBaseNode):
node_icon_path = os.path.join(os.path.dirname(pygadmin.__file__), "icons", node_icon_path = os.path.join(os.path.dirname(pygadmin.__file__), "icons",
"{}_valid.svg".format(self._node_type.lower())) "{}_valid.svg".format(self._node_type.lower()))
# If all databases should be loaded, this parameter is True. This is a default parameter.
if load_all_databases is True:
child = None
# If the parameter is not True, only one database should be loaded.
else:
child = database
# Get the children with a query. # Get the children with a query.
self.get_children_with_query() self.get_children_with_query(child)
else: else:
# Use the server icon for a invalid connection. # Use the server icon for a invalid connection.
@ -232,14 +240,22 @@ class ServerNode(AbstractBaseNode):
return child return child
def get_children_with_query(self): def get_children_with_query(self, child=None):
""" """
Get all children of the node with a database query. Get all children of the node with a database query. As default, get all the children of the node, but use an
option for only getting one given child.
""" """
# If one explicit child is not given, get all the children of the server node.
if child is None:
# Use a query to get all children, in this case, all the database nodes. # Use a query to get all children, in this case, all the database nodes.
self.fetch_children(DatabaseNode, "SELECT datname FROM pg_database ORDER BY datname ASC;") self.fetch_children(DatabaseNode, "SELECT datname FROM pg_database ORDER BY datname ASC;")
# If an explicit child is given, load the one explicit child.
else:
self.fetch_children(DatabaseNode, "SELECT datname FROM pg_database WHERE datname=%s ORDER BY datname ASC;",
[child])
class DatabaseNode(AbstractBaseNode): class DatabaseNode(AbstractBaseNode):
""" """

View File

@ -73,6 +73,10 @@ class ConnectionDialogWidget(QDialog):
self.show() self.show()
def init_line_edit_ui(self): def init_line_edit_ui(self):
"""
Initialize the line edits.
"""
# Make a list for storing the QLabels for every connection parameter. This is necessary for using the QLabel in # Make a list for storing the QLabels for every connection parameter. This is necessary for using the QLabel in
# the layout setting. # the layout setting.
self.connection_parameter_label_list = [] self.connection_parameter_label_list = []
@ -213,6 +217,11 @@ class ConnectionDialogWidget(QDialog):
# Connect the state change to a function for handling a change in the checked status of the checkbox. # Connect the state change to a function for handling a change in the checked status of the checkbox.
self.use_postgres_database_checkbox.stateChanged.connect(self.set_database_edit_field_to_checkbox) self.use_postgres_database_checkbox.stateChanged.connect(self.set_database_edit_field_to_checkbox)
# Create a checkbox for loading all databases as a configurable parameter.
self.load_all_databases_checkbox = QCheckBox("Load all databases")
# Set the default as checked.
self.load_all_databases_checkbox.setChecked(True)
# Create a checkbox for usage in specific cases. # Create a checkbox for usage in specific cases.
self.open_at_start_checkbox = QCheckBox("Open always a connection dialog at start") self.open_at_start_checkbox = QCheckBox("Open always a connection dialog at start")
@ -242,8 +251,8 @@ class ConnectionDialogWidget(QDialog):
# This case happens for the label of the port. # This case happens for the label of the port.
else: else:
# The label is placed further down, so the checkbox for the default database is placed accurate. # The label is placed further down, so the checkboxes for the database are placed accurate.
grid_layout.addWidget(self.connection_parameter_label_list[parameter_number], parameter_number + 2, 2) grid_layout.addWidget(self.connection_parameter_label_list[parameter_number], parameter_number + 3, 2)
# Use an incrementer for the next for loop. # Use an incrementer for the next for loop.
connection_parameter_edit_incrementer = 1 connection_parameter_edit_incrementer = 1
@ -259,7 +268,8 @@ class ConnectionDialogWidget(QDialog):
if connection_parameter == "Database": if connection_parameter == "Database":
# Place the checkbox under the QLineEdit for the database. # Place the checkbox under the QLineEdit for the database.
grid_layout.addWidget(self.use_postgres_database_checkbox, connection_parameter_edit_incrementer, 3) grid_layout.addWidget(self.use_postgres_database_checkbox, connection_parameter_edit_incrementer, 3)
connection_parameter_edit_incrementer += 1 grid_layout.addWidget(self.load_all_databases_checkbox, connection_parameter_edit_incrementer + 1, 3)
connection_parameter_edit_incrementer += 2
# The port as the parameter which belongs to this checkbox is the last one in the list for the user, so this # The port as the parameter which belongs to this checkbox is the last one in the list for the user, so this
# checkbox is placed below the QLineEdit for the port. # checkbox is placed below the QLineEdit for the port.
@ -468,12 +478,14 @@ class ConnectionDialogWidget(QDialog):
return return
# Define the parameter in a dictionary which is required by the connection store. # Define the parameters in a dictionary which is required by the connection store.
connection_parameters = {"Host": self.connection_parameter_edit_dictionary["Host"].text(), connection_parameters = {"Host": self.connection_parameter_edit_dictionary["Host"].text(),
"Username": self.connection_parameter_edit_dictionary["Username"].text(), "Username": self.connection_parameter_edit_dictionary["Username"].text(),
"Database": self.connection_parameter_edit_dictionary["Database"].text(), "Database": self.connection_parameter_edit_dictionary["Database"].text(),
# The port is used as integer number, not as string. # The port is used as integer number, not as string.
"Port": int(self.connection_parameter_edit_dictionary["Port"].text()) "Port": int(self.connection_parameter_edit_dictionary["Port"].text()),
# Get the status for loading all databases out of the checkbox.
"Load All": self.load_all_databases_checkbox.isChecked()
} }
return connection_parameters, connection_identifier, changed_password return connection_parameters, connection_identifier, changed_password
@ -861,6 +873,19 @@ class ConnectionDialogWidget(QDialog):
# Use the port as string, because all elements of the QLineEdit have to be strings. # Use the port as string, because all elements of the QLineEdit have to be strings.
str(self.selected_connection_parameters_dictionary["Port"])) str(self.selected_connection_parameters_dictionary["Port"]))
# Get the status for loading all databases for the selected connection.
load_all_databases = global_connection_store.get_connection_load_all_information(
self.selected_connection_parameters_dictionary["Host"],
self.selected_connection_parameters_dictionary["Database"],
self.selected_connection_parameters_dictionary["Port"],
self.selected_connection_parameters_dictionary["Username"]
)
# Set the status as status of the checkbox.
self.load_all_databases_checkbox.setChecked(load_all_databases)
# Save the status in the dictionary for the selected connection.
self.selected_connection_parameters_dictionary["Load All"] = load_all_databases
# Define a password identifier for recognition in the password manager and keyring. # Define a password identifier for recognition in the password manager and keyring.
password_identifier = self.selected_connection_identifier.split("/")[0] password_identifier = self.selected_connection_identifier.split("/")[0]
# Set the password as text in the QLineEdit. This is not a security flaw, because it is protected by the # Set the password as text in the QLineEdit. This is not a security flaw, because it is protected by the

View File

@ -178,12 +178,20 @@ class TreeWidget(QWidget):
# Create a server node for every connection dictionary. # Create a server node for every connection dictionary.
for connection_parameter in connection_parameters: for connection_parameter in connection_parameters:
# Get the parameter for loading all databases.
try:
load_all_databases = connection_parameter["Load All"]
except KeyError:
load_all_databases = True
new_node = ServerNode(name=connection_parameter["Host"], new_node = ServerNode(name=connection_parameter["Host"],
host=connection_parameter["Host"], host=connection_parameter["Host"],
user=connection_parameter["Username"], user=connection_parameter["Username"],
database=connection_parameter["Database"], database=connection_parameter["Database"],
port=connection_parameter["Port"], port=connection_parameter["Port"],
timeout=connection_parameter["Timeout"]) timeout=connection_parameter["Timeout"],
load_all_databases=load_all_databases)
# Append the node to the server list. # Append the node to the server list.
server_node_list.append(new_node) server_node_list.append(new_node)
@ -415,6 +423,13 @@ class TreeWidget(QWidget):
the server node. the server node.
""" """
# Get the parameter for loading all databases.
try:
load_all_databases = connection_parameters_for_server_node["Load All"]
except KeyError:
load_all_databases = True
# Try to create a server node. # Try to create a server node.
try: try:
# Check for a duplicate, because only one server node is necessary for one host, user and port. # Check for a duplicate, because only one server node is necessary for one host, user and port.
@ -424,7 +439,8 @@ class TreeWidget(QWidget):
user=connection_parameters_for_server_node["Username"], user=connection_parameters_for_server_node["Username"],
database=connection_parameters_for_server_node["Database"], database=connection_parameters_for_server_node["Database"],
port=connection_parameters_for_server_node["Port"], port=connection_parameters_for_server_node["Port"],
timeout=connection_parameters_for_server_node["Timeout"]) timeout=connection_parameters_for_server_node["Timeout"],
load_all_databases=load_all_databases)
else: else:
# If there is a duplicate, set the server node as return value to None, because a server node was not # If there is a duplicate, set the server node as return value to None, because a server node was not