From ae0c884e443806fb9546c6b8adf8d1ffe18cb39b Mon Sep 17 00:00:00 2001 From: Craig Williams Date: Mon, 7 Feb 2022 12:04:10 +0000 Subject: [PATCH] Split organisation member management out of the organisation controller into a sub-controller --- routes/organisation-members.php | 17 +++ routes/organisations.php | 3 - src/Controller/OrganisationController.php | 54 +------- .../OrganisationMembersController.php | 130 ++++++++++++++++++ 4 files changed, 148 insertions(+), 56 deletions(-) create mode 100644 routes/organisation-members.php create mode 100644 src/Controller/OrganisationMembersController.php diff --git a/routes/organisation-members.php b/routes/organisation-members.php new file mode 100644 index 0000000..b8b4a24 --- /dev/null +++ b/routes/organisation-members.php @@ -0,0 +1,17 @@ +group('/api/organisations/o/{slug}/members', function () { + $this->get('', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationMembersController:getList'); +})->add('authGuard')->add(new NoCache()); \ No newline at end of file diff --git a/routes/organisations.php b/routes/organisations.php index ffbef11..16ebdef 100644 --- a/routes/organisations.php +++ b/routes/organisations.php @@ -31,9 +31,6 @@ $app->group('/api/organisations', function () { $this->put('/o/{slug}', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationController:update'); $this->delete('/o/{slug}', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationController:delete'); - - - $this->get('/o/{slug}/members', 'UserFrosting\Sprinkle\Organisations\Controller\OrganisationController:getMembers'); })->add('authGuard')->add(new NoCache()); $app->group('/modals/organisations', function () { diff --git a/src/Controller/OrganisationController.php b/src/Controller/OrganisationController.php index a8a45ad..f4b6eee 100644 --- a/src/Controller/OrganisationController.php +++ b/src/Controller/OrganisationController.php @@ -589,59 +589,7 @@ class OrganisationController extends SimpleController ], ]); } - - /** - * Members List API. - * - * @param Request $request - * @param Response $response - * @param array $args - * - * @throws NotFoundException If organisation is not found - * @throws ForbiddenException If user is not authorized to access page - */ - public function getMembers(Request $request, Response $response, $args) - { - $organisation = $this->getOrganisationFromParams($args); - - // If the organisation no longer exists, forward to main organisation listing page - if (!$organisation) { - throw new NotFoundException(); - } - - // GET parameters - $params = $request->getQueryParams(); - - /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ - $authorizer = $this->ci->authorizer; - - /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ - $currentUser = $this->ci->currentUser; - - // Access-controlled page - if (!$authorizer->checkAccess($currentUser, 'view_organisation_field', [ - 'organisation' => $organisation, - 'property' => 'members', - ])) { - throw new ForbiddenException(); - } - - /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ - $classMapper = $this->ci->classMapper; - - $sprunje = $classMapper->createInstance('user_sprunje', $classMapper, $params); - $sprunje->extendQuery(function ($query) use ($classMapper, $organisation) { - return $query - ->join('organisation_members', function($join) use($organisation) { - $join->on('organisation_members.user_id', '=', 'users.id')->where('organisation_id', $organisation->id); - }); - }); - - // Be careful how you consume this data - it has not been escaped and contains untrusted user-supplied content. - // For example, if you plan to insert it into an HTML DOM, you must escape it on the client side (or use client-side templating). - return $sprunje->toResponse($response); - } - + /** * Renders a page displaying a organisation's information, in read-only mode. diff --git a/src/Controller/OrganisationMembersController.php b/src/Controller/OrganisationMembersController.php new file mode 100644 index 0000000..683fff1 --- /dev/null +++ b/src/Controller/OrganisationMembersController.php @@ -0,0 +1,130 @@ +getOrganisationFromParams($args); + + // If the organisation no longer exists, forward to main organisation listing page + if (!$organisation) { + throw new NotFoundException(); + } + + // GET parameters + $params = $request->getQueryParams(); + + /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ + $authorizer = $this->ci->authorizer; + + /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ + $currentUser = $this->ci->currentUser; + + // Access-controlled page + if (!$authorizer->checkAccess($currentUser, 'view_organisation_field', [ + 'organisation' => $organisation, + 'property' => 'members', + ])) { + throw new ForbiddenException(); + } + + /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = $this->ci->classMapper; + + $sprunje = $classMapper->createInstance('user_sprunje', $classMapper, $params); + $sprunje->extendQuery(function ($query) use ($classMapper, $organisation) { + return $query + ->join('organisation_members', function($join) use($organisation) { + $join->on('organisation_members.user_id', '=', 'users.id')->where('organisation_id', $organisation->id); + }); + }); + + // Be careful how you consume this data - it has not been escaped and contains untrusted user-supplied content. + // For example, if you plan to insert it into an HTML DOM, you must escape it on the client side (or use client-side templating). + return $sprunje->toResponse($response); + } + + + /** + * Get organisation from params. + * + * @param array $params + * + * @throws BadRequestException + * + * @return Organisation + */ + protected function getOrganisationFromParams($params) + { + // Load the request schema + $schema = new RequestSchema('schema://requests/organisation/get-by-slug.yaml'); + + // Whitelist and set parameter defaults + $transformer = new RequestDataTransformer($schema); + $data = $transformer->transform($params); + + // Validate, and throw exception on validation errors. + $validator = new ServerSideValidator($schema, $this->ci->translator); + if (!$validator->validate($data)) { + // TODO: encapsulate the communication of error messages from ServerSideValidator to the BadRequestException + $e = new BadRequestException(); + foreach ($validator->errors() as $idx => $field) { + foreach ($field as $eidx => $error) { + $e->addUserMessage($error); + } + } + + throw $e; + } + + /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ + $classMapper = $this->ci->classMapper; + + // Get the organisation + $organisation = $classMapper->getClassMapping('organisation')::where('slug', $data['slug']) + ->first(); + + return $organisation; + } +}