diff --git a/Mergin/plugin.py b/Mergin/plugin.py index 3b473f84..28100079 100644 --- a/Mergin/plugin.py +++ b/Mergin/plugin.py @@ -43,6 +43,7 @@ icon_path, mm_symbol_path, mergin_project_local_path, + refresh_project_role, remove_project_variables, set_qgis_project_mergin_variables, unsaved_project_check, @@ -247,6 +248,9 @@ def create_manager(self): if self.mc is not None: self.choose_active_workspace() self.manager = MerginProjectsManager(self) + if self.mergin_proj_dir is not None: + refresh_project_role(self.mc, self.mergin_proj_dir) + set_qgis_project_mergin_variables(self.mergin_proj_dir) else: error = "Configure the Mergin Maps plugin \nto access your projects" except (URLError, ClientError, LoginError): @@ -539,6 +543,8 @@ def on_qgis_project_changed(self): self.mergin_proj_dir = mergin_project_local_path() if self.mergin_proj_dir is not None: self.enable_toolbar_actions() + if self.mc is not None: + refresh_project_role(self.mc, self.mergin_proj_dir) set_qgis_project_mergin_variables(self.mergin_proj_dir) # re-render Browser items so the opened-project indicator follows the active QGIS project. if self.has_browser_item(): diff --git a/Mergin/projects_manager.py b/Mergin/projects_manager.py index c4243592..8f4e4b34 100644 --- a/Mergin/projects_manager.py +++ b/Mergin/projects_manager.py @@ -28,8 +28,10 @@ LoginError, find_qgis_files, login_error_message, + mergin_project_local_path, same_dir, send_logs, + set_qgis_project_mergin_variables, storage_limit_fail, unhandled_exception_message, unsaved_project_check, @@ -220,7 +222,7 @@ def create_project(self, project_name, project_dir, is_public, namespace): project_dir == QgsProject.instance().absolutePath() or project_dir + "/" in QgsProject.instance().absolutePath() ): - write_project_variables(project_name, full_project_name, "v1") + write_project_variables(project_name, full_project_name, "v1", mp.project_role()) QMessageBox.information( None, @@ -231,6 +233,11 @@ def create_project(self, project_name, project_dir, is_public, namespace): return True + def refresh_project_variables(self, project_dir): + """Re-read the Mergin Maps variables from the project metadata, if that project is the open one.""" + if same_dir(project_dir, mergin_project_local_path()): + set_qgis_project_mergin_variables(project_dir) + def project_status(self, project_dir): if project_dir is None: return @@ -254,6 +261,7 @@ def project_status(self, project_dir): if qgis_proj_filename in find_qgis_files(project_dir): AuthSync().export_auth(self.mc) pull_changes, push_changes, push_changes_summary = self.mc.project_status(project_dir) + self.refresh_project_variables(project_dir) dlg = ProjectStatusDialog( pull_changes, push_changes, @@ -399,6 +407,9 @@ def sync_project(self, project_dir, project_name=None): QMessageBox.critical(None, "Project syncing", msg, QMessageBox.StandardButton.Close) return + # a role change creates no project version, so it only arrives with the status we just fetched + self.refresh_project_variables(project_dir) + if not sum(len(v) for v in list(pull_changes.values()) + list(push_changes.values())): QMessageBox.information( None, @@ -510,6 +521,7 @@ def sync_project(self, project_dir, project_name=None): _, has_push_changes = get_push_changes_batch(self.mc, project_dir) error_retries_attempts = 0 if not has_push_changes: + self.refresh_project_variables(project_dir) # TODO: report success only when we have actually done anything msg = "Mergin Maps project {} synchronised successfully".format(project_name) QMessageBox.information(None, "Project sync", msg, QMessageBox.StandardButton.Close) diff --git a/Mergin/utils.py b/Mergin/utils.py index a5ee8123..5f4e3c74 100644 --- a/Mergin/utils.py +++ b/Mergin/utils.py @@ -943,13 +943,15 @@ def unhandled_exception_message(error_details, dialog_title, error_text, mm_clie box.exec() -def write_project_variables(project_name, project_full_name, version): +def write_project_variables(project_name, project_full_name, version, role=""): QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mergin_project_name", project_name) QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mergin_project_full_name", project_full_name) QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mergin_project_version", int_version(version)) QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mm_project_name", project_name) QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mm_project_full_name", project_full_name) QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mm_project_version", int_version(version)) + # projects downloaded with an older client have no role in their metadata + QgsExpressionContextUtils.setProjectVariable(QgsProject.instance(), "mm_project_role", role or "") def remove_project_variables(): @@ -959,6 +961,7 @@ def remove_project_variables(): QgsExpressionContextUtils.removeProjectVariable(QgsProject.instance(), "mm_project_name") QgsExpressionContextUtils.removeProjectVariable(QgsProject.instance(), "mm_project_full_name") QgsExpressionContextUtils.removeProjectVariable(QgsProject.instance(), "mm_project_version") + QgsExpressionContextUtils.removeProjectVariable(QgsProject.instance(), "mm_project_role") def pretty_summary(summary): @@ -1016,13 +1019,28 @@ def get_local_mergin_projects_info(workspace=None): return local_projects_info +def refresh_project_role(mc, project_dir): + """Ask the server for the user's current role on the project and store it in the project metadata.""" + try: + mp = MerginProject(project_dir) + try: + role = mc.project_info_v2(mp.project_id()).role + except (NotImplementedError, ClientError): + # servers below 2025.8.2 have no v2 project info, and old projects have no id in their metadata + role = mc.project_info(mp.project_full_name())["role"] + mp.update_project_role(role) + except (InvalidProject, ClientError, URLError): + # keep whatever the metadata holds, the variable has to stay usable offline + pass + + def set_qgis_project_mergin_variables(project_dir): """Check if QGIS project project_dir is a local Mergin Maps project and set QGIS project variables for Mergin Maps.""" try: mp = MerginProject(project_dir) - write_project_variables(mp.project_name(), mp.project_full_name(), mp.version()) + write_project_variables(mp.project_name(), mp.project_full_name(), mp.version(), mp.project_role()) except InvalidProject: remove_project_variables()