From d264fa552af8a02a555410578ae964577bcead45 Mon Sep 17 00:00:00 2001 From: ipula Date: Thu, 24 Oct 2024 16:00:29 +0200 Subject: [PATCH 1/5] send and accept invitation views and php integrations --- .../invitation/AcceptUserDetailsForm.php | 87 +++++ .../forms/invitation/UserDetailsForm.php | 69 ++++ ...RoleAssignmentInviteRedirectController.php | 40 ++- classes/invitation/sections/Email.php | 98 ++++++ classes/invitation/sections/Form.php | 45 +++ classes/invitation/sections/Section.php | 54 +++ classes/invitation/sections/Sections.php | 75 +++++ .../stepTypes/AcceptInvitationStep.php | 212 ++++++++++++ .../stepTypes/InvitationStepTypes.php | 34 ++ .../stepTypes/SendInvitationStep.php | 186 +++++++++++ classes/invitation/steps/Step.php | 73 +++++ js/load.js | 6 + locale/en/invitation.po | 308 +++++++++++++++++- locale/en/user.po | 3 + pages/invitation/InvitationHandler.php | 142 ++++++++ pages/invitation/index.php | 1 + templates/invitation/acceptInvitation.tpl | 23 ++ templates/invitation/userInvitation.tpl | 25 ++ templates/management/access.tpl | 1 + 19 files changed, 1478 insertions(+), 4 deletions(-) create mode 100644 classes/components/forms/invitation/AcceptUserDetailsForm.php create mode 100644 classes/components/forms/invitation/UserDetailsForm.php create mode 100644 classes/invitation/sections/Email.php create mode 100644 classes/invitation/sections/Form.php create mode 100644 classes/invitation/sections/Section.php create mode 100644 classes/invitation/sections/Sections.php create mode 100644 classes/invitation/stepTypes/AcceptInvitationStep.php create mode 100644 classes/invitation/stepTypes/InvitationStepTypes.php create mode 100644 classes/invitation/stepTypes/SendInvitationStep.php create mode 100644 classes/invitation/steps/Step.php create mode 100644 templates/invitation/acceptInvitation.tpl create mode 100644 templates/invitation/userInvitation.tpl diff --git a/classes/components/forms/invitation/AcceptUserDetailsForm.php b/classes/components/forms/invitation/AcceptUserDetailsForm.php new file mode 100644 index 00000000000..532ed843537 --- /dev/null +++ b/classes/components/forms/invitation/AcceptUserDetailsForm.php @@ -0,0 +1,87 @@ +action = $action; + $this->locales = $locales; + + $countries = []; + foreach (Locale::getCountries() as $country) { + $countries[] = [ + 'value' => $country->getAlpha2(), + 'label' => $country->getLocalName() + ]; + } + + usort($countries, function ($a, $b) { + return strcmp($a['label'], $b['label']); + }); + + $this->addField(new FieldText('givenName', [ + 'label' => __('user.givenName'), + 'description' => __('acceptInvitation.userDetailsForm.givenName.description'), + 'isRequired' => true, + 'isMultilingual' => true, + 'size' => 'large', + 'value' => '' + ])) + ->addField(new FieldText('familyName', [ + 'label' => __('user.familyName'), + 'description' => __('acceptInvitation.userDetailsForm.familyName.description'), + 'isRequired' => false, + 'isMultilingual' => true, + 'size' => 'large', + 'value' => '' + ])) + ->addField(new FieldText('affiliation', [ + 'label' => __('user.affiliation'), + 'description' => __('acceptInvitation.userDetailsForm.affiliation.description'), + 'isMultilingual' => true, + 'isRequired' => false, + 'size' => 'large', + + ])) + ->addField(new FieldSelect('userCountry', [ + 'label' => __('acceptInvitation.userDetailsForm.countryOfAffiliation.label'), + 'description' => __('acceptInvitation.userDetailsForm.countryOfAffiliation.description'), + 'options' => $countries, + 'isRequired' => true, + 'size' => 'large', + ])); + + } +} diff --git a/classes/components/forms/invitation/UserDetailsForm.php b/classes/components/forms/invitation/UserDetailsForm.php new file mode 100644 index 00000000000..01306aec5f4 --- /dev/null +++ b/classes/components/forms/invitation/UserDetailsForm.php @@ -0,0 +1,69 @@ +action = $action; + $this->locales = $locales; + + $this->addField(new FieldText('inviteeEmail', [ + 'label' => __('user.email'), + 'description' => __('invitation.email.description'), + 'isRequired' => true, + 'size' => 'large', + ])) + ->addField(new FieldHTML('orcid', [ + 'label' => __('user.orcid'), + 'description' => __('invitation.orcid.description'), + 'isRequired' => false, + 'size' => 'large', + ])) + ->addField(new FieldText('givenName', [ + 'label' => __('user.givenName'), + 'description' => __('invitation.givenName.description'), + 'isRequired' => false, + 'isMultilingual' => true, + 'size' => 'large', + ])) + ->addField(new FieldText('familyName', [ + 'label' => __('user.familyName'), + 'description' => __('invitation.familyName.description'), + 'isRequired' => false, + 'isMultilingual' => true, + 'size' => 'large', + ])); + } +} diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php index c0832538780..07b923a5868 100644 --- a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php +++ b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php @@ -15,9 +15,12 @@ use APP\core\Request; use APP\template\TemplateManager; +use PKP\core\PKPApplication; use PKP\invitation\core\enums\InvitationAction; +use PKP\invitation\core\enums\InvitationStatus; use PKP\invitation\core\InvitationActionRedirectController; use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite; +use PKP\invitation\stepTypes\AcceptInvitationStep; class UserRoleAssignmentInviteRedirectController extends InvitationActionRedirectController { @@ -29,14 +32,45 @@ public function getInvitation(): UserRoleAssignmentInvite public function acceptHandle(Request $request): void { $templateMgr = TemplateManager::getManager($request); - $templateMgr->assign('invitation', $this->invitation); - $templateMgr->display('frontend/pages/invitations.tpl'); + $context = $request->getContext(); + $steps = new AcceptInvitationStep(); + $templateMgr->setState([ + 'steps' => $steps->getSteps($this->invitation, $context), + 'primaryLocale' => $context->getData('primaryLocale'), + 'pageTitle' => __('invitation.wizard.pageTitle'), + 'invitationId' => (int)$request->getUserVar('id') ?: null, + 'invitationKey' => $request->getUserVar('key') ?: null, + 'pageTitleDescription' => __('invitation.wizard.pageTitleDescription'), + ]); + $templateMgr->assign([ + 'pageComponent' => 'PageOJS', + ]); + $templateMgr->display('invitation/acceptInvitation.tpl'); } public function declineHandle(Request $request): void { - return; + if ($this->invitation->getStatus() !== InvitationStatus::PENDING) { + $request->getDispatcher()->handle404(); + } + + $context = $request->getContext(); + + $url = PKPApplication::get()->getDispatcher()->url( + PKPApplication::get()->getRequest(), + PKPApplication::ROUTE_PAGE, + $context->getData('urlPath'), + 'login', + null, + null, + [ + ] + ); + + $this->getInvitation()->decline(); + + $request->redirectUrl($url); } public function preRedirectActions(InvitationAction $action) diff --git a/classes/invitation/sections/Email.php b/classes/invitation/sections/Email.php new file mode 100644 index 00000000000..8e80d42a2bf --- /dev/null +++ b/classes/invitation/sections/Email.php @@ -0,0 +1,98 @@ + $recipients One or more User objects who are the recipients of this email + * @param Mailable $mailable The mailable that will be used to send this email + * + * @throws Exception + */ + public function __construct(string $id, string $name, string $description, array $recipients, Mailable $mailable, array $locales) + { + parent::__construct($id, $name, $description); + $this->locales = $locales; + $this->mailable = $mailable; + $this->recipients = $recipients; + } + + public function getState(): stdClass + { + $config = parent::getState(); + $config->canChangeRecipients = false; + $config->canSkip = false; + $config->emailTemplates = $this->getEmailTemplates(); + $config->initialTemplateKey = $this->mailable::getEmailTemplateKey(); + $config->recipientOptions = $this->getRecipientOptions(); + $config->anonymousRecipients = $this->anonymousRecipients; + $config->variables = []; + $config->locale = Locale::getLocale(); + $config->locales = []; + return $config; + } + + protected function getRecipientOptions(): array + { + $recipientOptions = []; + foreach ($this->recipients as $user) { + $names = []; + foreach ($this->locales as $locale) { + $names[$locale] = $user->getFullName(true, false, $locale); + } + $recipientOptions[] = [ + 'value' => $user->getId(), + 'label' => $names, + ]; + } + return $recipientOptions; + } + + protected function getEmailTemplates(): array + { + $request = Application::get()->getRequest(); + $context = $request->getContext(); + + $emailTemplates = collect(); + if ($this->mailable::getEmailTemplateKey()) { + $emailTemplate = Repo::emailTemplate()->getByKey($context->getId(), $this->mailable::getEmailTemplateKey()); + if ($emailTemplate) { + $emailTemplates->add($emailTemplate); + } + Repo::emailTemplate() + ->getCollector($context->getId()) + ->alternateTo([$this->mailable::getEmailTemplateKey()]) + ->getMany() + ->each(fn (EmailTemplate $e) => $emailTemplates->add($e)); + } + + return Repo::emailTemplate()->getSchemaMap()->mapMany($emailTemplates)->toArray(); + } +} diff --git a/classes/invitation/sections/Form.php b/classes/invitation/sections/Form.php new file mode 100644 index 00000000000..c62ba7fb3db --- /dev/null +++ b/classes/invitation/sections/Form.php @@ -0,0 +1,45 @@ +form = $form; + } + + public function getState(): stdClass + { + $config = parent::getState(); + foreach ($this->form->getConfig() as $key => $value) { + $config->$key = $value; + } + unset($config->pages[0]['submitButton']); + + return $config; + } +} diff --git a/classes/invitation/sections/Section.php b/classes/invitation/sections/Section.php new file mode 100644 index 00000000000..89fe3e96d42 --- /dev/null +++ b/classes/invitation/sections/Section.php @@ -0,0 +1,54 @@ +id = $id; + $this->name = $name; + $this->description = $description; + if (!isset($this->type)) { + throw new Exception('Decision workflow step created without specifying a type.'); + } + } + + /** + * Compile initial state data to pass to the frontend + */ + public function getState(): stdClass + { + $config = new stdClass(); + $config->id = $this->id; + $config->type = $this->type; + $config->name = $this->name; + $config->description = $this->description; + $config->errors = new stdClass(); + + return $config; + } +} diff --git a/classes/invitation/sections/Sections.php b/classes/invitation/sections/Sections.php new file mode 100644 index 00000000000..abce3d0f69b --- /dev/null +++ b/classes/invitation/sections/Sections.php @@ -0,0 +1,75 @@ +id = $id; + $this->name = $name; + $this->description = $description; + $this->sectionComponent = $sectionComponent; + $this->type = $type; + } + /** + * Add a step to the invitation + */ + public function addSection($section, $props): void + { + if(is_null($section)) { + $this->sections[] = $section; + } else { + $this->sections[$section->id] = $section; + } + $this->props = $props; + } + + /** + * get section states + */ + public function getState(): array + { + $state = []; + foreach ($this->sections as $section) { + if(is_null($section)) { + $props = [ + ...$this->props + ]; + } else { + $props = [ + ...$this->props, + $section->type => $section->getState(), + ]; + } + $state[] = [ + 'id' => $this->id, + 'name' => $this->name, + 'description' => $this->description, + 'sectionComponent' => $this->sectionComponent, + 'props' => $props, + ]; + } + return $state; + } +} diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php new file mode 100644 index 00000000000..59e7a8d1de6 --- /dev/null +++ b/classes/invitation/stepTypes/AcceptInvitationStep.php @@ -0,0 +1,212 @@ +invitationModel->userId) { + case !null: + $user = Repo::user()->get($invitation->invitationModel->userId); + if(!$user->getData('orcidAccessToken')) { + $steps[] = $this->verifyOrcidStep(); + $steps[] = $this->acceptInvitationReviewStep($context); + } + break; + default: + $steps[] = $this->verifyOrcidStep(); + $steps[] = $this->userAccountDetailsStep(); + $steps[] = $this->userDetailsStep($context); + $steps[] = $this->acceptInvitationReviewStep($context); + } + return $steps; + } + + /** + * user orcid verification step + */ + private function verifyOrcidStep(): \stdClass + { + $sections = new Sections( + 'userVerifyOrcid', + __('acceptInvitation.verifyOrcid.stepName'), + __('userInvitation.searchUser.stepDescription'), + 'popup', + 'AcceptInvitationVerifyOrcid' + ); + $sections->addSection( + null, + [ + 'validateFields' => [] + ] + ); + $step = new Step( + 'verifyOrcid', + __('acceptInvitation.verifyOrcid.stepName'), + __('acceptInvitation.verifyOrcid.stepDescription'), + __('acceptInvitation.verifyOrcid.stepLabel'), + __('userInvitation.verifyOrcid.nextButtonLabel'), + 'popup' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * user account details step + */ + private function userAccountDetailsStep(): \stdClass + { + $sections = new Sections( + 'userCreateForm', + __('acceptInvitation.accountDetails.stepName'), + __('userInvitation.accountDetails.stepDescription'), + 'form', + 'AcceptInvitationUserAccountDetails' + ); + $sections->addSection( + null, + [ + 'validateFields' => [ + 'username', + 'password', + 'privacyStatement' + ] + ] + ); + $step = new Step( + 'userCreate', + __('acceptInvitation.accountDetails.stepName'), + __('acceptInvitation.accountDetails.stepDescription'), + __('acceptInvitation.accountDetails.stepLabel'), + __('acceptInvitation.accountDetails.nextButtonLabel'), + 'form' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * user details form step + * + * @throws \Exception + */ + private function userDetailsStep(Context $context): \stdClass + { + $sections = new Sections( + 'userCreateForm', + __('acceptInvitation.accountDetails.stepName'), + __('userInvitation.accountDetails.stepDescription'), + 'form', + 'AcceptInvitationUserDetailsForms' + ); + $sections->addSection( + new Form( + 'userDetails', + __('acceptInvitation.userDetails.form.name'), + __('acceptInvitation.userDetails.form.description'), + new AcceptUserDetailsForm('accept', $this->getFormLocals($context)), + ), + [ + 'validateFields' => [ + 'affiliation', + 'givenName', + 'familyName', + 'userCountry', + ] + ] + ); + $step = new Step( + 'userDetails', + __('acceptInvitation.userDetails.stepName'), + __('acceptInvitation.userDetails.stepDescription'), + __('acceptInvitation.userDetails.stepLabel'), + __('acceptInvitation.userDetails.nextButtonLabel'), + 'form' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * review details and accept invitation step + * + * @throws \Exception + */ + private function acceptInvitationReviewStep(Context $context): \stdClass + { + $sections = new Sections( + 'userCreateRoles', + '', + '', + 'table', + 'AcceptInvitationReview' + ); + $sections->addSection( + new Form( + 'userDetails', + __('acceptInvitation.userDetails.form.name'), + __('acceptInvitation.userDetails.form.description'), + new AcceptUserDetailsForm('accept', $this->getFormLocals($context)), + ), + [ + 'validateFields' => [ + + ] + ] + ); + $step = new Step( + 'userCreateReview', + __('acceptInvitation.detailsReview.stepName'), + __('acceptInvitation.detailsReview.stepDescription'), + __('acceptInvitation.detailsReview.stepLabel'), + __('acceptInvitation.detailsReview.nextButtonLabel'), + 'review' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * @param Context $context + * @return array + */ + private function getFormLocals(Context $context): array + { + $localeNames = $context->getSupportedFormLocaleNames(); + $locales = []; + foreach ($localeNames as $key => $name) { + $locales[] = [ + 'key' => $key, + 'label' => $name, + ]; + } + return $locales; + } +} diff --git a/classes/invitation/stepTypes/InvitationStepTypes.php b/classes/invitation/stepTypes/InvitationStepTypes.php new file mode 100644 index 00000000000..6bb90f28feb --- /dev/null +++ b/classes/invitation/stepTypes/InvitationStepTypes.php @@ -0,0 +1,34 @@ +invitationSearchUser(); + } + $steps[] = $this->invitationDetailsForm($context); + $steps[] = $this->invitationInvitedEmail($context); + return $steps; + } + + /** + * create search user section + */ + private function invitationSearchUser(): stdClass + { + $sections = new Sections( + 'searchUserForm', + __('userInvitation.searchUser.stepName'), + __('userInvitation.searchUser.stepDescription'), + 'form', + 'UserInvitationSearchFormStep', + true + ); + $sections->addSection( + null, + [ + 'validateFields' => [] + ] + ); + $step = new Step( + 'searchUser', + __('userInvitation.searchUser.stepName'), + __('userInvitation.searchUser.stepDescription'), + __('userInvitation.searchUser.stepLabel'), + __('userInvitation.searchUser.nextButtonLabel'), + 'emptySection', + true + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * create user details form section + * + * @throws Exception + */ + private function invitationDetailsForm(Context $context): stdClass + { + $localeNames = $context->getSupportedFormLocaleNames(); + $locales = []; + foreach ($localeNames as $key => $name) { + $locales[] = [ + 'key' => $key, + 'label' => $name, + ]; + } + $sections = new Sections( + 'userDetails', + __('userInvitation.enterDetails.stepName'), + __('userInvitation.enterDetails.stepDescription'), + 'form', + 'UserInvitationDetailsFormStep' + ); + $sections->addSection( + new Form( + 'userDetails', + __('userInvitation.enterDetails.stepName'), + __('userInvitation.enterDetails.stepDescription'), + new UserDetailsForm('users', $locales, $context), + ), + [ + 'validateFields' => [], + 'userGroups' => $this->getAllUserGroup($context) + ] + ); + $step = new Step( + 'userDetails', + __('userInvitation.enterDetails.stepName'), + __('userInvitation.enterDetails.stepDescription'), + __('userInvitation.enterDetails.stepLabel'), + __('userInvitation.enterDetails.nextButtonLabel'), + 'form' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * create email composer for send invite + * + * @throws Exception + */ + private function invitationInvitedEmail(Context $context): stdClass + { + $sections = new Sections( + 'userInvitedEmail', + __('userInvitation.sendMail.stepLabel'), + __('userInvitation.sendMail.stepName'), + 'email', + 'UserInvitationEmailComposerStep' + ); + $fakeInvitation = $this->getFakeInvitation(); + $mailable = new UserRoleAssignmentInvitationNotify($context, $fakeInvitation); + $sections->addSection( + new Email( + 'userInvited', + __('userInvitation.sendMail.stepName'), + __('userInvitation.sendMail.stepDescription'), + [], + $mailable + ->sender(Application::get()->getRequest()->getUser()) + ->cc('') + ->bcc(''), + $context->getSupportedFormLocales(), + ), + [ + 'validateFields' => [] + ] + ); + $step = new Step( + 'userInvited', + __('userInvitation.sendMail.stepName'), + __('userInvitation.sendMail.stepDescription'), + __('userInvitation.sendMail.stepLabel'), + __('userInvitation.sendMail.nextButtonLabel'), + 'email' + ); + $step->addSectionToStep($sections->getState()); + return $step->getState(); + } + + /** + * get all user groups + */ + private function getAllUserGroup(Context $context): array + { + $allUserGroups = []; + $userGroups = Repo::userGroup()->getCollector() + ->filterByContextIds([$context->getId()]) + ->getMany(); + foreach ($userGroups as $userGroup) { + $allUserGroups[] = [ + 'value' => (int) $userGroup->getId(), + 'label' => $userGroup->getLocalizedName(), + 'disabled' => false + ]; + } + return $allUserGroups; + } +} diff --git a/classes/invitation/steps/Step.php b/classes/invitation/steps/Step.php new file mode 100644 index 00000000000..adf35516516 --- /dev/null +++ b/classes/invitation/steps/Step.php @@ -0,0 +1,73 @@ +id = $id; + $this->name = $name; + $this->description = $description; + $this->stepLabel = $stepLabel; + $this->nextButtonLabel = $nextButtonLabel; + $this->type = $type; + $this->skipInvitationUpdate = $skipInvitationUpdate; + } + + /** + * Compile initial state data to pass to the frontend + */ + public function getState(): stdClass + { + $config = new stdClass(); + $config->id = $this->id; + $config->name = $this->name; + $config->description = $this->description; + $config->nextButtonLabel = $this->nextButtonLabel; + $config->skipInvitationUpdate = $this->skipInvitationUpdate; + $config->type = $this->type; + $config->stepLabel = $this->stepLabel; + $config->sections = $this->sections; + return $config; + } + + /** + * Add a step to the workflow + */ + public function addSectionToStep($sections): void + { + $this->sections = $sections; + } +} diff --git a/js/load.js b/js/load.js index d82c54741b6..1ee1f943881 100644 --- a/js/load.js +++ b/js/load.js @@ -106,6 +106,9 @@ import FieldSlider from '@/components/Form/fields/FieldSlider.vue'; // Panel components from UI Library import ListPanel from '@/components/ListPanel/ListPanel.vue'; +// Manager components +import UserInvitationManager from '@/managers/UserInvitationManager/UserInvitationManager.vue'; + // Helper for initializing and tracking Vue controllers import VueRegistry from './classes/VueRegistry.js'; @@ -216,6 +219,9 @@ VueRegistry.registerComponent('field-pub-id', FieldPubId); // Register ListPanel VueRegistry.registerComponent('PkpListPanel', ListPanel); +// Register Invitation Manager +VueRegistry.registerComponent('UserInvitationManager', UserInvitationManager); + const pinia = createPinia(); function pkpCreateVueApp(createAppArgs) { diff --git a/locale/en/invitation.po b/locale/en/invitation.po index 853e431cbf4..10b06f59b5d 100644 --- a/locale/en/invitation.po +++ b/locale/en/invitation.po @@ -101,4 +101,310 @@ msgid "invitation.userRoleAssignment.userGroup.startDate.mustBeAfterToday" msgstr "This attribute must have a value equal or after today" msgid "invitation.validation.error.propertyProhibited" -msgstr "The :attribute field is prohibited" \ No newline at end of file +msgstr "The :attribute field is prohibited" + +msgid "invitation.step" +msgstr "STEP" + +msgid "invitation.header" +msgstr "Invitations" + +msgid "invitation.inviteToRole.btn" +msgstr "Invite to a role" + +msgid "invitation.wizard.pageTitle" +msgstr "Invite user to take a role" + +msgid "invitation.wizard.pageTitleDescription" +msgstr "You are inviting a user to take a role in OJS along with appearing in the journal masthead" + +msgid "userInvitation.enterDetailsLabel" +msgstr "Enter details" + +msgid "userInvitation.reviewAndInviteLabel" +msgstr "Review & invite for roles" + +msgid "userInvitation.searchUser.stepName" +msgstr "Search User" + +msgid "userInvitation.searchUser.stepLabel" +msgstr "{$step} - Search User" + +msgid "userInvitation.searchUser.nextButtonLabel" +msgstr "Search User" + +msgid "userInvitation.searchUser.stepDescription" +msgstr "Search for the user using their email address, username or ORCID ID. Enter at least one details to get started. If user does not exist, ypu can invite them to take up roles and be a part of your journal. If the user already exist in the system, you can view user information and invite to take a additional roles." + +msgid "userInvitation.emailField.description" +msgstr "e.g. aeinstein@example.com" + +msgid "userInvitation.usernameField.description" +msgstr "e.g. mickeymouse" + +msgid "userInvitation.orcidField.description" +msgstr "e.g. 0000-0000-0000-0000" + +msgid "userInvitation.enterDetails.stepName" +msgstr "Enter details" + +msgid "userInvitation.enterDetails.stepLabel" +msgstr "{$step} - Enter details and invite for roles" + +msgid "userInvitation.enterDetails.stepDescription" +msgstr "You can invite them to take up a role in OJS" + +msgid "userInvitation.enterDetails.nextButtonLabel" +msgstr "Save And Continue" + +msgid "invitation.role.selectRole" +msgstr "Select a new role" + +msgid "invitation.role.dateStart" +msgstr "Start Date" + +msgid "invitation.role.dateEnd" +msgstr "End Date" + +msgid "invitation.role.masthead" +msgstr "Journal Masthead" + +msgid "invitation.role.addRole.button" +msgstr "Add Another Role" + +msgid "userInvitation.roleTable.role" +msgstr "Role" + +msgid "userInvitation.roleTable.startDate" +msgstr "Start Date" + +msgid "userInvitation.roleTable.endDate" +msgstr "End Date" + +msgid "userInvitation.roleTable.journalMasthead" +msgstr "Journal Masthead" + +msgid "userInvitation.sendMail.stepName" +msgstr "Review & invite for roles" + +msgid "userInvitation.sendMail.nextButtonLabel" +msgstr "Invite user to the role" + +msgid "userInvitation.sendMail.stepDescription" +msgstr "Send the user an email to let them know about the invitation, next steps, journal GDPR polices and ORCiD verification" + +msgid "userInvitation.sendMail.stepLabel" +msgstr "{$step} - Modify email shared with the user" + +msgid "userInvitation.modal.title" +msgstr "Invitation Sent" + +msgid "userInvitation.modal.message" +msgstr "{$email} has been invited to new role in OJS.You can be updated about users on the User and Roles page, your ojs notification and/ or your email" + +msgid "userInvitation.modal.button" +msgstr "View All Users" + +msgid "invitation.role.removeRole.button" +msgstr "Remove Role" + +msgid "invitation.email.description" +msgstr "e.g. aeinstein@example.com" + +msgid "invitation.orcid.description" +msgstr "On accepting the invite, the user will be redirected to ORCID to verify their account, if they wish to." + +msgid "invitation.givenName.description" +msgstr "If you know the given name of the user, you can enter the information. However, this information can be changed by the user" + +msgid "invitation.familyName.description" +msgstr "If you know the family name of the user, you can enter the information. However, this information can be changed by the user" + +msgid "acceptInvitation.verifyOrcid.stepName" +msgstr "Verify ORCID iD" + +msgid "acceptInvitation.verifyOrcid.stepLabel" +msgstr "{$step} - Verify ORCID iD" + +msgid "acceptInvitation.verifyOrcid.stepDescription" +msgstr "You can choose to verify your ORCID iD ok skip it. If you chose to skip it now, You can verify your ORCID iD from your profile section in OJS later" + +msgid "acceptInvitation.verifyOrcid.nextButtonLabel" +msgstr "Save and continue" + +msgid "acceptInvitation.accountDetails.stepName" +msgstr "Create OJS account" + +msgid "acceptInvitation.accountDetails.stepLabel" +msgstr "{$step} - Create OJS account" + +msgid "acceptInvitation.accountDetails.stepDescription" +msgstr "To get started with OJS and accept the new role, you will need to create an account with us. For this purpose please enter a username and password." + +msgid "acceptInvitation.accountDetails.nextButtonLabel" +msgstr "Save and continue" + +msgid "acceptInvitation.userDetails.stepName" +msgstr "Enter details" + +msgid "acceptInvitation.userDetails.stepLabel" +msgstr "{$step} - Enter details" + +msgid "acceptInvitation.userDetails.stepDescription" +msgstr "Enter your details like email ID, affiliation ect. As per the GDPR compliance, this information can only modified by you. You can also choose if you want this information to be visible on your profile to the editor." + +msgid "acceptInvitation.userDetails.nextButtonLabel" +msgstr "Save and continue" + +msgid "acceptInvitation.userDetails.form.name" +msgstr "Accept invitation user details form" + +msgid "acceptInvitation.userDetails.form.description" +msgstr "Please provide the following details to help us to manage your account" + +msgid "acceptInvitation.detailsReview.stepName" +msgstr "Review & create account" + +msgid "acceptInvitation.detailsReview.stepLabel" +msgstr "{$step} - Review & create account" + +msgid "acceptInvitation.detailsReview.stepDescription" +msgstr "Review details to start your new roles in OJS" + +msgid "acceptInvitation.detailsReview.nextButtonLabel" +msgstr "Accept And Continue to OJS" + +msgid "acceptInvitation.skipVerifyOrcid" +msgstr "Skip ORCID verification" + +msgid "acceptInvitation.verifyOrcid" +msgstr "Verify ORCID iD" + +msgid "acceptInvitation.usernameField.description" +msgstr "It should be 10 characters long and could be a combination of uppercase letters, lowercase letters or numbers" + +msgid "acceptInvitation.passwordField.description" +msgstr "It should be 12 characters long and should be a combination of uppercase letters, lowercase letters, numbers and symbols" + +msgid "acceptInvitation.privacyStatement.label" +msgstr "Yes, I agree to have my data collected and stored according to the" + +msgid "acceptInvitation.privacyStatement.btn" +msgstr "Privacy Statement" + +msgid "acceptInvitation.userDetailsForm.givenName.description" +msgstr "Also known as a forename or the first name, it is tha part of a personal name that identifies a preson" + +msgid "acceptInvitation.userDetailsForm.familyName.description" +msgstr "A surname, family name, or last name is the mostly hereditary portion of one's personal name that indicates one's family" + +msgid "acceptInvitation.userDetailsForm.affiliation.description" +msgstr "This is the institute you are affiliated with" + +msgid "acceptInvitation.userDetailsForm.countryOfAffiliation.description" +msgstr "This is a country in which the institute you are affiliated with is situated" + +msgid "acceptInvitation.userDetailsForm.countryOfAffiliation.label" +msgstr "Country of affiliation" + +msgid "acceptInvitation.review.accountDetails" +msgstr "Account Details" + +msgid "acceptInvitation.review.userDetails" +msgstr "User Details" + +msgid "invitation.orcid.acceptInvitation.message" +msgstr "Not verified. You can verify your ORCID iD from your profile section in OJS" + +msgid "acceptInvitation.modal.title" +msgstr "You've been assigned a new role in OJS" + +msgid "acceptInvitation.modal.message" +msgstr "Congratulations on your new role in OJS! You might now have access to new options. If you need assistance navigating the system, please click on the “Help” buttons throughout the interface for guidance" + +msgid "acceptInvitation.modal.button" +msgstr "View All Submissions" + +msgid "invitation.tableHeader.name" +msgstr "Name" + +msgid "invitation.searchForm.emptyError" +msgstr "At least provide one search criteria." + +msgid "invitation.wizard.viewPageTitleDescription" +msgstr "You are viewing {$name}'s user details" + +msgid "invitation.reviewerAccess.validation.error.reviewAssignmentId.notExisting" +msgstr "The id {reviewAssignmentId} does not correspond to a valid review assignment" + +msgid "invitation.api.error.invitationCantBeCanceled" +msgstr "This invitation can't be cancelled" + +msgid "invitation.api.error.initialization.noUserIdAndEmailTogether" +msgstr "You cannot provide both email and userId together." + +msgid "invitation.userRoleAssignment.error.update.prohibitedForExistingUser" +msgstr "The attribute is not allowed to be access for existing users" + +msgid "invitation.userRoleAssignment.error.update.prohibitedForNonExistingUser" +msgstr "The attribute is not allowed to be access for non existing users" + +msgid "invitation.userRoleAssignment.userGroup.startDate.mustBeAfterToday" +msgstr "This attribute must have a value equal or after today" + +msgid "invitation.validation.error.propertyProhibited" +msgstr "The :attribute field is prohibited" + +msgid "invitation.cancelInvite.actionName" +msgstr "Cancel Invite" + +msgid "invitation.cancelInvite.title" +msgstr "Cancel Invitation" + +msgid "invitation.cancelInvite.message" +msgstr "Cancel the invitation sent to {$givenName} {$familyName} will deactivate acceptance link sent via email. Here are the invitation details: " + +msgid "invitation.masthead.show" +msgstr "Appear on the masthead" + +msgid "invitation.masthead.hidden" +msgstr "Does not appear on the masthead" + +msgid "invitation.role.modifyRole.button" +msgstr "Modify Role" + +msgid "invitation.management.options" +msgstr "Invitation management options" + +msgid "userInvitation.cancel.message" +msgstr "Are you sure want to cancel this invitation ?" + +msgid "userInvitation.cancel.keepWorking" +msgstr "Keep Working" + +msgid "userInvitation.status.invited" +msgstr "Invited {$date}" + +msgid "userInvitation.search.userNotFound" +msgstr "The user does not have a role in this journal" + +msgid "userInvitation.search.userFound" +msgstr "The user already exists in the journal" + +msgid "userInvitation.edit.title" +msgstr "Edit Invitation" + +msgid "userInvitation.edit.message" +msgstr "If you edit the existing invitation or add a new role, the current invitation will be canceled and, a new one will be sent. Are you sure you want to proceed?" + +msgid "validation.after_or_equal" +msgstr "Start date should be greater than or equal to today" + +msgid "invitation.removeRoles" +msgstr "User Removed From Role" + +msgid "acceptInvitation.privacyStatement.validation" +msgstr "Please confirm that you have read and agree privacy statement" + +msgid "acceptInvitation.cancel.message" +msgstr "Are you sure want to cancel accepting invitation ?" diff --git a/locale/en/user.po b/locale/en/user.po index 29721f1288b..0bd2b34d368 100644 --- a/locale/en/user.po +++ b/locale/en/user.po @@ -788,3 +788,6 @@ msgstr "Are you sure you want to remove this ORCID?" msgid "orcid.field.unverified.shouldRequest" msgstr "This ORCID has not been verified. Please remove this unverified ORCID and request verification from the user/author directly." + +msgid "user.removeRole.message" +msgstr "Are you sure want remove this role permanently ?" diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php index 9874438dee5..cdb529b7308 100644 --- a/pages/invitation/InvitationHandler.php +++ b/pages/invitation/InvitationHandler.php @@ -20,11 +20,16 @@ use APP\core\Request; use APP\facades\Repo; use APP\handler\Handler; +use APP\template\TemplateManager; +use PKP\core\PKPApplication; +use PKP\facades\Locale; use PKP\invitation\core\enums\InvitationAction; use PKP\invitation\core\Invitation; +use PKP\invitation\stepTypes\SendInvitationStep; class InvitationHandler extends Handler { + public $_isBackendPage = true; public const REPLY_PAGE = 'invitation'; public const REPLY_OP_ACCEPT = 'accept'; public const REPLY_OP_DECLINE = 'decline'; @@ -34,6 +39,7 @@ class InvitationHandler extends Handler */ public function accept(array $args, Request $request): void { + $this->setupTemplate($request); $invitation = $this->getInvitationByKey($request); $invitationHandler = $invitation->getInvitationActionRedirectController(); $invitationHandler->preRedirectActions(InvitationAction::ACCEPT); @@ -62,7 +68,17 @@ private function getInvitationByKey(Request $request): Invitation if (is_null($invitation)) { $request->getDispatcher()->handle404(); } + return $invitation; + } + + private function getInvitationById(Request $request, $id): Invitation + { + $invitation = Repo::invitation() + ->getById($id); + if (is_null($invitation)) { + $request->getDispatcher()->handle404('The link is deactivated as the invitation was cancelled'); + } return $invitation; } @@ -92,4 +108,130 @@ public static function getActionUrl(InvitationAction $action, Invitation $invita ] ); } + + public function invite($args, $request): void + { + $invitationMode = 'create'; + $invitationPayload = [ + 'userId' => null, + 'inviteeEmail' => '', + 'orcid' => '', + 'givenName' => '', + 'familyName' => '', + 'orcidValidation' => false, + 'userGroupsToAdd' => [ + [ + 'userGroupId' => null, + 'dateStart' => null, + 'dateEnd' => null, + 'masthead' => null, + ] + ], + 'currentUserGroups' => [], + 'userGroupsToRemove' => [], + 'emailComposer' => [ + 'body' => '', + 'subject' => '', + ] + ]; + $invitation = null; + $user = null; + if(!empty($args)) { + $invitation = $this->getInvitationById($request, $args[0]); + $payload = $invitation->getPayload()->toArray(); + $invitationModel = $invitation->invitationModel->toArray(); + + $invitationMode = 'edit'; + if($invitationModel['userId']){ + $user = Repo::user()->get($invitationModel['userId']); + } + $invitationPayload['userId'] = $invitationModel['userId']; + $invitationPayload['inviteeEmail'] = $invitationModel['email'] ?: $user->getEmail(); + $invitationPayload['orcid'] = $payload['orcid']; //$reviewer->getData('orcidAccessToken') + $invitationPayload['givenName'] = $user ? $user->getGivenName(null) : $payload['givenName']; + $invitationPayload['familyName'] = $user ? $user->getFamilyName(null) : $payload['familyName']; + $invitationPayload['affiliation'] = $user ? $user->getAffiliation(null) : $payload['affiliation']; + $invitationPayload['country'] = $user ? $user->getCountry() : $payload['userCountry']; + $invitationPayload['userGroupsToAdd'] = $payload['userGroupsToAdd']; + $invitationPayload['currentUserGroups'] = !$invitationModel['userId'] ? [] : $this->getUserUserGroups($invitationModel['userId']); + $invitationPayload['userGroupsToRemove'] = !$payload['userGroupsToRemove'] ? null : $payload['userGroupsToRemove']; + $invitationPayload['emailComposer'] = [ + 'emailBody'=>$payload['emailBody'], + 'emailSubject'=>$payload['emailSubject'], + ]; + } + $templateMgr = TemplateManager::getManager($request); + $breadcrumbs = $templateMgr->getTemplateVars('breadcrumbs'); + $this->setupTemplate($request); + $context = $request->getContext(); + $breadcrumbs[] = [ + 'id' => 'contexts', + 'name' => __('navigation.access'), + 'url' => $request + ->getDispatcher() + ->url( + $request, + PKPApplication::ROUTE_PAGE, + $request->getContext()->getPath(), + 'management', + 'settings', + ) + ]; + $breadcrumbs[] = [ + 'id' => 'invitationWizard', + 'name' => __('invitation.wizard.pageTitle'), + ]; + $steps = new SendInvitationStep(); + $templateMgr->setState([ + 'steps' => $steps->getSteps($invitation, $context), + 'emailTemplatesApiUrl' => $request + ->getDispatcher() + ->url( + $request, + Application::ROUTE_API, + $context->getData('urlPath'), + 'emailTemplates' + ), + 'primaryLocale' => $context->getData('primaryLocale'), + 'invitationType' => 'userRoleAssignment', + 'invitationPayload' => $invitationPayload, + 'invitationMode' => $invitationMode, + 'pageTitle' => $invitation ? + ( + $invitationPayload['givenName'][Locale::getLocale()] . ' ' + . $invitationPayload['familyName'][Locale::getLocale()]) + : __('invitation.wizard.pageTitle'), + 'pageTitleDescription' => $invitation ? + __( + 'invitation.wizard.viewPageTitleDescription', + ['name' => $invitationPayload['givenName'][Locale::getLocale()]] + ) + : __('invitation.wizard.pageTitleDescription'), + ]); + $templateMgr->assign([ + 'pageComponent' => 'PageOJS', + 'breadcrumbs' => $breadcrumbs, + 'pageWidth' => TemplateManager::PAGE_WIDTH_FULL, + ]); + $templateMgr->display('/invitation/userInvitation.tpl'); + } + + private function getUserUserGroups($id): array + { + $output = []; + $userGroups = Repo::userGroup()->userUserGroups($id); + foreach ($userGroups as $userGroup) { + $output[] = [ + 'id' => (int) $userGroup->getId(), + 'name' => $userGroup->getName(null), + 'abbrev' => $userGroup->getAbbrev(null), + 'roleId' => (int) $userGroup->getRoleId(), + 'showTitle' => (bool) $userGroup->getShowTitle(), + 'permitSelfRegistration' => (bool) $userGroup->getPermitSelfRegistration(), + 'permitMetadataEdit' => (bool) $userGroup->getPermitMetadataEdit(), + 'recommendOnly' => (bool) $userGroup->getRecommendOnly(), + ]; + } + return $output; + } } diff --git a/pages/invitation/index.php b/pages/invitation/index.php index cbe585b1269..d9d964fa01f 100644 --- a/pages/invitation/index.php +++ b/pages/invitation/index.php @@ -16,5 +16,6 @@ switch ($op) { case 'decline': case 'accept': + case 'invite': return new PKP\pages\invitation\InvitationHandler(); } diff --git a/templates/invitation/acceptInvitation.tpl b/templates/invitation/acceptInvitation.tpl new file mode 100644 index 00000000000..19e2341e217 --- /dev/null +++ b/templates/invitation/acceptInvitation.tpl @@ -0,0 +1,23 @@ + +{/block} diff --git a/templates/invitation/userInvitation.tpl b/templates/invitation/userInvitation.tpl new file mode 100644 index 00000000000..e28201ece18 --- /dev/null +++ b/templates/invitation/userInvitation.tpl @@ -0,0 +1,25 @@ +?php +{** + * templates/management/userInvitation.tpl + * + * Copyright (c) 2014-2024 Simon Fraser University + * Copyright (c) 2003-2024 John Willinsky + * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. + * + * @brief show create user invitation page to the users. + * + * @hook Template::Settings::access [] + *} +{extends file="layouts/backend.tpl"} +{block name="page"} + +{/block} diff --git a/templates/management/access.tpl b/templates/management/access.tpl index a39482b6569..0ffcc7b7cce 100644 --- a/templates/management/access.tpl +++ b/templates/management/access.tpl @@ -18,6 +18,7 @@ + {include file="management/accessUsers.tpl"} From a2cb3b221dfc4ba15227d7a20678a31ca2aa77d8 Mon Sep 17 00:00:00 2001 From: ipula Date: Thu, 24 Oct 2024 16:49:42 +0200 Subject: [PATCH 2/5] add userOrcid into validateFields --- classes/invitation/stepTypes/AcceptInvitationStep.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php index 59e7a8d1de6..15babd571d0 100644 --- a/classes/invitation/stepTypes/AcceptInvitationStep.php +++ b/classes/invitation/stepTypes/AcceptInvitationStep.php @@ -63,7 +63,7 @@ private function verifyOrcidStep(): \stdClass $sections->addSection( null, [ - 'validateFields' => [] + 'validateFields' => ['userOrcid'] ] ); $step = new Step( @@ -135,9 +135,7 @@ private function userDetailsStep(Context $context): \stdClass ), [ 'validateFields' => [ - 'affiliation', 'givenName', - 'familyName', 'userCountry', ] ] From b6a29abaa73339ef98094fd57a2c073bd0ec069f Mon Sep 17 00:00:00 2001 From: ipula Date: Thu, 24 Oct 2024 18:42:10 +0200 Subject: [PATCH 3/5] add user details step validate fields --- classes/invitation/stepTypes/AcceptInvitationStep.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php index 15babd571d0..5a6ec1874e9 100644 --- a/classes/invitation/stepTypes/AcceptInvitationStep.php +++ b/classes/invitation/stepTypes/AcceptInvitationStep.php @@ -135,7 +135,9 @@ private function userDetailsStep(Context $context): \stdClass ), [ 'validateFields' => [ + 'affiliation', 'givenName', + 'familyName', 'userCountry', ] ] From 8beae7b9fa42d300fe0f6aa8f287e6f1668ece97 Mon Sep 17 00:00:00 2001 From: ipula Date: Mon, 28 Oct 2024 16:16:48 +0100 Subject: [PATCH 4/5] add user object into steps --- .../handlers/UserRoleAssignmentInviteRedirectController.php | 5 ++++- classes/invitation/stepTypes/AcceptInvitationStep.php | 6 +++--- classes/invitation/stepTypes/InvitationStepTypes.php | 3 ++- classes/invitation/stepTypes/SendInvitationStep.php | 5 +++-- pages/invitation/InvitationHandler.php | 2 +- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php index 07b923a5868..486af2de884 100644 --- a/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php +++ b/classes/invitation/invitations/userRoleAssignment/handlers/UserRoleAssignmentInviteRedirectController.php @@ -21,6 +21,7 @@ use PKP\invitation\core\InvitationActionRedirectController; use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite; use PKP\invitation\stepTypes\AcceptInvitationStep; +use APP\facades\Repo; class UserRoleAssignmentInviteRedirectController extends InvitationActionRedirectController { @@ -35,8 +36,10 @@ public function acceptHandle(Request $request): void $templateMgr->assign('invitation', $this->invitation); $context = $request->getContext(); $steps = new AcceptInvitationStep(); + $invitationModel = $this->invitation->invitationModel->toArray(); + $user = $invitationModel['userId'] ?Repo::user()->get($invitationModel['userId']) : null; $templateMgr->setState([ - 'steps' => $steps->getSteps($this->invitation, $context), + 'steps' => $steps->getSteps($this->invitation, $context,$user), 'primaryLocale' => $context->getData('primaryLocale'), 'pageTitle' => __('invitation.wizard.pageTitle'), 'invitationId' => (int)$request->getUserVar('id') ?: null, diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php index 5a6ec1874e9..8b6f9bf691f 100644 --- a/classes/invitation/stepTypes/AcceptInvitationStep.php +++ b/classes/invitation/stepTypes/AcceptInvitationStep.php @@ -19,6 +19,7 @@ use PKP\invitation\sections\Form; use PKP\invitation\sections\Sections; use PKP\invitation\steps\Step; +use PKP\user\User; class AcceptInvitationStep extends InvitationStepTypes { @@ -27,13 +28,12 @@ class AcceptInvitationStep extends InvitationStepTypes * * @throws \Exception */ - public function getSteps(?Invitation $invitation, Context $context): array + public function getSteps(?Invitation $invitation, Context $context, ?User $user): array { $steps = []; - switch ($invitation->invitationModel->userId) { + switch ($user) { case !null: - $user = Repo::user()->get($invitation->invitationModel->userId); if(!$user->getData('orcidAccessToken')) { $steps[] = $this->verifyOrcidStep(); $steps[] = $this->acceptInvitationReviewStep($context); diff --git a/classes/invitation/stepTypes/InvitationStepTypes.php b/classes/invitation/stepTypes/InvitationStepTypes.php index 6bb90f28feb..31125e49408 100644 --- a/classes/invitation/stepTypes/InvitationStepTypes.php +++ b/classes/invitation/stepTypes/InvitationStepTypes.php @@ -15,6 +15,7 @@ use PKP\context\Context; use PKP\invitation\core\Invitation; use PKP\invitation\invitations\userRoleAssignment\UserRoleAssignmentInvite; +use PKP\user\User; abstract class InvitationStepTypes { @@ -22,7 +23,7 @@ abstract class InvitationStepTypes * Get the invitation steps * use of the built-in UI for making the invitation */ - abstract public function getSteps(?Invitation $invitation, Context $context); + abstract public function getSteps(?Invitation $invitation, Context $context, ?User $user): array; /** fake invitation for email template */ diff --git a/classes/invitation/stepTypes/SendInvitationStep.php b/classes/invitation/stepTypes/SendInvitationStep.php index 99f67ccf91b..898884dd6b2 100644 --- a/classes/invitation/stepTypes/SendInvitationStep.php +++ b/classes/invitation/stepTypes/SendInvitationStep.php @@ -23,6 +23,7 @@ use PKP\invitation\sections\Sections; use PKP\invitation\steps\Step; use PKP\mail\mailables\UserRoleAssignmentInvitationNotify; +use PKP\user\User; use stdClass; class SendInvitationStep extends InvitationStepTypes @@ -32,10 +33,10 @@ class SendInvitationStep extends InvitationStepTypes * * @throws Exception */ - public function getSteps(?Invitation $invitation, Context $context): array + public function getSteps(?Invitation $invitation, Context $context,?User $user): array { $steps = []; - if(!$invitation) { + if(!$invitation && !$user) { $steps[] = $this->invitationSearchUser(); } $steps[] = $this->invitationDetailsForm($context); diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php index cdb529b7308..1f474896e4e 100644 --- a/pages/invitation/InvitationHandler.php +++ b/pages/invitation/InvitationHandler.php @@ -183,7 +183,7 @@ public function invite($args, $request): void ]; $steps = new SendInvitationStep(); $templateMgr->setState([ - 'steps' => $steps->getSteps($invitation, $context), + 'steps' => $steps->getSteps($invitation, $context,$user), 'emailTemplatesApiUrl' => $request ->getDispatcher() ->url( From 23ceacbe74f254e667f982dd399d6d6f12ef19f3 Mon Sep 17 00:00:00 2001 From: ipula Date: Mon, 28 Oct 2024 16:41:06 +0100 Subject: [PATCH 5/5] add comments to functions --- .../invitation/stepTypes/AcceptInvitationStep.php | 1 + pages/invitation/InvitationHandler.php | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/classes/invitation/stepTypes/AcceptInvitationStep.php b/classes/invitation/stepTypes/AcceptInvitationStep.php index 8b6f9bf691f..d5a4813c0b4 100644 --- a/classes/invitation/stepTypes/AcceptInvitationStep.php +++ b/classes/invitation/stepTypes/AcceptInvitationStep.php @@ -194,6 +194,7 @@ private function acceptInvitationReviewStep(Context $context): \stdClass } /** + * Get all form locals * @param Context $context * @return array */ diff --git a/pages/invitation/InvitationHandler.php b/pages/invitation/InvitationHandler.php index 1f474896e4e..31c5431bf68 100644 --- a/pages/invitation/InvitationHandler.php +++ b/pages/invitation/InvitationHandler.php @@ -109,6 +109,13 @@ public static function getActionUrl(InvitationAction $action, Invitation $invita ); } + /** + * Create an invitation to accept new role + * @param $args + * @param $request + * @return void + * @throws \Exception + */ public function invite($args, $request): void { $invitationMode = 'create'; @@ -216,6 +223,11 @@ public function invite($args, $request): void $templateMgr->display('/invitation/userInvitation.tpl'); } + /** + * Get current user user groups + * @param $id + * @return array + */ private function getUserUserGroups($id): array { $output = [];