From 7f91013a96d0f954a95d7a109af6e6e76f491691 Mon Sep 17 00:00:00 2001 From: Mikko Nieminen Date: Mon, 17 Jun 2024 17:31:02 +0200 Subject: [PATCH] add RemoteProject uniqueness validation (#1433) --- CHANGELOG.rst | 1 + projectroles/models.py | 12 ++++++++++++ projectroles/tests/test_models.py | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eab3cd7b..525f35bb 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -78,6 +78,7 @@ Changed - Move project app link logic in ``AppLinkContent`` (#1380) - Move user dropdown link logic in ``AppLinkContent`` (#1381, #1413) - Do not recreate ``AppSetting`` objects on remote sync update (#1409) + - Enforce project and site uniqueness in ``RemoteProject`` model (#1433) - **Sodarcache** - Rewrite REST API views (#498, #1389) - Raise ``update_cache()`` exception for ``synccache`` in debug mode (#1375) diff --git a/projectroles/models.py b/projectroles/models.py index c27d8c14..26fbf118 100644 --- a/projectroles/models.py +++ b/projectroles/models.py @@ -63,6 +63,9 @@ ) CAT_PUBLIC_ACCESS_MSG = 'Public guest access is not allowed for categories' ADD_EMAIL_ALREADY_SET_MSG = 'Email already set as {email_type} email for user' +REMOTE_PROJECT_UNIQUE_MSG = ( + 'RemoteProject with the same project UUID and site anready exists' +) # Project ---------------------------------------------------------------------- @@ -1261,6 +1264,15 @@ class RemoteProject(models.Model): class Meta: ordering = ['site__name', 'project_uuid'] + def save(self, *args, **kwargs): + # NOTE: Can't use unique constraint with foreign key relation + rp = self.__class__.objects.filter( + project_uuid=self.project_uuid, site=self.site + ).first() + if rp and rp.id != self.id: + raise ValidationError(REMOTE_PROJECT_UNIQUE_MSG) + super().save(*args, **kwargs) + def __str__(self): return '{}: {} ({})'.format( self.site.name, str(self.project_uuid), self.site.mode diff --git a/projectroles/tests/test_models.py b/projectroles/tests/test_models.py index c072a1f2..8157bb6c 100644 --- a/projectroles/tests/test_models.py +++ b/projectroles/tests/test_models.py @@ -1505,6 +1505,16 @@ def test_get_project_no_foreign_key(self): self.remote_project.save() self.assertEqual(self.remote_project.get_project(), self.project) + def test_create_duplicate(self): + """Test creating duplicate remote project for site (should fail)""" + with self.assertRaises(ValidationError): + self.make_remote_project( + project_uuid=self.project.sodar_uuid, + site=self.site, + level=SODAR_CONSTANTS['REMOTE_LEVEL_READ_ROLES'], + project=self.project, + ) + class TestSODARUser(TestCase): """Tests for SODARUser"""