Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions app/Controller/CoInvitesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -371,13 +371,7 @@ protected function process_invite($inviteid, $confirm, $loginIdentifier=null) {
// supported enrollment flow involves a new Org Identity for the CO, so
// there won't be an existing CO Person identity linked to use instead.
// At some point (ie: additional Role enrollment; CO-310) this will change.

$token = Security::generateAuthKey();

$this->CoInvite->CoPetition->id = $invite['CoPetition']['id'];
$this->CoInvite->CoPetition->saveField('enrollee_token', $token);

$redirect['token'] = $token;
$redirect['token'] = $this->CoInvite->CoPetition->ensureEnrolleeToken($invite['CoPetition']['id']);

$this->redirect($redirect);
} elseif(!empty($invite['CoInvite']['email_address_id'])) {
Expand Down
46 changes: 32 additions & 14 deletions app/Controller/CoPetitionsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1729,31 +1729,49 @@ protected function execute_sendApproverNotification($id) {
*/

protected function execute_sendConfirmation($id) {
$this->CoPetition->sendConfirmation($id, $this->Session->read('Auth.User.co_person_id'));

$ea = $this->CoPetition->needConfirmation($id);
if(!empty($ea)) {

$this->CoPetition->sendConfirmation($id, $ea, $this->Session->read('Auth.User.co_person_id'));

$this->CoPetition->updateStatus($id,
$this->CoPetition->updateStatus($id,
PetitionStatusEnum::PendingConfirmation,
$this->Session->read('Auth.User.co_person_id'));

// The step is done
// The step is done

$debug = Configure::read('debug');
$debug = Configure::read('debug');

if(!$debug) {
$this->redirect($this->generateDoneRedirect('sendConfirmation', $id));
} else {
// We need to populate the view var to render the debug link
$coInviteId = $this->CoPetition->field('co_invite_id',
if(!$debug) {
$this->redirect($this->generateDoneRedirect('sendConfirmation', $id));
} else {
// We need to populate the view var to render the debug link
$coInviteId = $this->CoPetition->field('co_invite_id',
array('CoPetition.id' => $id));

if($coInviteId) {
$args = array();
$args['conditions']['CoInvite.id'] = $coInviteId;
$args['contain'] = false;
if($coInviteId) {
$args = array();
$args['conditions']['CoInvite.id'] = $coInviteId;
$args['contain'] = false;

$this->set('vv_co_invite', $this->CoPetition->CoInvite->find('first', $args));
$this->set('vv_co_invite', $this->CoPetition->CoInvite->find('first', $args));
}
}
}
else {

// there are no unconfirmed addresses left, directly proceed to processConfirmation
$coPersonId = $this->CoPetition->field('enrollee_co_person_id', array('CoPetition.id' => $id));
$this->CoPetition->updateStatus($id, PetitionStatusEnum::Confirmed, $coPersonId);

$redirect = $this->generateDoneRedirect('processConfirmation', $id);

// we need to switch from PetitionerToken to EnrolleeToken, which is normally done in the
// process of sending an invite and confirming it
$redirect['token'] = $this->CoPetition->ensureEnrolleeToken($id);
$this->redirect($redirect);
}
}

/**
Expand Down
73 changes: 15 additions & 58 deletions app/Model/CoInvite.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public function processReply($inviteId, $confirm, $loginIdentifier=null) {
// Check invite validity

if(time() < strtotime($invite['CoInvite']['expires'])) {
if($verifyEmail) {
if($verifyEmail && $confirm) {
// Verifying an email address

try {
Expand All @@ -121,12 +121,9 @@ public function processReply($inviteId, $confirm, $loginIdentifier=null) {
$dbc->rollback();
throw new RuntimeException($e->getMessage());
}
} elseif(isset($invite['CoPetition']['id'])) {
// Before we can delete the invitation, we need to unlink it from the petition

$this->CoPetition->id = $invite['CoPetition']['id'];
$this->CoPetition->saveField('co_invite_id', null);
} else {
}

if(!isset($invite['CoPetition']['id'])) {
// Default (ie: non-enrollment flow) behavior: update CO Person

$this->CoPerson->id = $invite['CoPerson']['id'];
Expand All @@ -137,58 +134,7 @@ public function processReply($inviteId, $confirm, $loginIdentifier=null) {
}
}

// Mark the email address associated with this invite as verified.

if($confirm) {
// We're actually verifying an org identity email address even though we're
// getting to the EmailAddress object via CoPerson

$orgId = null;

if(isset($invite['CoPetition']['enrollee_org_identity_id'])) {
$orgId = $invite['CoPetition']['enrollee_org_identity_id'];
} elseif(empty($invite['CoPetition'])) {
// Try to find the org identity associated with this invite

$args = array();
$args['conditions']['CoOrgIdentityLink.co_person_id'] = $invite['CoPerson']['co_person_id'];
$args['conditions']['EmailAddress.mail'] = $invite['CoInvite']['mail'];
$args['joins'][0]['table'] = 'cm_email_addresses';
$args['joins'][0]['alias'] = 'EmailAddress';
$args['joins'][0]['type'] = 'INNER';
$args['joins'][0]['conditions'][0] = 'CoOrgIdentityLink.org_identity_id=EmailAddress.org_identity_id';
$args['contain'] = false;

// This *should* generate one result...
$link = $this->CoPerson->CoOrgIdentityLink->find('first', $args);

if(!empty($link['CoOrgIdentityLink']['org_identity_id'])) {
$orgId = $link['CoOrgIdentityLink']['org_identity_id'];
}
}

if($orgId) {
try {
$this->CoPerson->EmailAddress->verify($orgId, null, $invite['CoInvite']['mail'], $invite['CoPetition']['enrollee_co_person_id']);
}
catch(Exception $e) {
$dbc->rollback();
throw new RuntimeException($e->getMessage());
}
}
}

// Toss the invite
$this->delete($invite['CoInvite']['id']);
} else {
if(!empty($invite['CoPetition']['id'])) {
// Before we can delete the invitation, we need to unlink it from the petition

$this->CoPetition->id = $invite['CoPetition']['id'];
$this->CoPetition->saveField('co_invite_id', null);
}

$this->delete($invite['CoInvite']['id']);

// Record a history record that the invitation expired
try {
Expand All @@ -209,6 +155,17 @@ public function processReply($inviteId, $confirm, $loginIdentifier=null) {
throw new OutOfBoundsException(_txt('er.inv.exp'));
}

if(!empty($invite['CoPetition']['id'])) {

// Before we can delete the invitation, we need to unlink it from the petition

$this->CoPetition->id = $invite['CoPetition']['id'];
$this->CoPetition->saveField('co_invite_id', null);
}

// Toss the invite
$this->delete($invite['CoInvite']['id']);

// Create a history record

if($verifyEmail) {
Expand Down
113 changes: 89 additions & 24 deletions app/Model/CoPetition.php
Original file line number Diff line number Diff line change
Expand Up @@ -2264,6 +2264,62 @@ public function sendApproverNotification($id, $actorCoPersonId) {
return true;
}

/**
* Checks for associated email address to find an 'unverified' one
*
* @since COmanage Registry vTODO
* @param Integer CO Petition ID
* @throws InvalidArgumentException
* @return EmailAddress address to be verified, if there are any available
* null if no associated unverified addresses are available
*
* Associated in this context means: directly associated with the Enrollee.
* We check the EmailAddress belonging to the Enrollee OI and COPerson.
* We do not check for linked addresses in any of the OrgIdentityLink records
* at this point
*/
public function needConfirmation($id) {

$args = array();
$args['conditions']['CoPetition.id'] = $id;
$args['contain']['EnrolleeCoPerson']= array('EmailAddress');
$args['contain']['EnrolleeOrgIdentity'] = array('EmailAddress', 'PrimaryName');

$pt = $this->find('first', $args);

if(empty($pt)) {
throw new InvalidArgumentException(_txt('er.notfound', array(_txt('ct.co_petitions.1'), $id)));
}
else {
// check all email addresses and see if any of those are unverified
if(!empty($pt['EnrolleeOrgIdentity']['EmailAddress'])) {
foreach($pt['EnrolleeOrgIdentity']['EmailAddress'] as $em) {
if(!$em['verified']) {
return $em;
}
}
}
else {
throw new RuntimeException(_txt('er.orgp.nomail',
array(generateCn($pt['EnrolleeOrgIdentity']['PrimaryName']),
$pt['EnrolleeOrgIdentity']['id'])));
}

// check all CoPerson related email addresses
if(!empty($pt['EnrolleeCoPerson']['EmailAddress'])) {
foreach($pt['EnrolleeCoPerson']['EmailAddress'] as $em) {
if(!$em['verified']) {
return $em;
}
}
}
}

// return null to indicate we did not find any unverified email addresses

return null;
}

/**
* Send a confirmation (invite) for a Petition.
* - postcondition: Invite sent
Expand All @@ -2275,42 +2331,22 @@ public function sendApproverNotification($id, $actorCoPersonId) {
* @return String Address the invitation was sent to
*/

public function sendConfirmation($id, $actorCoPersonId) {
public function sendConfirmation($id, $ea, $actorCoPersonId) {
// Just let any exceptions fall through

$args = array();
$args['conditions']['CoPetition.id'] = $id;
$args['contain']['EnrolleeCoPerson'][] = 'PrimaryName';
$args['contain']['EnrolleeCoPerson']['CoPersonRole'][] = 'Cou';
$args['contain']['EnrolleeCoPerson']['CoPersonRole']['SponsorCoPerson'][] = 'PrimaryName';
$args['contain']['EnrolleeOrgIdentity'] = array('EmailAddress', 'PrimaryName');
$args['contain']['EnrolleeOrgIdentity'] = array('PrimaryName');

$pt = $this->find('first', $args);

if(empty($pt)) {
throw new InvalidArgumentException(_txt('er.notfound', array(_txt('ct.co_petitions.1'), $id)));
}

if(empty($pt['EnrolleeOrgIdentity']['EmailAddress'])) {
throw new RuntimeException(_txt('er.orgp.nomail',
array(generateCn($pt['EnrolleeOrgIdentity']['PrimaryName']),
$pt['EnrolleeOrgIdentity']['id'])));
}

$toEmail = null;

// Which email do we pick? Ultimately we could look at type and/or verified,
// but for now we'll just pick the first one. sendApprovalNotification does similar.
// Note array_shift will muck with $pt, but we don't need it anymore.

$ea = array_shift($pt['EnrolleeOrgIdentity']['EmailAddress']);

if(empty($ea['mail'])) {
throw new RuntimeException(_txt('er.orgp.nomail',
array(generateCn($pt['EnrolleeOrgIdentity']['PrimaryName']),
$pt['EnrolleeOrgIdentity']['id'])));
}

$toEmail = $ea['mail'];

// Now we need some info from the enrollment flow
Expand Down Expand Up @@ -2369,7 +2405,7 @@ public function sendConfirmation($id, $actorCoPersonId) {
$ef['Co']['name'],
$subject,
$body,
null,
$ea['id'],
$ef['CoEnrollmentFlow']['invitation_validity'],
$cc,
$bcc,
Expand Down Expand Up @@ -3217,4 +3253,33 @@ private function validateRelated($primaryModel, $requestData, $validatedData, $e
return $ret;
}
}

/**
* Ensure an enrollee token exists
*
* @since COmanage Registry vTODO
* @param id CoPetition model id
*/

public function ensureEnrolleeToken($id) {
$args=array();
$args['conditions']['CoPetition.id']=$id;
$model = $this->find('first', $args);

$token=null;
// if model is empty, disregard the request instead of throwing exceptions
if(!empty($model) && !empty($model['CoPetition'])) {
if(empty($model['CoPetition']['enrollee_token'])) {

$token = Security::generateAuthKey();
$this->id = $id;
$this->saveField('enrollee_token', $token);
}
else {
$token = $model['CoPetition']['enrollee_token'];
}
}

return $token;
}
}