From 1d607486ea01452bd383178801bb5b0e8a1a7693 Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Tue, 4 Jun 2024 14:58:51 +0200 Subject: [PATCH 1/6] Working draft --- docker-app/qfieldcloud/core/admin.py | 1 + docker-app/qfieldcloud/core/exceptions.py | 9 ++++++++ ...6_project_restrict_project_modification.py | 20 +++++++++++++++++ docker-app/qfieldcloud/core/models.py | 8 +++++++ .../qfieldcloud/core/permissions_utils.py | 22 +++++++++++++++++++ .../qfieldcloud/core/views/files_views.py | 8 +++++++ 6 files changed, 68 insertions(+) create mode 100644 docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py diff --git a/docker-app/qfieldcloud/core/admin.py b/docker-app/qfieldcloud/core/admin.py index 74874c3e8..405cd6fd0 100644 --- a/docker-app/qfieldcloud/core/admin.py +++ b/docker-app/qfieldcloud/core/admin.py @@ -758,6 +758,7 @@ class ProjectAdmin(QFieldCloudModelAdmin): "status", "status_code", "project_filename", + "restrict_project_modification", "file_storage_bytes", "storage_keep_versions", "packaging_offliner", diff --git a/docker-app/qfieldcloud/core/exceptions.py b/docker-app/qfieldcloud/core/exceptions.py index fad060b0b..1f20b2fa4 100644 --- a/docker-app/qfieldcloud/core/exceptions.py +++ b/docker-app/qfieldcloud/core/exceptions.py @@ -133,6 +133,15 @@ class MultipleProjectsError(QFieldCloudException): status_code = status.HTTP_400_BAD_REQUEST +class RestrictedProjectModificationError(QFieldCloudException): + """Raised when the user is trying to modify the QGIS project file of a + a project that has the restrict_project_modification flag set to True""" + + code = "restricted_project_modification" + message = "Restricted project modification" + status_code = status.HTTP_400_BAD_REQUEST + + class DeltafileValidationError(QFieldCloudException): """Raised when a deltafile validation fails""" diff --git a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py new file mode 100644 index 000000000..4664e8c48 --- /dev/null +++ b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.25 on 2024-05-25 10:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0075_auto_20240323_1419"), + ] + + operations = [ + migrations.AddField( + model_name="project", + name="restrict_project_modification", + field=models.BooleanField( + default=False, + help_text="Restrict modification of the QGIS project file to administrators.", + ), + ), + ] diff --git a/docker-app/qfieldcloud/core/models.py b/docker-app/qfieldcloud/core/models.py index 28014d058..51799f62a 100644 --- a/docker-app/qfieldcloud/core/models.py +++ b/docker-app/qfieldcloud/core/models.py @@ -1016,6 +1016,14 @@ class Meta: "If enabled, QFieldCloud will automatically overwrite conflicts in this project. Disabling this will force the project manager to manually resolve all the conflicts." ), ) + + restrict_project_modification = models.BooleanField( + default=False, + help_text=_( + "Restrict modification of the QGIS project file to administrators." + ), + ) + thumbnail_uri = models.CharField( _("Thumbnail Picture URI"), max_length=255, blank=True ) diff --git a/docker-app/qfieldcloud/core/permissions_utils.py b/docker-app/qfieldcloud/core/permissions_utils.py index ce8575eda..43bcf6507 100644 --- a/docker-app/qfieldcloud/core/permissions_utils.py +++ b/docker-app/qfieldcloud/core/permissions_utils.py @@ -253,6 +253,28 @@ def can_create_files(user: QfcUser, project: Project) -> bool: ) +def can_modify_qgis_project_file(user: QfcUser, project: Project) -> bool: + if project.restrict_project_modification: + return user_has_project_roles( + user, + project, + [ + ProjectCollaborator.Roles.ADMIN, + ], + ) + else: + return user_has_project_roles( + user, + project, + [ + ProjectCollaborator.Roles.ADMIN, + ProjectCollaborator.Roles.MANAGER, + ProjectCollaborator.Roles.EDITOR, + ProjectCollaborator.Roles.REPORTER, + ], + ) + + def can_read_projects(user: QfcUser, _account: QfcUser) -> bool: return user.is_authenticated diff --git a/docker-app/qfieldcloud/core/views/files_views.py b/docker-app/qfieldcloud/core/views/files_views.py index 463f329a1..2a185a16c 100644 --- a/docker-app/qfieldcloud/core/views/files_views.py +++ b/docker-app/qfieldcloud/core/views/files_views.py @@ -261,6 +261,14 @@ def post(self, request, projectid, filename, format=None): project = Project.objects.get(id=projectid) is_qgis_project_file = utils.is_qgis_project_file(filename) + # check if the project restricts qgs/qgz file modification to admins + if is_qgis_project_file and not permissions_utils.can_modify_qgis_project_file( + request.user, project + ): + raise exceptions.RestrictedProjectModificationError( + "The project restricts modification of the QGIS project file to administrators." + ) + # check only one qgs/qgz file per project if ( is_qgis_project_file From fa0b06b5ad70e34059a1c1d3e8ccaa66ec585a44 Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Thu, 13 Jun 2024 12:04:43 +0200 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Ivan Ivanov --- docker-app/qfieldcloud/core/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-app/qfieldcloud/core/models.py b/docker-app/qfieldcloud/core/models.py index 51799f62a..666000071 100644 --- a/docker-app/qfieldcloud/core/models.py +++ b/docker-app/qfieldcloud/core/models.py @@ -1017,7 +1017,7 @@ class Meta: ), ) - restrict_project_modification = models.BooleanField( + is_project_modification_restricted = models.BooleanField( default=False, help_text=_( "Restrict modification of the QGIS project file to administrators." From 65fca730c3fdef1aae1597294dc29a6c312b899c Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Thu, 13 Jun 2024 12:08:59 +0200 Subject: [PATCH 3/6] Rename "restrict_project_modification" to "is_project_modification_restricted" --- docker-app/qfieldcloud/core/admin.py | 2 +- docker-app/qfieldcloud/core/exceptions.py | 2 +- .../migrations/0076_project_restrict_project_modification.py | 2 +- docker-app/qfieldcloud/core/permissions_utils.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docker-app/qfieldcloud/core/admin.py b/docker-app/qfieldcloud/core/admin.py index 405cd6fd0..b0a6f1b1d 100644 --- a/docker-app/qfieldcloud/core/admin.py +++ b/docker-app/qfieldcloud/core/admin.py @@ -758,7 +758,7 @@ class ProjectAdmin(QFieldCloudModelAdmin): "status", "status_code", "project_filename", - "restrict_project_modification", + "is_project_modification_restricted", "file_storage_bytes", "storage_keep_versions", "packaging_offliner", diff --git a/docker-app/qfieldcloud/core/exceptions.py b/docker-app/qfieldcloud/core/exceptions.py index 1f20b2fa4..307bf741f 100644 --- a/docker-app/qfieldcloud/core/exceptions.py +++ b/docker-app/qfieldcloud/core/exceptions.py @@ -135,7 +135,7 @@ class MultipleProjectsError(QFieldCloudException): class RestrictedProjectModificationError(QFieldCloudException): """Raised when the user is trying to modify the QGIS project file of a - a project that has the restrict_project_modification flag set to True""" + a project that has the 'is_project_modification_restricted' flag set to True""" code = "restricted_project_modification" message = "Restricted project modification" diff --git a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py index 4664e8c48..856dedea9 100644 --- a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py +++ b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name="project", - name="restrict_project_modification", + name="is_project_modification_restricted", field=models.BooleanField( default=False, help_text="Restrict modification of the QGIS project file to administrators.", diff --git a/docker-app/qfieldcloud/core/permissions_utils.py b/docker-app/qfieldcloud/core/permissions_utils.py index 43bcf6507..a1878fcde 100644 --- a/docker-app/qfieldcloud/core/permissions_utils.py +++ b/docker-app/qfieldcloud/core/permissions_utils.py @@ -254,7 +254,7 @@ def can_create_files(user: QfcUser, project: Project) -> bool: def can_modify_qgis_project_file(user: QfcUser, project: Project) -> bool: - if project.restrict_project_modification: + if project.is_project_modification_restricted: return user_has_project_roles( user, project, From c12e9699924aa2befb7d4e5226cc4711fbfc362f Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Mon, 17 Jun 2024 15:55:14 +0200 Subject: [PATCH 4/6] Final wording --- docker-app/qfieldcloud/core/admin.py | 2 +- docker-app/qfieldcloud/core/exceptions.py | 4 ++-- .../migrations/0076_project_restrict_project_modification.py | 4 ++-- docker-app/qfieldcloud/core/models.py | 4 ++-- docker-app/qfieldcloud/core/permissions_utils.py | 3 ++- docker-app/qfieldcloud/core/views/files_views.py | 2 +- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docker-app/qfieldcloud/core/admin.py b/docker-app/qfieldcloud/core/admin.py index b0a6f1b1d..ea2917386 100644 --- a/docker-app/qfieldcloud/core/admin.py +++ b/docker-app/qfieldcloud/core/admin.py @@ -758,7 +758,7 @@ class ProjectAdmin(QFieldCloudModelAdmin): "status", "status_code", "project_filename", - "is_project_modification_restricted", + "is_projectfile_restricted", "file_storage_bytes", "storage_keep_versions", "packaging_offliner", diff --git a/docker-app/qfieldcloud/core/exceptions.py b/docker-app/qfieldcloud/core/exceptions.py index 307bf741f..66568f8e6 100644 --- a/docker-app/qfieldcloud/core/exceptions.py +++ b/docker-app/qfieldcloud/core/exceptions.py @@ -134,8 +134,8 @@ class MultipleProjectsError(QFieldCloudException): class RestrictedProjectModificationError(QFieldCloudException): - """Raised when the user is trying to modify the QGIS project file of a - a project that has the 'is_project_modification_restricted' flag set to True""" + """Raised when a user with insufficient role is trying to modify the QGIS project file + of a project that has the 'is_projectfile_restricted' flag set""" code = "restricted_project_modification" message = "Restricted project modification" diff --git a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py index 856dedea9..43462c5d2 100644 --- a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py +++ b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py @@ -11,10 +11,10 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name="project", - name="is_project_modification_restricted", + name="is_projectfile_restricted", field=models.BooleanField( default=False, - help_text="Restrict modification of the QGIS project file to administrators.", + help_text="Restrict modification of the QGIS project file to managers and administrators.", ), ), ] diff --git a/docker-app/qfieldcloud/core/models.py b/docker-app/qfieldcloud/core/models.py index 666000071..b91ebd649 100644 --- a/docker-app/qfieldcloud/core/models.py +++ b/docker-app/qfieldcloud/core/models.py @@ -1017,10 +1017,10 @@ class Meta: ), ) - is_project_modification_restricted = models.BooleanField( + is_projectfile_restricted = models.BooleanField( default=False, help_text=_( - "Restrict modification of the QGIS project file to administrators." + "Restrict modification of the QGIS project file to managers and administrators." ), ) diff --git a/docker-app/qfieldcloud/core/permissions_utils.py b/docker-app/qfieldcloud/core/permissions_utils.py index a1878fcde..d65778e62 100644 --- a/docker-app/qfieldcloud/core/permissions_utils.py +++ b/docker-app/qfieldcloud/core/permissions_utils.py @@ -254,12 +254,13 @@ def can_create_files(user: QfcUser, project: Project) -> bool: def can_modify_qgis_project_file(user: QfcUser, project: Project) -> bool: - if project.is_project_modification_restricted: + if project.is_projectfile_restricted: return user_has_project_roles( user, project, [ ProjectCollaborator.Roles.ADMIN, + ProjectCollaborator.Roles.MANAGER, ], ) else: diff --git a/docker-app/qfieldcloud/core/views/files_views.py b/docker-app/qfieldcloud/core/views/files_views.py index 2a185a16c..8a7266dbc 100644 --- a/docker-app/qfieldcloud/core/views/files_views.py +++ b/docker-app/qfieldcloud/core/views/files_views.py @@ -266,7 +266,7 @@ def post(self, request, projectid, filename, format=None): request.user, project ): raise exceptions.RestrictedProjectModificationError( - "The project restricts modification of the QGIS project file to administrators." + "The project restricts modification of the QGIS project file to managers and administrators." ) # check only one qgs/qgz file per project From 02a02787820ca0dd38c6012f07933d7deaf741ca Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Tue, 18 Jun 2024 16:41:43 +0200 Subject: [PATCH 5/6] Rename to is_projectfile_restricted, because it will affect all project files in the long run --- docker-app/qfieldcloud/core/admin.py | 2 +- docker-app/qfieldcloud/core/exceptions.py | 4 ++-- .../migrations/0076_project_restrict_project_modification.py | 4 ++-- docker-app/qfieldcloud/core/models.py | 4 ++-- docker-app/qfieldcloud/core/permissions_utils.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docker-app/qfieldcloud/core/admin.py b/docker-app/qfieldcloud/core/admin.py index ea2917386..2bfabcb9e 100644 --- a/docker-app/qfieldcloud/core/admin.py +++ b/docker-app/qfieldcloud/core/admin.py @@ -758,7 +758,7 @@ class ProjectAdmin(QFieldCloudModelAdmin): "status", "status_code", "project_filename", - "is_projectfile_restricted", + "is_projectfiles_restricted", "file_storage_bytes", "storage_keep_versions", "packaging_offliner", diff --git a/docker-app/qfieldcloud/core/exceptions.py b/docker-app/qfieldcloud/core/exceptions.py index 66568f8e6..192bb7212 100644 --- a/docker-app/qfieldcloud/core/exceptions.py +++ b/docker-app/qfieldcloud/core/exceptions.py @@ -134,8 +134,8 @@ class MultipleProjectsError(QFieldCloudException): class RestrictedProjectModificationError(QFieldCloudException): - """Raised when a user with insufficient role is trying to modify the QGIS project file - of a project that has the 'is_projectfile_restricted' flag set""" + """Raised when a user with insufficient role is trying to modify QGIS project files + of a project that has the 'is_projectfiles_restricted' flag set""" code = "restricted_project_modification" message = "Restricted project modification" diff --git a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py index 43462c5d2..b90b07519 100644 --- a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py +++ b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py @@ -11,10 +11,10 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name="project", - name="is_projectfile_restricted", + name="is_projectfiles_restricted", field=models.BooleanField( default=False, - help_text="Restrict modification of the QGIS project file to managers and administrators.", + help_text="Restrict modifications of QGIS project files to managers and administrators.", ), ), ] diff --git a/docker-app/qfieldcloud/core/models.py b/docker-app/qfieldcloud/core/models.py index b91ebd649..34bcae139 100644 --- a/docker-app/qfieldcloud/core/models.py +++ b/docker-app/qfieldcloud/core/models.py @@ -1017,10 +1017,10 @@ class Meta: ), ) - is_projectfile_restricted = models.BooleanField( + is_projectfiles_restricted = models.BooleanField( default=False, help_text=_( - "Restrict modification of the QGIS project file to managers and administrators." + "Restrict modifications of QGIS project files to managers and administrators." ), ) diff --git a/docker-app/qfieldcloud/core/permissions_utils.py b/docker-app/qfieldcloud/core/permissions_utils.py index d65778e62..ad38cb207 100644 --- a/docker-app/qfieldcloud/core/permissions_utils.py +++ b/docker-app/qfieldcloud/core/permissions_utils.py @@ -254,7 +254,7 @@ def can_create_files(user: QfcUser, project: Project) -> bool: def can_modify_qgis_project_file(user: QfcUser, project: Project) -> bool: - if project.is_projectfile_restricted: + if project.is_projectfiles_restricted: return user_has_project_roles( user, project, From 0ea0f749e3dbb6c4092b68b94de380befdb289ba Mon Sep 17 00:00:00 2001 From: Michael Schmuki Date: Thu, 20 Jun 2024 21:10:46 +0200 Subject: [PATCH 6/6] Rename flag to has_restricted_projectfiles --- docker-app/qfieldcloud/core/admin.py | 2 +- docker-app/qfieldcloud/core/exceptions.py | 4 ++-- .../migrations/0076_project_restrict_project_modification.py | 4 ++-- docker-app/qfieldcloud/core/models.py | 4 ++-- docker-app/qfieldcloud/core/permissions_utils.py | 4 ++-- docker-app/qfieldcloud/core/views/files_views.py | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docker-app/qfieldcloud/core/admin.py b/docker-app/qfieldcloud/core/admin.py index 2bfabcb9e..458f94c61 100644 --- a/docker-app/qfieldcloud/core/admin.py +++ b/docker-app/qfieldcloud/core/admin.py @@ -758,7 +758,7 @@ class ProjectAdmin(QFieldCloudModelAdmin): "status", "status_code", "project_filename", - "is_projectfiles_restricted", + "has_restricted_projectfiles", "file_storage_bytes", "storage_keep_versions", "packaging_offliner", diff --git a/docker-app/qfieldcloud/core/exceptions.py b/docker-app/qfieldcloud/core/exceptions.py index 192bb7212..92ee05a32 100644 --- a/docker-app/qfieldcloud/core/exceptions.py +++ b/docker-app/qfieldcloud/core/exceptions.py @@ -134,8 +134,8 @@ class MultipleProjectsError(QFieldCloudException): class RestrictedProjectModificationError(QFieldCloudException): - """Raised when a user with insufficient role is trying to modify QGIS project files - of a project that has the 'is_projectfiles_restricted' flag set""" + """Raised when a user with insufficient role is trying to modify QGIS/QField projectfiles + of a project that has the 'has_restricted_projectfiles' flag set""" code = "restricted_project_modification" message = "Restricted project modification" diff --git a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py index b90b07519..9c8f84280 100644 --- a/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py +++ b/docker-app/qfieldcloud/core/migrations/0076_project_restrict_project_modification.py @@ -11,10 +11,10 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name="project", - name="is_projectfiles_restricted", + name="has_restricted_projectfiles", field=models.BooleanField( default=False, - help_text="Restrict modifications of QGIS project files to managers and administrators.", + help_text="Restrict modifications of QGIS/QField projectfiles to managers and administrators.", ), ), ] diff --git a/docker-app/qfieldcloud/core/models.py b/docker-app/qfieldcloud/core/models.py index 34bcae139..50b0c0a6f 100644 --- a/docker-app/qfieldcloud/core/models.py +++ b/docker-app/qfieldcloud/core/models.py @@ -1017,10 +1017,10 @@ class Meta: ), ) - is_projectfiles_restricted = models.BooleanField( + has_restricted_projectfiles = models.BooleanField( default=False, help_text=_( - "Restrict modifications of QGIS project files to managers and administrators." + "Restrict modifications of QGIS/QField projectfiles to managers and administrators." ), ) diff --git a/docker-app/qfieldcloud/core/permissions_utils.py b/docker-app/qfieldcloud/core/permissions_utils.py index ad38cb207..2af48c76c 100644 --- a/docker-app/qfieldcloud/core/permissions_utils.py +++ b/docker-app/qfieldcloud/core/permissions_utils.py @@ -253,8 +253,8 @@ def can_create_files(user: QfcUser, project: Project) -> bool: ) -def can_modify_qgis_project_file(user: QfcUser, project: Project) -> bool: - if project.is_projectfiles_restricted: +def can_modify_qgis_projectfile(user: QfcUser, project: Project) -> bool: + if project.has_restricted_projectfiles: return user_has_project_roles( user, project, diff --git a/docker-app/qfieldcloud/core/views/files_views.py b/docker-app/qfieldcloud/core/views/files_views.py index 8a7266dbc..1b44449d6 100644 --- a/docker-app/qfieldcloud/core/views/files_views.py +++ b/docker-app/qfieldcloud/core/views/files_views.py @@ -262,7 +262,7 @@ def post(self, request, projectid, filename, format=None): is_qgis_project_file = utils.is_qgis_project_file(filename) # check if the project restricts qgs/qgz file modification to admins - if is_qgis_project_file and not permissions_utils.can_modify_qgis_project_file( + if is_qgis_project_file and not permissions_utils.can_modify_qgis_projectfile( request.user, project ): raise exceptions.RestrictedProjectModificationError(