From cc7a1dfbfe7178ec0ad56f892254e0144a07ca62 Mon Sep 17 00:00:00 2001 From: Oliver Stolpe Date: Thu, 5 Dec 2024 16:51:25 +0100 Subject: [PATCH] feat: indicate when hpcuser has been removed from group (#351) --- adminsec/tests/test_views_api.py | 59 +++++++- usersec/serializers.py | 11 +- .../tests/snapshots/snap_test_serializers.py | 130 ++++++++++++++++++ usersec/tests/test_serializers.py | 68 +++++++++ 4 files changed, 265 insertions(+), 3 deletions(-) diff --git a/adminsec/tests/test_views_api.py b/adminsec/tests/test_views_api.py index a888019..8e5ecba 100644 --- a/adminsec/tests/test_views_api.py +++ b/adminsec/tests/test_views_api.py @@ -8,6 +8,7 @@ from test_plus import TestCase from usersec.models import REQUEST_STATUS_ACTIVE +from usersec.serializers import HPC_ALUMNI_GROUP from usersec.tests.factories import ( HpcGroupCreateRequestFactory, HpcGroupFactory, @@ -634,8 +635,6 @@ class TestHpcAccessStatusApiView(ApiTestCase): def test_get_succeed(self): """Test the GET method (staff users can do).""" - self.maxDiff = None - expected = { "hpc_users": [ { @@ -689,6 +688,62 @@ def test_get_succeed(self): self.response_200() self.assertEqual(self.last_response.json(), expected) + def test_get_succeed_alumni(self): + self.hpcuser_user.primary_group = None + self.hpcuser_user.save() + expected = { + "hpc_users": [ + { + "uid": self.hpcuser_user.user.uid, + "email": self.hpcuser_user.user.email, + "full_name": "User Name", + "first_name": self.hpcuser_user.user.first_name, + "last_name": self.hpcuser_user.user.last_name, + "phone_number": None, + "primary_group": HPC_ALUMNI_GROUP, + "resources_requested": self.hpcuser_user.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_user.description, + "username": self.hpcuser_user.username, + "expiration": self.hpcuser_user.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "home_directory": self.hpcuser_user.home_directory, + "login_shell": self.hpcuser_user.login_shell, + } + ], + "hpc_groups": [ + { + "owner": None, + "delegate": None, + "resources_requested": self.hpcuser_group.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_group.description, + "name": self.hpcuser_group.name, + "folders": self.hpcuser_group.folders, + "expiration": self.hpcuser_group.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "gid": self.hpcuser_group.gid, + } + ], + "hpc_projects": [ + { + "gid": self.hpcuser_project.gid, + "group": self.hpcuser_group.name, + "delegate": None, + "resources_requested": self.hpcuser_project.resources_requested, + "status": "INITIAL", + "description": self.hpcuser_project.description, + "name": self.hpcuser_project.name, + "folders": self.hpcuser_project.folders, + "expiration": self.hpcuser_project.expiration.strftime("%Y-%m-%dT%H:%M:%SZ"), + "members": [], + } + ], + } + for user in [self.user_staff, self.user_admin, self.user_hpcadmin]: + with self.login(user): + self.get("adminsec:api-hpcaccess-status") + self.response_200() + self.assertEqual(self.last_response.json(), expected) + def test_get_fail(self): """Test the GET method (non-staff cannot do).""" for user in [self.user_user]: diff --git a/usersec/serializers.py b/usersec/serializers.py index 1115cf6..a5909fa 100644 --- a/usersec/serializers.py +++ b/usersec/serializers.py @@ -14,6 +14,8 @@ HpcUserVersion, ) +HPC_ALUMNI_GROUP = "hpc-alumnis" + class HpcObjectAbstractSerializer(serializers.Serializer): """Common base class for HPC object serializers.""" @@ -46,6 +48,7 @@ class HpcUserAbstractSerializer(HpcObjectAbstractSerializer): phone_number = serializers.SerializerMethodField() home_directory = serializers.CharField() login_shell = serializers.CharField() + removed = serializers.BooleanField(read_only=True) def get_email(self, obj) -> Optional[str]: return obj.user.email @@ -82,6 +85,7 @@ class Meta: "expiration", "home_directory", "login_shell", + "removed", ] @@ -100,7 +104,12 @@ class Meta: class HpcUserStatusSerializer(HpcUserAbstractSerializer, serializers.ModelSerializer): """Serializer for HpcUser model.""" - primary_group = serializers.SlugRelatedField(slug_field="name", read_only=True) + primary_group = serializers.SerializerMethodField() + + def get_primary_group(self, obj): + if obj.primary_group is None: + return HPC_ALUMNI_GROUP + return obj.primary_group.name class Meta: model = HpcUser diff --git a/usersec/tests/snapshots/snap_test_serializers.py b/usersec/tests/snapshots/snap_test_serializers.py index a1f1ef6..e94a117 100644 --- a/usersec/tests/snapshots/snap_test_serializers.py +++ b/usersec/tests/snapshots/snap_test_serializers.py @@ -6,6 +6,74 @@ snapshots = Snapshot() +snapshots["TestHcpaccessStatus::testSerializeExisting 1"] = { + "hpc_groups": [ + { + "delegate": None, + "description": "this is a group", + "expiration": "2050-01-01T00:00:00Z", + "folders": { + "tier1_scratch": "/data/scratch/group", + "tier1_work": "/data/work/group", + "tier2_mirrored": "/data/mirrored/group", + "tier2_unmirrored": "/data/unmirrored/group", + }, + "gid": 2000, + "name": "group0", + "owner": None, + "resources_requested": { + "tier1_scratch": 1, + "tier1_work": 1, + "tier2_mirrored": 0, + "tier2_unmirrored": 0, + }, + "status": "INITIAL", + } + ], + "hpc_projects": [ + { + "delegate": None, + "description": "this is a project", + "expiration": "2050-01-01T00:00:00Z", + "folders": { + "tier1_scratch": "/data/scratch/project", + "tier1_work": "/data/work/project", + "tier2_mirrored": "/data/mirrored/project", + "tier2_unmirrored": "/data/unmirrored/project", + }, + "gid": 5000, + "group": "group0", + "members": [], + "name": "hpc-project0", + "resources_requested": { + "tier1_scratch": 1, + "tier1_work": 1, + "tier2_mirrored": 0, + "tier2_unmirrored": 0, + }, + "status": "INITIAL", + } + ], + "hpc_users": [ + { + "description": "this is a user", + "email": "bscott@example.net", + "expiration": "2050-01-01T00:00:00Z", + "first_name": "", + "full_name": "Kevin Wolfe", + "home_directory": "/data/cephfs-1/home/users/user0_c", + "last_name": "", + "login_shell": "/usr/bin/bash", + "phone_number": "961.928.4407x744", + "primary_group": "group0", + "resources_requested": {"tier1_home": 1.0}, + "status": "INITIAL", + "uid": 9092, + "username": "user0_c", + } + ], +} + snapshots["TestHpcGroupCreateRequestSerializer::testSerializeExisting 1"] = { "current_version": 1, "date_created": "2019-01-01T00:00:00Z", @@ -48,6 +116,28 @@ "uuid": "uuid_placeholder", } +snapshots["TestHpcGroupStatusSerializer::testSerializeExisting 1"] = { + "delegate": None, + "description": "this is a group", + "expiration": "2050-01-01T00:00:00Z", + "folders": { + "tier1_scratch": "/data/scratch/group", + "tier1_work": "/data/work/group", + "tier2_mirrored": "/data/mirrored/group", + "tier2_unmirrored": "/data/unmirrored/group", + }, + "gid": 2000, + "name": "group0", + "owner": None, + "resources_requested": { + "tier1_scratch": 1, + "tier1_work": 1, + "tier2_mirrored": 0, + "tier2_unmirrored": 0, + }, + "status": "INITIAL", +} + snapshots["TestHpcProjectCreateRequestSerializer::testSerializeExisting 1"] = { "current_version": 1, "date_created": "2019-01-01T00:00:00Z", @@ -94,6 +184,29 @@ "uuid": "uuid_placeholder", } +snapshots["TestHpcProjectStatusSerializer::testSerializeExisting 1"] = { + "delegate": None, + "description": "this is a project", + "expiration": "2050-01-01T00:00:00Z", + "folders": { + "tier1_scratch": "/data/scratch/project", + "tier1_work": "/data/work/project", + "tier2_mirrored": "/data/mirrored/project", + "tier2_unmirrored": "/data/unmirrored/project", + }, + "gid": 5000, + "group": "group_name_placeholder", + "members": [], + "name": "hpc-project0", + "resources_requested": { + "tier1_scratch": 1, + "tier1_work": 1, + "tier2_mirrored": 0, + "tier2_unmirrored": 0, + }, + "status": "INITIAL", +} + snapshots["TestHpcUserSerializer::testSerializeExisting 1"] = { "current_version": 1, "date_created": "2019-01-01T00:00:00Z", @@ -114,3 +227,20 @@ "username": "user0_c", "uuid": "uuid_placeholder", } + +snapshots["TestHpcUserStatusSerializer::testSerializeExisting 1"] = { + "description": "this is a user", + "email": "email_placeholder", + "expiration": "2050-01-01T00:00:00Z", + "first_name": "first_name_placeholder", + "full_name": "name_placeholder", + "home_directory": "/data/cephfs-1/home/users/user0_c", + "last_name": "last_name_placeholder", + "login_shell": "/usr/bin/bash", + "phone_number": "phone_number_placeholder", + "primary_group": "primary_group_name_placeholder", + "resources_requested": {"tier1_home": 1.0}, + "status": "INITIAL", + "uid": 2000, + "username": "user0_c", +} diff --git a/usersec/tests/test_serializers.py b/usersec/tests/test_serializers.py index 9ab6f21..5af0f32 100644 --- a/usersec/tests/test_serializers.py +++ b/usersec/tests/test_serializers.py @@ -2,13 +2,18 @@ from snapshottest.django import TestCase as TestCaseSnap from test_plus import TestCase as TestCasePlus +from adminsec.views_api import HpcAccessStatus from hpcaccess.utils.tests import FROZEN_TIME from usersec.serializers import ( + HpcAccessStatusSerializer, HpcGroupCreateRequestSerializer, HpcGroupSerializer, + HpcGroupStatusSerializer, HpcProjectCreateRequestSerializer, HpcProjectSerializer, + HpcProjectStatusSerializer, HpcUserSerializer, + HpcUserStatusSerializer, ) from usersec.tests.factories import ( HpcGroupCreateRequestFactory, @@ -104,3 +109,66 @@ def testSerializeExisting(self): result["group"] = "group_uuid_placeholder" result["name_requested"] = "name_requested_placeholder" self.assertMatchSnapshot(result) + + +@freeze_time(FROZEN_TIME) +class TestHpcUserStatusSerializer(ResetSequenceMixin, TestCaseSnap, TestCasePlus): + def setUp(self): + super().setUp() + self.hpc_user = HpcUserFactory() + + def testSerializeExisting(self): + serializer = HpcUserStatusSerializer(self.hpc_user) + result = dict(serializer.data) + result["email"] = "email_placeholder" + result["primary_group"] = "primary_group_name_placeholder" + result["phone_number"] = "phone_number_placeholder" + result["full_name"] = "name_placeholder" + result["first_name"] = "first_name_placeholder" + result["last_name"] = "last_name_placeholder" + result["uid"] = 2000 + self.assertMatchSnapshot(result) + + +@freeze_time(FROZEN_TIME) +class TestHpcGroupStatusSerializer(ResetSequenceMixin, TestCaseSnap, TestCasePlus): + def setUp(self): + super().setUp() + self.hpc_group = HpcGroupFactory() + + def testSerializeExisting(self): + serializer = HpcGroupStatusSerializer(self.hpc_group) + result = dict(serializer.data) + self.assertMatchSnapshot(result) + + +@freeze_time(FROZEN_TIME) +class TestHpcProjectStatusSerializer(ResetSequenceMixin, TestCaseSnap, TestCasePlus): + def setUp(self): + super().setUp() + self.hpc_project = HpcProjectFactory() + + def testSerializeExisting(self): + serializer = HpcProjectStatusSerializer(self.hpc_project) + result = dict(serializer.data) + result["group"] = "group_name_placeholder" + self.assertMatchSnapshot(result) + + +@freeze_time(FROZEN_TIME) +class TestHcpaccessStatus(ResetSequenceMixin, TestCaseSnap, TestCasePlus): + def setUp(self): + super().setUp() + hpc_group = HpcGroupFactory() + hpc_project = HpcProjectFactory(group=hpc_group) + hpc_user = HpcUserFactory(primary_group=hpc_group) + self.hpc_access_status = HpcAccessStatus( + hpc_users=[hpc_user], + hpc_groups=[hpc_group], + hpc_projects=[hpc_project], + ) + + def testSerializeExisting(self): + serializer = HpcAccessStatusSerializer(self.hpc_access_status) + result = dict(serializer.data) + self.assertMatchSnapshot(result)