Skip to content

Commit

Permalink
pkp#9887 Redesign Invitations
Browse files Browse the repository at this point in the history
  • Loading branch information
defstat committed May 31, 2024
1 parent b2819aa commit 217eb46
Show file tree
Hide file tree
Showing 46 changed files with 2,011 additions and 910 deletions.
246 changes: 246 additions & 0 deletions api/v1/invitations/PKPInvitationController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
<?php

/**
* @file api/v1/invitations/PKPInvitationController.php
*
* Copyright (c) 2023 Simon Fraser University
* Copyright (c) 2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPInvitationController
*
* @brief Controller class to handle API requests for invitations operations.
*
*/

namespace PKP\API\v1\invitations;

use APP\facades\Repo;
use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use PKP\core\PKPBaseController;
use PKP\core\PKPRequest;
use PKP\invitation\invitations\contacts\IApiHandleable;
use PKP\invitation\invitations\PKPCreateInvitationController;
use PKP\invitation\invitations\Invitation;
use PKP\invitation\invitations\PKPReceiveInvitationController;
use PKP\invitation\models\InvitationModel;
use PKP\security\Role;

class PKPInvitationController extends PKPBaseController
{
public const PARAM_TYPE = 'type';
public const PARAM_ID = 'invitationId';
public const PARAM_KEY = 'key';

public $requiresType = [
'add',
];

public $requiresOnlyId = [
'get',
'populate',
'dispatchInvitation',
];

public $requiresIdAndKey = [
'receive',
'finalise',
'refine',
'decline',
];

private ?Invitation $invitation = null;
private ?PKPCreateInvitationController $createInvitationHandler = null;
private ?PKPReceiveInvitationController $receiveInvitationHandler = null;
private PKPCreateInvitationController|PKPReceiveInvitationController|null $selectedHandler = null;

private function getHandlerForAction(string $actionName)
{
if (in_array($actionName, $this->requiresType) || in_array($actionName, $this->requiresOnlyId)) {
return $this->createInvitationHandler;
}

if (in_array($actionName, $this->requiresIdAndKey)) {
return $this->receiveInvitationHandler;
}

throw new Exception("No handler defined for the action: $actionName");
}

/**
* @copydoc \PKP\core\PKPBaseController::getHandlerPath()
*/
public function getHandlerPath(): string
{
return 'invitations';
}

/**
* @copydoc \PKP\core\PKPBaseController::getRouteGroupMiddleware()
*/
public function getRouteGroupMiddleware(): array
{
return [];
}

/**
* @copydoc \PKP\core\PKPBaseController::getGroupRoutes()
*/
public function getGroupRoutes(): void
{
// Get By Id Methods
Route::get('{invitationId}', $this->get(...))
->name('invitation.get')
->whereNumber('invitationId')
->middleware([
self::roleAuthorizer(Role::getAllRoles()),
]);

Route::post('add/{type}', $this->add(...))
->name('invitation.add')
->middleware([
self::roleAuthorizer(Role::getAllRoles()),
]);

Route::put('{invitationId}/populate', $this->populate(...))
->name('invitation.populate')
->whereNumber('invitationId')
->middleware([
self::roleAuthorizer(Role::getAllRoles()),
]);

Route::put('{invitationId}/dispatch', $this->dispatchInvitation(...))
->name('invitation.dispatch')
->whereNumber('invitationId')
->middleware([
self::roleAuthorizer(Role::getAllRoles()),
]);

// Get By Key methods.
Route::get('{invitationId}/key/{key}', $this->receive(...))
->name('invitation.receive')
->whereNumber('invitationId');

Route::put('{invitationId}/key/{key}/finalize', $this->finalize(...))
->name('invitation.finalize')
->whereNumber('invitationId');

Route::put('{invitationId}/key/{key}/refine', $this->refine(...))
->name('invitation.refine')
->whereNumber('invitationId');

Route::put('{invitationId}/key/{key}/decline', $this->decline(...))
->name('invitation.decline')
->whereNumber('invitationId');
}

/**
* @copydoc \PKP\core\PKPBaseController::authorize()
*/
public function authorize(PKPRequest $request, array &$args, array $roleAssignments): bool
{
$illuminateRequest = $args[0]; /** @var \Illuminate\Http\Request $illuminateRequest */
$actionName = static::getRouteActionName($illuminateRequest);

$invitation = null;

$invitationType = $this->getParameter(self::PARAM_TYPE);
$invitationId = (int) $this->getParameter(self::PARAM_ID);
$invitationKey = $this->getParameter(self::PARAM_KEY);

if (in_array($actionName, $this->requiresType)) {
if (!isset($invitationType)) {
throw new Exception("Parameter with the name '" . self::PARAM_TYPE . "' needs to be declared");
}

$invitation = app(Invitation::class)->createNew($invitationType);
} elseif (in_array($actionName, $this->requiresOnlyId)) {
if (!isset($invitationId)) {
throw new Exception("Parameter with the name '" . self::PARAM_ID . "' needs to be declared");
}

$invitationModel = InvitationModel::find($invitationId);
if (!isset($invitationModel)) {
throw new Exception("Invitation not found");
}

$invitation = app(Invitation::class)->getExisting($invitationModel->type, $invitationModel);
} elseif (in_array($actionName, $this->requiresIdAndKey)) {
if (!isset($invitationId) || !isset($invitationKey)) {
throw new Exception("Parameters with the names '" . self::PARAM_ID . "' and '" . self::PARAM_KEY . "' need to be declared");
}

$invitation = Repo::invitation()->getByIdAndKey($invitationId, $invitationKey);
}

if (!isset($invitation)) {
throw new Exception("Invitation could not be created");
}

$this->invitation = $invitation;

if (!$this->invitation instanceof IApiHandleable) {
throw new Exception('This invitation does not support API handling');
}

$this->createInvitationHandler = $invitation->getCreateInvitationController();
$this->receiveInvitationHandler = $invitation->getReceiveInvitationController();

if (!isset($this->createInvitationHandler) || !isset($this->receiveInvitationHandler)) {
throw new Exception('This invitation should have defined its API handling code');
}

$this->selectedHandler = $this->getHandlerForAction($actionName);

if (!method_exists($this->selectedHandler, $actionName)) {
throw new Exception("The handler does not support the method: $actionName");
}

$this->selectedHandler->authorize($this, $request, $args, $roleAssignments);

return parent::authorize($request, $args, $roleAssignments);
}

public function add(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->add($illuminateRequest);
}

public function get(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->get($illuminateRequest);
}

public function populate(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->populate($illuminateRequest);
}

public function dispatchInvitation(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->dispatch($illuminateRequest);
}

public function receive(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->receive($illuminateRequest);
}

public function refine(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->refine($illuminateRequest);
}

public function finalize(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->finalize($illuminateRequest);
}

public function decline(Request $illuminateRequest): JsonResponse
{
return $this->selectedHandler->decline($illuminateRequest);
}
}
1 change: 1 addition & 0 deletions classes/core/PKPContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ public function registerConfiguredProviders()
$this->register(new AppServiceProvider($this));
$this->register(new LocaleServiceProvider($this));
$this->register(new PKPRoutingProvider($this));
$this->register(new PKPInvitationServiceProvider($this));
}

/**
Expand Down
63 changes: 63 additions & 0 deletions classes/core/PKPInvitationServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/**
* @file classes/core/PKPInvitationServiceProvider.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPInvitationServiceProvider
*
* @brief Registers a new service provider for Invitations
*/

namespace PKP\core;

use Illuminate\Support\ServiceProvider;
use PKP\invitation\core\PKPInvitationFactory;
use PKP\invitation\invitations\Invitation;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

class PKPInvitationServiceProvider extends ServiceProvider
{
public function register(): void
{
// Ensures that PKPInvitationFactory is initialized only once
$this->app->singleton(Invitation::class, function ($app) {
PKPInvitationFactory::init();
return PKPInvitationFactory::getInstance();
});
}

public function boot(): void
{
$this->preloadInvitationClasses();
}

protected function preloadInvitationClasses(): void
{
$invitationDirectories = [
'PKP\invitations' => __DIR__ . '/../../invitations',
'APP\invitations' => __DIR__ . '/../../../../invitations',
];

foreach ($invitationDirectories as $namespace => $path) {
if (!is_dir($path)) {
continue;
}

$invitationDirectory = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator($invitationDirectory);

foreach ($iterator as $file) {
if ($file->isFile() && preg_match('/Invite\.php$/', $file->getFilename())) {
$className = $namespace . '\\' . str_replace('.php', '', $file->getFilename());

class_exists($className, true);
}
}
}
}
}
2 changes: 1 addition & 1 deletion classes/facades/Repo.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
use PKP\emailTemplate\Repository as EmailTemplateRepository;
use PKP\highlight\Repository as HighlightRepository;
use PKP\institution\Repository as InstitutionRepository;
use PKP\invitation\repositories\Invitation as InvitationRepository;
use PKP\invitation\repositories\Repository as InvitationRepository;
use PKP\job\repositories\FailedJob as FailedJobRepository;
use PKP\job\repositories\Job as JobRepository;
use PKP\log\event\Repository as EventLogRepository;
Expand Down
44 changes: 44 additions & 0 deletions classes/invitation/core/PKPInvitationDiscovery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/**
* @file classes/invitation/core/PKPInvitationDiscovery.php
*
* Copyright (c) 2023 Simon Fraser University
* Copyright (c) 2023 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPInvitationDiscovery
*
* @ingroup invitation
*
* @brief Invitation Discovery service class
*/

namespace PKP\invitation\core;

use PKP\invitation\invitations\Invitation;
use ReflectionClass;

class PKPInvitationDiscovery
{
public static function discoverInvitations(): array
{
$invitations = [];

$invitationClasses = array_filter(get_declared_classes(), function($value) {
return preg_match('/Invite$/', $value) === 1;
});

foreach ($invitationClasses as $invitationClass) {
if (is_subclass_of($invitationClass, Invitation::class)) {
$reflectedClass = new ReflectionClass($invitationClass);
if (!$reflectedClass->isAbstract()) {
$type = $invitationClass::getType();
$invitations[$type] = $invitationClass;
}
}
}

return $invitations;
}
}
Loading

0 comments on commit 217eb46

Please sign in to comment.