From 4b160476327ecb893c08ce4deb29ce1180f6e0ef Mon Sep 17 00:00:00 2001 From: Elmar Ludwig Date: Mon, 6 Nov 2023 15:15:21 +0000 Subject: add implementation for /institutes/{id}/memberships route, fixes #3429 Closes #3429 Merge request studip/studip!2334 --- lib/classes/JsonApi/RouteMap.php | 1 + .../InstituteMembershipsShow.php | 2 +- .../JsonApi/Routes/Institutes/Authority.php | 9 +++ .../Institutes/InstituteMembershipsIndex.php | 80 ++++++++++++++++++++++ lib/classes/JsonApi/Schemas/Institute.php | 7 ++ tests/jsonapi/InstituteMembershipsIndexTest.php | 41 +++++++++++ 6 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 lib/classes/JsonApi/Routes/Institutes/InstituteMembershipsIndex.php create mode 100644 tests/jsonapi/InstituteMembershipsIndexTest.php diff --git a/lib/classes/JsonApi/RouteMap.php b/lib/classes/JsonApi/RouteMap.php index e779e8b..2eb33a8 100644 --- a/lib/classes/JsonApi/RouteMap.php +++ b/lib/classes/JsonApi/RouteMap.php @@ -253,6 +253,7 @@ class RouteMap $group->get('/institutes/{id}', Routes\Institutes\InstitutesShow::class); $group->get('/institutes', Routes\Institutes\InstitutesIndex::class); + $group->get('/institutes/{id}/memberships', Routes\Institutes\InstituteMembershipsIndex::class); $group->get('/institutes/{id}/status-groups', Routes\Institutes\StatusGroupsOfInstitutes::class); } diff --git a/lib/classes/JsonApi/Routes/InstituteMemberships/InstituteMembershipsShow.php b/lib/classes/JsonApi/Routes/InstituteMemberships/InstituteMembershipsShow.php index 7662af3..13e0dd4 100644 --- a/lib/classes/JsonApi/Routes/InstituteMemberships/InstituteMembershipsShow.php +++ b/lib/classes/JsonApi/Routes/InstituteMemberships/InstituteMembershipsShow.php @@ -22,7 +22,7 @@ class InstituteMembershipsShow extends JsonApiController } $user = $this->getUser($request); - if ($user->id !== $membership->user_id) { + if ($user->id !== $membership->user_id && !get_visibility_by_id($membership->user_id)) { throw new AuthorizationFailedException(); } diff --git a/lib/classes/JsonApi/Routes/Institutes/Authority.php b/lib/classes/JsonApi/Routes/Institutes/Authority.php index b3fe9b1..c6ee43b 100644 --- a/lib/classes/JsonApi/Routes/Institutes/Authority.php +++ b/lib/classes/JsonApi/Routes/Institutes/Authority.php @@ -2,6 +2,7 @@ namespace JsonApi\Routes\Institutes; +use Institute; use User; class Authority @@ -9,6 +10,14 @@ class Authority /** * @SuppressWarnings(PHPMD.Superglobals) */ + public static function canEditInstitute(User $user, Institute $institute) + { + return $GLOBALS['perm']->have_studip_perm('admin', $institute->id, $user->id); + } + + /** + * @SuppressWarnings(PHPMD.Superglobals) + */ public static function canIndexInstitutesOfUser(User $observer, User $user) { return $GLOBALS['perm']->have_perm('admin', $observer->id) diff --git a/lib/classes/JsonApi/Routes/Institutes/InstituteMembershipsIndex.php b/lib/classes/JsonApi/Routes/Institutes/InstituteMembershipsIndex.php new file mode 100644 index 0000000..9184fd9 --- /dev/null +++ b/lib/classes/JsonApi/Routes/Institutes/InstituteMembershipsIndex.php @@ -0,0 +1,80 @@ +validateFilters(); + + $user = $this->getUser($request); + $memberships = $this->getMemberships($institute, $user, $this->getFilters()); + + list($offset, $limit) = $this->getOffsetAndLimit(); + + return $this->getPaginatedContentResponse($memberships->limit($offset, $limit), count($memberships)); + } + + private function getMemberships(\Institute $institute, \User $user, array $filters) + { + $memberships = $institute->members; + + $visibleMemberships = Authority::canEditInstitute($user, $institute) + ? $memberships + : $memberships->filter(function ($membership) use ($user) { + return $membership->user_id === $user->id || get_visibility_by_id($membership->user_id); + }); + + return isset($filters['permission']) + ? $visibleMemberships->filter(function ($membership) use ($filters) { + return $membership->inst_perms === $filters['permission']; + }) + : $visibleMemberships; + } + + private function validateFilters() + { + $filtering = $this->getQueryParameters()->getFilteringParameters() ?? []; + + if (array_key_exists('permission', $filtering)) { + if (!in_array($filtering['permission'], ['user', 'autor', 'tutor', 'dozent', 'admin'])) { + throw new BadRequestException('Filter `permission` must be one of `user`, `autor`, `tutor`, `dozent`, `admin`.'); + } + } + } + + private function getFilters() + { + $filtering = $this->getQueryParameters()->getFilteringParameters() ?? []; + + $filters['permission'] = $filtering['permission'] ?? null; + + return $filters; + } +} diff --git a/lib/classes/JsonApi/Schemas/Institute.php b/lib/classes/JsonApi/Schemas/Institute.php index d3eda4a..c1775b1 100644 --- a/lib/classes/JsonApi/Schemas/Institute.php +++ b/lib/classes/JsonApi/Schemas/Institute.php @@ -12,6 +12,7 @@ class Institute extends SchemaProvider const REL_BLUBBER = 'blubber-threads'; const REL_FILES = 'file-refs'; const REL_FOLDERS = 'folders'; + const REL_MEMBERSHIPS = 'memberships'; const REL_STATUS_GROUPS = 'status-groups'; public function getId($institute): ?string @@ -60,6 +61,12 @@ class Institute extends SchemaProvider ], ]; + $relationships[self::REL_MEMBERSHIPS] = [ + self::RELATIONSHIP_LINKS => [ + Link::RELATED => $this->getRelationshipRelatedLink($resource, self::REL_MEMBERSHIPS), + ], + ]; + $relationships = $this->addStatusGroupsRelationship( $relationships, $resource, diff --git a/tests/jsonapi/InstituteMembershipsIndexTest.php b/tests/jsonapi/InstituteMembershipsIndexTest.php new file mode 100644 index 0000000..f9ddf9d --- /dev/null +++ b/tests/jsonapi/InstituteMembershipsIndexTest.php @@ -0,0 +1,41 @@ +setConnection('studip', $this->getModule('\\Helper\\StudipDb')->dbh); + } + + protected function _after() + { + } + + public function testIndexMemberships() + { + $credentials = $this->tester->getCredentialsForTestAutor(); + $instituteId = '2560f7c7674942a7dce8eeb238e15d93'; + + $institute = \Institute::find($instituteId); + + $app = $this->tester->createApp($credentials, 'get', '/institutes/{id}/memberships', InstituteMembershipsIndex::class); + + $requestBuilder = $this->tester->createRequestBuilder($credentials); + $requestBuilder->setUri('/institutes/'.$instituteId.'/memberships')->fetch(); + + $response = $this->tester->sendMockRequest($app, $requestBuilder->getRequest()); + + $this->tester->assertTrue($response->isSuccessfulDocument([200])); + $document = $response->document(); + $this->tester->assertTrue($document->isResourceCollectionDocument()); + $resources = $document->primaryResources(); + $this->tester->assertCount(count($institute->members), $resources); + } +} -- cgit v1.0