ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'create_organisation')) { throw new ForbiddenException(); } // Get POST parameters: name, slug, icon, description $params = $request->getParsedBody(); // Load the request schema $schema = new RequestSchema('schema://requests/organisation/create.yaml'); // Whitelist and set parameter defaults $transformer = new RequestDataTransformer($schema); $data = $transformer->transform($params); $error = false; // Validate request data $validator = new ServerSideValidator($schema, $this->ci->translator); if (!$validator->validate($data)) { $ms->addValidationErrors($validator); $error = true; } // Check if name or slug already exists if ($classMapper->getClassMapping('organisation')::findUnique($data['name'], 'name')) { $ms->addMessageTranslated('danger', 'ORGANISATION.NAME.IN_USE', $data); $error = true; } if ($classMapper->getClassMapping('organisation')::findUnique($data['slug'], 'slug')) { $ms->addMessageTranslated('danger', 'ORGANISATION.SLUG.IN_USE', $data); $error = true; } if ($error) { return $response->withJson([], 400); } $data['flag_approved'] = 1; $data['registrant_id'] = $currentUser->id; // All checks passed! log events/activities and create organisation // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($classMapper, $data, $ms, $currentUser) { // Create the organisation $organisation = $classMapper->createInstance('organisation', $data); // Store new organisation to database $organisation->save(); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} created organisation {$organisation->name}.", [ 'type' => 'organisation_create', 'user_id' => $currentUser->id, ]); $ms->addMessageTranslated('success', 'ORGANISATION.CREATION_SUCCESSFUL', $data); }); return $response->withJson([], 200); } /** * Returns info for a single organisation. * * This page requires authentication. * Request type: GET * * @param Request $request * @param Response $response * @param string[] $args * * @throws NotFoundException If organisation is not found * @throws ForbiddenException If user is not authorized to access page */ public function getInfo(Request $request, Response $response, array $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; $organisation = $this->getOrganisationFromParams($args); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'uri_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } // Join organisation's member counts $organisation = $organisation->joinMemberCounts()->first(); $result = $organisation->toArray(); return $response->withJson($result, 200, JSON_PRETTY_PRINT); } /** * Processes the request to update an existing organisation's details. * * Processes the request from the organisation update form, checking that: * 1. The organisation name/slug are not already in use; * 2. The user has the necessary permissions to update the posted field(s); * 3. The submitted data is valid. * This route requires authentication (and should generally be limited to admins or the root user). * * Request type: PUT * * @see getModalOrganisationEdit * * @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 update(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; // Get the organisation based on slug in URL $organisation = $this->getOrganisationFromParams($args); if (!$organisation) { throw new NotFoundException(); } // Get PUT parameters: (name, slug, icon, description) $params = $request->getParsedBody(); // Load the request schema $schema = new RequestSchema('schema://requests/organisation/edit-info.yaml'); // Whitelist and set parameter defaults $transformer = new RequestDataTransformer($schema); $data = $transformer->transform($params); $error = false; // Validate request data $validator = new ServerSideValidator($schema, $this->ci->translator); if (!$validator->validate($data)) { $ms->addValidationErrors($validator); $error = true; } // Determine targeted fields $fieldNames = []; foreach ($data as $name => $value) { $fieldNames[] = $name; } // Access-controlled resource - check that currentUser has permission to edit submitted fields for this organisation if (!$authorizer->checkAccess($currentUser, 'update_organisation_field', [ 'organisation' => $organisation, 'fields' => array_values(array_unique($fieldNames)), ])) { throw new ForbiddenException(); } // Check if name or slug already exists if ( isset($data['name']) && $data['name'] != $organisation->name && $classMapper->getClassMapping('organisation')::findUnique($data['name'], 'name') ) { $ms->addMessageTranslated('danger', 'ORGANISATION.NAME.IN_USE', $data); $error = true; } if ( isset($data['slug']) && $data['slug'] != $organisation->slug && $classMapper->getClassMapping('organisation')::findUnique($data['slug'], 'slug') ) { $ms->addMessageTranslated('danger', 'ORGANISATION.SLUG.IN_USE', $data); $error = true; } if ($error) { return $response->withJson([], 400); } $oldSlug = $organisation->slug; // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($data, $organisation, $currentUser) { // Update the organisation and generate success messages foreach ($data as $name => $value) { if ($value != $organisation->$name) { $organisation->$name = $value; } } $organisation->save(); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} updated details for organisation {$organisation->name}.", [ 'type' => 'organisation_update_info', 'user_id' => $currentUser->id, ]); }); $ms->addMessageTranslated('success', 'ORGANISATION.UPDATE', [ 'name' => $organisation->name, ]); if ($oldSlug != $organisation->slug) { return $response->withJson([ 'redirect' => $this->ci->router->pathFor('uri_organisation', ['slug' => $organisation->slug]) ], 200); } else { return $response->withJson([], 200); } } /** * Processes the request to merge two organisations. * * Processes the request from the merge organisation form, checking that: * 1. The source organisation slug exists; * 2. The target organisation slug exists; * 3. The user has permission to merge organisations; * 4. The submitted data is valid. * This route requires authentication (and should generally be limited to admins or the root user). * * Request type: POST * * @see getModalMerge * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function merge(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'merge_organisations')) { throw new ForbiddenException(); } // Get POST parameters $params = $request->getParsedBody(); // Load the request schema $schema = new RequestSchema('schema://requests/organisation/merge.yaml'); // Whitelist and set parameter defaults $transformer = new RequestDataTransformer($schema); $data = $transformer->transform($params); // Validate, and return bad request on validation errors. $validator = new ServerSideValidator($schema, $this->ci->translator); if (!$validator->validate($data)) { $ms->addValidationErrors($validator); return $response->withJson([], 400); } // Get the organisations $source = $classMapper->getClassMapping('organisation')::findUnique($data['source_slug'], 'slug', false); $target = $classMapper->getClassMapping('organisation')::findUnique($data['target_slug'], 'slug', false); // If a organisation doesn't exist, return 404 if (!$source || !$target) { throw new NotFoundException(); } $sourceName = $source->name; // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($source, $target, $currentUser, $sourceName) { $this->ci->get('organisation.beforeMerge')($source, $target); $source->beforeMerge($target, ['currentUser' => $currentUser]); $source->delete(true); unset($source); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} merged organisation {$sourceName} into {$target->name}.", [ 'type' => 'organisation_merge', 'user_id' => $currentUser->id, ]); }); $ms->addMessageTranslated('success', 'ORGANISATION.MERGE_SUCCESSFUL', [ 'source' => $sourceName, 'target' => $target->name, ]); return $response->withJson([], 200); } /** * Processes the request to delete an existing organisation. * * Deletes the specified organisation. * Organisations with members will retain the membership information. * Before doing so, checks that: * 1. The user has permission to delete this organisation; * 2. The submitted data is valid. * This route requires authentication (and should generally be limited to admins or the root user). * * Request type: DELETE * * @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 * @throws BadRequestException */ public function delete(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; $organisation = $this->getOrganisationFromParams($args); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'delete_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } $organisationName = $organisation->name; // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($organisation, $currentUser, $organisationName) { // Delete the organisation (soft) $organisation->delete(); unset($organisation); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} deleted organisation {$organisationName}.", [ 'type' => 'organisation_delete', 'user_id' => $currentUser->id, ]); }); $ms->addMessageTranslated('success', 'ORGANISATION.DELETION_SUCCESSFUL', [ 'name' => $organisationName, ]); return $response->withJson([], 200); } /** * Processes the request to permenently delete a deleted organisation. * * Permenently deletes the specified organisation. * Before doing so, checks that: * 1. The user has permission to delete this organisation; * 2. The submitted data is valid. * This route requires authentication (and should generally be limited to admins or the root user). * * Request type: DELETE * * @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 * @throws BadRequestException */ public function deletePermenent(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; $organisation = $this->getOrganisationFromParams($args, true); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'permenent_delete_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } $organisationName = $organisation->name; // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($organisation, $organisationName, $currentUser) { // Delete the organisation (HARD) $organisation->delete(true); unset($organisation); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} permenetly deleted organisation {$organisationName}.", [ 'type' => 'organisation_delete', 'user_id' => $currentUser->id, ]); }); $ms->addMessageTranslated('success', 'ORGANISATION.PERMENENT_DELETION_SUCCESSFUL', [ 'name' => $organisationName, ]); return $response->withJson([], 200); } /** * Restores a deleted organisation * * Before doing so, checks that: * 1. The user has permission to restore this organisation; * 2. The submitted data is valid. * This route requires authentication (and should generally be limited to admins or the root user). * * Request type: PUT * * @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 * @throws BadRequestException */ public function restore(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\Sprinkle\Core\Alert\AlertStream $ms */ $ms = $this->ci->alerts; $organisation = $this->getOrganisationFromParams($args, true); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'restore_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } // Begin transaction - DB will be rolled back if an exception occurs Capsule::transaction(function () use ($organisation, $currentUser) { if (!$organisation->flag_approved) { $this->ci->repoOrganisationApproval->revert($organisation); } $organisation->restore(); // Create activity record $this->ci->userActivityLogger->info("User {$currentUser->user_name} restored deleted organisation {$organisation->name}.", [ 'type' => 'organisation_restore', 'user_id' => $currentUser->id, ]); }); $ms->addMessageTranslated('success', 'ORGANISATION.RESTORE_SUCCESSFUL', [ 'name' => $organisation->name, ]); return $response->withJson([], 200); } /** * Returns a list of Organisations. * * Generates a list of organisations, optionally paginated, sorted and/or filtered. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function getList(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'uri_organisations')) { throw new ForbiddenException(); } // GET parameters $params = $request->getQueryParams(); $params['ci'] = $this->ci; $sprunje = $classMapper->createInstance('organisation_sprunje', $classMapper, $params); $sprunje->extendQuery(function ($query) use ($currentUser) { return $query->withUser($currentUser->id); }); if (!$currentUser->isMaster() && $currentUser->roles()->where('slug', 'organisations-admin')->count() == 0) { $sprunje->extendQuery(function ($query) { return $query->where('flag_approved', true) ->orWhereNotNull('is_member'); }); } // 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); } /** * Returns a list of Organisations. * * Generates a list of organisations, optionally paginated, sorted and/or filtered. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function getListDeleted(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'uri_deleted_organisations')) { throw new ForbiddenException(); } // GET parameters $params = $request->getQueryParams(); $sprunje = $classMapper->createInstance('organisation_sprunje', $classMapper, $params); $sprunje->extendQuery(function ($query) use ($user) { return $query->onlyTrashed(); }); // 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 deletion confirmation modal. * * @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 * @throws BadRequestException */ public function getModalConfirmDelete(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; // GET parameters $params = $request->getQueryParams(); $organisation = $this->getOrganisationFromParams($params); // If the organisation no longer exists, forward to main organisation listing page if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'delete_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } return $this->ci->view->render($response, 'modals/confirm-delete-organisation.html.twig', [ 'organisation' => $organisation, 'form' => [ 'action' => "api/organisations/o/{$organisation->slug}", ], ]); } /** * Get permenent deletion confirmation modal. * * @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 * @throws BadRequestException */ public function getModalConfirmPermenentDelete(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; // GET parameters $params = $request->getQueryParams(); $organisation = $this->getOrganisationFromParams($params, true); // If the organisation no longer exists, forward to main organisation listing page if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'permenent_delete_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } return $this->ci->view->render($response, 'modals/confirm-permenent-delete-organisation.html.twig', [ 'organisation' => $organisation, 'form' => [ 'action' => "api/organisations/o/{$organisation->slug}/permenent", ], ]); } /** * Renders the modal form for creating a new organisation. * * This does NOT render a complete page. Instead, it renders the HTML for the modal, which can be embedded in other pages. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function getModalCreate(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\I18n\Translator $translator */ $translator = $this->ci->translator; // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'create_organisation')) { throw new ForbiddenException(); } // Create a dummy organisation to prepopulate fields $organisation = $classMapper->createInstance('organisation', []); $fieldNames = ['name', 'slug', 'description']; $fields = [ 'hidden' => [], 'disabled' => [], ]; // Load validation rules $schema = new RequestSchema('schema://requests/organisation/create.yaml'); $validator = new JqueryValidationAdapter($schema, $this->ci->translator); return $this->ci->view->render($response, 'modals/organisation.html.twig', [ 'organisation' => $organisation, 'form' => [ 'action' => 'api/organisations', 'method' => 'POST', 'fields' => $fields, 'submit_text' => $translator->translate('CREATE'), ], 'page' => [ 'validators' => $validator->rules('json', false), ], ]); } /** * Renders the modal form for editing an existing organisation. * * This does NOT render a complete page. Instead, it renders the HTML for the modal, which can be embedded in other pages. * This page requires authentication. * * Request type: GET * * @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 getModalEdit(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\I18n\Translator $translator */ $translator = $this->ci->translator; // GET parameters $params = $request->getQueryParams(); $organisation = $this->getOrganisationFromParams($params); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Generate form $fields = [ 'hidden' => [], 'disabled' => [], ]; // Access-controlled resource - check that currentUser has permission to edit basic fields "name", "slug", "description" for this organisation $fieldNames = ['name', 'slug', 'description']; foreach ($fieldNames as $field) { if (!$authorizer->checkAccess($currentUser, 'update_organisation_field', [ 'organisation' => $organisation, 'fields' => [$field], ])) { $fields['disabled'][] = $field; } } if (!$currentUser->isMaster() && $currentUser->roles()->where('slug', 'organisations-admin')->count() == 0) { $fields['hidden'][] = 'slug'; } // Load validation rules $schema = new RequestSchema('schema://requests/organisation/edit-info.yaml'); $validator = new JqueryValidationAdapter($schema, $translator); return $this->ci->view->render($response, 'modals/organisation.html.twig', [ 'organisation' => $organisation, 'form' => [ 'action' => "api/organisations/o/{$organisation->slug}", 'method' => 'PUT', 'fields' => $fields, 'submit_text' => $translator->translate('UPDATE'), ], 'page' => [ 'validators' => $validator->rules('json', false), ], ]); } /** * Renders the modal form for merging two organisations. * * This does NOT render a complete page. Instead, it renders the HTML for the modal, which can be embedded in other pages. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function getModalMerge(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Core\Util\ClassMapper $classMapper */ $classMapper = $this->ci->classMapper; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; /** @var \UserFrosting\I18n\Translator $translator */ $translator = $this->ci->translator; // GET parameters $params = $request->getQueryParams(); $organisation = $this->getOrganisationFromParams($params); // If the organisation doesn't exist, return 404 if (!$organisation) { throw new NotFoundException(); } // Access-controlled resource - check that currentUser has permission to merge organisations. if (!$authorizer->checkAccess($currentUser, 'merge_organisations')) { throw new ForbiddenException(); } // Load validation rules $schema = new RequestSchema('schema://requests/organisation/merge.yaml'); $validator = new JqueryValidationAdapter($schema, $translator); $otherOrganisations = $classMapper->getClassMapping('organisation')::where('id', '!=', $organisation->id)->get(); return $this->ci->view->render($response, 'modals/organisation-merge.html.twig', [ 'organisation' => $organisation, 'other_organisations' => $otherOrganisations, 'form' => [ 'action' => "api/organisations/o/{$organisation->slug}/merge", 'method' => 'POST', 'submit_text' => $translator->translate('MERGE'), ], 'page' => [ 'validators' => $validator->rules('json', false), ], ]); } /** * Renders a page displaying a organisation's information, in read-only mode. * * This checks that the currently logged-in user has permission to view the requested organisation's info. * It checks each field individually, showing only those that you have permission to view. * This will also try to show buttons for deleting, and editing the organisation. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function pageInfo(Request $request, Response $response, $args) { /** @var \UserFrosting\Sprinkle\Account\Authorize\AuthorizationManager $authorizer */ $authorizer = $this->ci->authorizer; /** @var \UserFrosting\Sprinkle\Account\Database\Models\Interfaces\UserInterface $currentUser */ $currentUser = $this->ci->currentUser; $organisation = $this->getOrganisationFromParams($args); // If the organisation no longer exists, forward to main organisation listing page if (!$organisation) { throw new NotFoundException(); } // Access-controlled page if (!$authorizer->checkAccess($currentUser, 'uri_organisation', [ 'organisation' => $organisation, ])) { throw new ForbiddenException(); } // Determine fields that currentUser is authorized to view $fieldNames = ['name', 'slug', 'description', 'members']; // Generate form $fields = [ 'hidden' => [], ]; foreach ($fieldNames as $field) { if (!$authorizer->checkAccess($currentUser, 'view_organisation_field', [ 'organisation' => $organisation, 'property' => $field, ])) { $fields['hidden'][] = $field; } } // Determine buttons to display $editButtons = [ 'hidden' => [], ]; if (!$authorizer->checkAccess($currentUser, 'update_organisation_field', [ 'organisation' => $organisation, 'fields' => [], ])) { $editButtons['hidden'][] = 'edit'; } if (!$authorizer->checkAccess($currentUser, 'delete_organisation', [ 'organisation' => $organisation, ])) { $editButtons['hidden'][] = 'delete'; } $canAccessOrganisations = $authorizer->checkAccess($currentUser, 'uri_organisations'); return $this->ci->view->render($response, 'pages/organisation.html.twig', [ 'organisation' => $organisation, 'fields' => $fields, 'tools' => $editButtons, 'delete_redirect' => ($canAccessOrganisations ? $this->ci->router->pathFor('uri_organisations') : $this->ci->router->pathFor('dashboard')), 'leave_redirect' => ($canAccessOrganisations ? $this->ci->router->pathFor('uri_organisations') : $this->ci->router->pathFor('dashboard')), ]); } /** * Renders the organisation listing page. * * This page renders a table of organisations, with dropdown menus for admin actions for each organisation. * Actions typically include: edit organisation, delete organisation. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function pageList(Request $request, Response $response, $args) { /** @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, 'uri_organisations')) { throw new ForbiddenException(); } return $this->ci->view->render($response, 'pages/organisations.html.twig'); } /** * Renders the organisation listing page for deleted organisations. * * This page renders a table of organisations, with dropdown menus for admin actions for each organisation. * Actions typically include: restore organisation, permenently delete etd. * This page requires authentication. * * Request type: GET * * @param Request $request * @param Response $response * @param array $args * * @throws ForbiddenException If user is not authorized to access page */ public function pageListDeleted(Request $request, Response $response, $args) { /** @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, 'uri_deleted_organisations')) { throw new ForbiddenException(); } return $this->ci->view->render($response, 'pages/deleted-organisations.html.twig'); } /** * Get organisation from params. * * @param array $params * * @throws BadRequestException * * @return Organisation */ protected function getOrganisationFromParams($params, $withTrashed = false) { // 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; $query = $classMapper->getClassMapping('organisation')::where('slug', $data['slug']); if ($withTrashed) { $query->withTrashed(); } // Get the organisation $organisation = $query->first(); return $organisation; } }