Skip to content

Commit

Permalink
pkp#10630 Add support for add existing user to a context
Browse files Browse the repository at this point in the history
  • Loading branch information
defstat committed Nov 24, 2024
1 parent 6013d78 commit 7aed60a
Show file tree
Hide file tree
Showing 10 changed files with 326 additions and 140 deletions.
140 changes: 62 additions & 78 deletions api/v1/invitations/InvitationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,8 @@
use PKP\invitation\core\Invitation;
use PKP\invitation\core\ReceiveInvitationController;
use PKP\invitation\core\traits\HasMailable;
use PKP\invitation\invitations\userRoleAssignment\resources\UserRoleAssignmentInviteResource;
use PKP\invitation\invitations\userRoleAssignment\rules\EmailMustNotExistRule;
use PKP\invitation\invitations\userRoleAssignment\rules\UserMustExistRule;
use PKP\invitation\models\InvitationModel;
use PKP\security\authorization\UserRolesRequiredPolicy;
use PKP\security\Role;
use PKP\validation\ValidatorFactory;
use Validator;
Expand All @@ -45,18 +42,24 @@ class InvitationController extends PKPBaseController
public const PARAM_ID = 'invitationId';
public const PARAM_KEY = 'key';

public $notNeedAPIHandler = [
'getMany',
public $actionsInvite = [
'get',
'populate',
'invite',
'getMailable',
'cancel',
];

public $noParamRequired = [
'getMany',
public $actionsReceive = [
'receive',
'finalize',
'refine',
'decline',
'cancel',
];

public $requiresType = [
'add',
'getMany',
];

public $requiresOnlyId = [
Expand Down Expand Up @@ -124,7 +127,7 @@ public function getGroupRoutes(): void
]),
])->group(function () {

Route::get('', $this->getMany(...))
Route::get('{type}', $this->getMany(...))
->name('invitation.getMany');

// Get By Id Methods
Expand Down Expand Up @@ -207,45 +210,39 @@ public function authorize(PKPRequest $request, array &$args, array $roleAssignme
$invitation = Repo::invitation()->getByIdAndKey($invitationId, $invitationKey);
}

if ($actionName == 'getMany') {
$this->addPolicy(new UserRolesRequiredPolicy($request), true);
} else {
if (!isset($invitation)) {
throw new Exception('Invitation could not be created');
}

$this->invitation = $invitation;
if (!isset($invitation)) {
throw new Exception('Invitation could not be created');
}

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

if (in_array($actionName, $this->requiresOnlyId) && $this->invitation->getStatus() != InvitationStatus::INITIALIZED) {
throw new Exception('This action is not allowed');
}
if (!$this->invitation instanceof IApiHandleable) {
throw new Exception('This invitation does not support API handling');
}

if (in_array($actionName, $this->requiresIdAndKey) && $this->invitation->getStatus() != InvitationStatus::PENDING) {
throw new Exception('This action is not allowed');
}
if (in_array($actionName, $this->actionsInvite) && $this->invitation->getStatus() != InvitationStatus::INITIALIZED) {
throw new Exception('This action is not allowed');
}

$this->createInvitationHandler = $invitation->getCreateInvitationController($this->invitation);
$this->receiveInvitationHandler = $invitation->getReceiveInvitationController($this->invitation);
if (in_array($actionName, $this->actionsReceive) && $this->invitation->getStatus() != InvitationStatus::PENDING) {
throw new Exception('This action is not allowed');
}

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

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

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

$this->selectedHandler->authorize($this, $request, $args, $roleAssignments);
}
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);
}

Expand All @@ -269,7 +266,6 @@ public function add(Request $illuminateRequest): JsonResponse
'nullable',
'required_without:userId',
'email',
new EmailMustNotExistRule($payload['inviteeEmail']),
]
];

Expand Down Expand Up @@ -338,63 +334,51 @@ public function getMany(Request $illuminateRequest): JsonResponse
$context = $illuminateRequest->attributes->get('context'); /** @var \PKP\context\Context $context */
$invitationType = $this->getParameter(self::PARAM_TYPE);

$count = $illuminateRequest->query('count', 10); // default count to 10 if not provided
$offset = $illuminateRequest->query('offset', 0); // default offset to 0 if not provided

// Build the common query
$query = InvitationModel::query()
->when($invitationType, function ($query, $invitationType) {
return $query->byType($invitationType);
})
->when($context, function ($query, $context) {
return $query->byContextId($context->getId());
})
->when($invitationType, fn($query) => $query->byType($invitationType))
->when($context, fn($query) => $query->byContextId($context->getId()))
->stillActive();

$maxCount = $query->count();

$invitations = $query->skip($offset)
->take($count)
->get();

$finalCollection = $invitations->map(function ($invitation) {
$specificInvitation = Repo::invitation()->getById($invitation->id);
return $specificInvitation;
});
// Delegate to the specific handler for additional logic
$specificData = $this->selectedHandler->getMany($illuminateRequest, $query);

return response()->json([
'itemsMax' => $maxCount,
'items' => (UserRoleAssignmentInviteResource::collection($finalCollection)),
'itemsMax' => $query->count(),
'items' => $specificData,
], Response::HTTP_OK);
}

public function getMailable(Request $illuminateRequest): JsonResponse
public function cancel(Request $illuminateRequest): JsonResponse
{
if (in_array(HasMailable::class, class_uses($this->invitation))) {
$mailable = $this->invitation->getMailable();

if (!$this->invitation->isPending()) {
return response()->json([
'mailable' => $mailable,
], Response::HTTP_OK);
'error' => __('invitation.api.error.invitationCantBeCanceled'),
], Response::HTTP_BAD_REQUEST);
}

return response()->json([
'error' => __('invitation.api.error.invitationTypeNotHasMailable'),
], Response::HTTP_BAD_REQUEST);
try {
return $this->selectedHandler->cancel();
} catch (\Exception $e) {
return response()->json([], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}

public function cancel(Request $illuminateRequest): JsonResponse
public function getMailable(Request $illuminateRequest): JsonResponse
{
if (!$this->invitation->isPending()) {
// Ensure the invitation supports mailables
if (!in_array(HasMailable::class, class_uses($this->invitation))) {
return response()->json([
'error' => __('invitation.api.error.invitationCantBeCanceled'),
'error' => __('invitation.api.error.invitationTypeNotHasMailable'),
], Response::HTTP_BAD_REQUEST);
}

$this->invitation->updateStatus(InvitationStatus::CANCELLED);

return response()->json(
(new UserRoleAssignmentInviteResource($this->invitation))->toArray($illuminateRequest),
Response::HTTP_OK
);
try {
return $this->selectedHandler->getMailable();
} catch (\Exception $e) {
return response()->json([
'error' => $e->getMessage(),
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
}
7 changes: 6 additions & 1 deletion classes/invitation/core/CreateInvitationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@

namespace PKP\invitation\core;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Collection;
use PKP\core\PKPBaseController;
use PKP\core\PKPRequest;
use PKP\invitation\core\Invitation;

abstract class CreateInvitationController extends Controller
{
Expand All @@ -30,4 +31,8 @@ abstract public function add(Request $illuminateRequest): JsonResponse;
abstract public function populate(Request $illuminateRequest): JsonResponse;
abstract public function invite(Request $illuminateRequest): JsonResponse;
abstract public function get(Request $illuminateRequest): JsonResponse;

abstract public function cancel(): JsonResponse;
abstract public function getMailable(): JsonResponse;
abstract public function getMany(Request $illuminateRequest, Builder $query): Collection;
}
19 changes: 12 additions & 7 deletions classes/invitation/core/Invitation.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,7 @@ public function updatePayload(?ValidationContext $validationContext = null): ?bo
}
}

// Update the payload attribute on the invitation model
$this->invitationModel->setAttribute('payload', $currentPayloadArray);

// Save the updated invitation model to the database
return $this->invitationModel->save();
return $this->invitationModel->update(['payload' => $currentPayloadArray]);
}

public function getNotAccessibleBeforeInvite(): array
Expand Down Expand Up @@ -351,6 +347,15 @@ public function getExistingUser(): ?User
return Repo::user()->get($this->invitationModel->userId);
}

public function getExistingUserByEmail(): ?User
{
if (!isset($this->invitationModel->email)) {
return null;
}

return Repo::user()->getByEmail($this->invitationModel->email);
}

public function getContext(): ?Context
{
if (!isset($this->invitationModel->contextId)) {
Expand Down Expand Up @@ -480,10 +485,10 @@ protected function array_diff_assoc_recursive($array1, $array2)
return $difference;
}

public function updateStatus(InvitationStatus $status): void
public function updateStatus(InvitationStatus $status): bool
{
$this->invitationModel->status = $status;
$this->invitationModel->save();
return $this->invitationModel->save();
}

public function isPending(): bool
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
use PKP\invitation\invitations\userRoleAssignment\rules\UserMustExistRule;
use PKP\mail\mailables\UserRoleAssignmentInvitationNotify;
use PKP\security\Validation;
use PKP\user\User;

class UserRoleAssignmentInvite extends Invitation implements IApiHandleable
{
Expand Down Expand Up @@ -166,6 +167,11 @@ public function getValidationRules(ValidationContext $validationContext = Valida
$this->getPayload()->userGroupsToAdd
);
$invitationValidationRules[Invitation::VALIDATION_RULE_GENERIC][] = new UserMustExistRule($this->getUserId());
}

if (
$validationContext === ValidationContext::VALIDATION_CONTEXT_FINALIZE
) {
$invitationValidationRules[Invitation::VALIDATION_RULE_GENERIC][] = new EmailMustNotExistRule($this->getEmail());
}

Expand Down Expand Up @@ -207,5 +213,25 @@ public function updatePayload(?ValidationContext $validationContext = null): ?bo
// Call the parent updatePayload method to continue the normal update process
return parent::updatePayload($validationContext);
}


public function changeInvitationUserIdUsingUserEmail(): ?bool
{
$invitationUserByEmail = $this->getExistingUserByEmail();

if (!isset($this->invitationModel->userId) && isset($invitationUserByEmail)) {
$this->invitationModel->userId = $invitationUserByEmail->getId();
$this->invitationModel->email = null;

$result = $this->invitationModel->save();

if ($result) {
$this->getPayload()->shouldUseInviteData = true;

return $this->updatePayload();
}
}

return null;
}

}
Loading

0 comments on commit 7aed60a

Please sign in to comment.