Skip to content

Issues-449 #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 1, 2021
Merged
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
66 changes: 59 additions & 7 deletions controllers/class.groupcontroller.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
* Group controller
*/

use Garden\Schema\Validation;
use Garden\Schema\ValidationException;
use Garden\Web\Exception\ClientException;
use Vanilla\Message;
use Cocur\Slugify\Slugify;


/**
* Handles accessing & displaying a single group via /group endpoint.
*/
Expand Down Expand Up @@ -405,9 +409,27 @@ public function invite($GroupID) {
if(GroupModel::isMemberOfGroup($user->UserID, $GroupID)) {
$this->Form->addError('User is a member of "'.$Group->Name.'".');
} else {
$this->GroupModel->invite($GroupID, $user->UserID);
$this->informMessage('Invitation was sent.');
$this->render('invitation_sent');
$groupInvitation['GroupID'] = $GroupID;
$groupInvitation['InviteeUserID'] = $user->UserID;
$groupInvitationModel = new GroupInvitationModel();
$result = $groupInvitationModel->save($groupInvitation);
if($result) {
$this->informMessage('Invitation was sent.');
} else {
$validationErrors = $groupInvitationModel->validationResults();
$validation = new Validation();
foreach ($validationErrors as $field => $errors) {
foreach ($errors as $error) {
$validation->addError(
$field,
$error
);
}
}
$this->Form->addError($validation->getMessage());
$this->render();
}

}
} catch (\Exception $e) {
$this->Form->addError('Error' . $e->getMessage());
Expand Down Expand Up @@ -535,11 +557,41 @@ public function unwatch($GroupID) {
* @param $UserID
* @throws Gdn_UserException
*/
public function accept($GroupID, $UserID) {
if(!GroupModel::isMemberOfGroup($UserID, $GroupID) ) {
$this->GroupModel->accept($GroupID, $UserID);
public function accept($token ='') {

if (!Gdn::session()->isValid()) {
redirectTo(signInUrl());
}
redirectTo(GroupsPlugin::GROUP_ROUTE.$GroupID);

$groupInvitationModel = new GroupInvitationModel();

$result = $groupInvitationModel->validateToken($token);
$validationErrors = $groupInvitationModel->Validation->results();
if (count($validationErrors) > 0) {
$validation = new Validation();
foreach ($validationErrors as $field => $errors) {
foreach ($errors as $error) {
$validation->addError(
$field,
$error
);
}
}
if ($validation->getErrorCount() > 0) {
$this->setData('ErrorMessage', $validation->getMessage());
$this->render();
}
} else {
if(!GroupModel::isMemberOfGroup($result['InviteeUserID'], $result['GroupID']) ) {
$GroupModel = new GroupModel();
$GroupModel->join($result['GroupID'],$result['InviteeUserID']);
}
$result['Status'] = 'accepted';
$result['DateAccepted'] = Gdn_Format::toDateTime();
$groupInvitationModel->save($result);
redirectTo(GroupsPlugin::GROUP_ROUTE.$result['GroupID']);
}

}


Expand Down
211 changes: 211 additions & 0 deletions models/class.groupinvitationmodel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<?php
/**
* Group Invitation model.
*/

/**
* Handles group invitation data.
*/
class GroupInvitationModel extends Gdn_Model {

/**
* Class constructor. Defines the related database table name.
*/
public function __construct() {
parent::__construct('GroupInvitation');
}

/**
*
*
* @param $groupInvitationID
* @return array|bool|stdClass
*/
public function getByGroupInvitationID($groupInvitationID) {
$dataSet = $this->SQL->from('GroupInvitation gi')
->join('Group g', 'gi.GroupID = g.GroupID')
->join('User ibyu', 'gi.InvitedByUserID = ibyu.UserID')
->join('User iu', 'gi.InviteeUserID = iu.UserID', 'left')
->select('gi.*')
->select('g.Name', '','GroupName')
->select('iu.UserID', '', 'InviteeUserID')
->select('iu.Email', '', 'InviteeEmail')
->select('iu.Name', '', 'InviteeName')
->select('ibyu.UserID', '', 'InvitedByUserID')
->select('ibyu.Email', '', 'InvitedByEmail')
->select('ibyu.Name', '', 'InvitedByName')
->where('gi.GroupInvitationID', $groupInvitationID)
->get();
return $dataSet->firstRow();
}


private function generateToken(){
$strongResult = true;
// Returns the generated string of bytes on success, or false on failure
$randomString = openssl_random_pseudo_bytes(16, $strongResult);
if($randomString === false) {
throw new Exception('Couldn\'t generate a random string');
}

return bin2hex($randomString);
}

/**
*
*
* @param array $formPostValues
* @param array|bool $settings
* @throws Exception
* @return bool|array
*/
public function save($formPostValues, $settings = false) {
$sendEmail = val('SendEmail', $settings, true);
$returnRow = val('ReturnRow', $settings, false);
$insert = $formPostValues['GroupInvitationID'] > 0? false: true;

// Define the primary key in this model's table.
$this->defineSchema();

if($insert) {
$formPostValues['InvitedByUserID'] = Gdn::session()->UserID;
$formPostValues['Token'] = self::generateToken();

$expires = strtotime(c('Plugins.Groups.InviteExpiration', '+1 day'));
$formPostValues['DateExpires'] = Gdn_Format::toDateTime($expires);
$formPostValues['Status'] = 'pending';
// Make sure required db fields are present.
$this->addInsertFields($formPostValues);
} else {
$this->addUpdateFields($formPostValues);
}

if(!$insert) {
$invitationID = $this->update(['Status' => $formPostValues['Status'], 'DateAccepted' => $formPostValues['DateAccepted']], ['GroupInvitationID' => $formPostValues['GroupInvitationID']] );
return $invitationID;
}

// Validate the form posted values
if ($this->validate($formPostValues, $insert) === true) {
$groupModel = new GroupModel();
// Make sure this user has permissions
$hasPermission = $groupModel->canInviteNewMember($formPostValues['GroupID']);
if (!$hasPermission) {
$this->Validation->addValidationResult('GroupID', 'You do not have permissions to invite new members.');
return false;
}

$now = Gdn_Format::toDateTime();
$testData = $this->getWhere(['InviteeUserID' => $formPostValues['InviteeUserID'], 'GroupID' => $formPostValues['GroupID'],
'Status' => 'pending', 'DateExpires >=' => $now])->result(DATASET_TYPE_ARRAY);
if (count($testData)> 0) {
// Check status
$this->Validation->addValidationResult('InviteeUserID', 'An invitation has already been sent to this user.');
return false;
}

// Call the base model for saving
$invitationID = parent::save($formPostValues);

// And send the invitation email
if ($sendEmail) {
try {
$this->send($invitationID);
} catch (Exception $ex) {
$this->Validation->addValidationResult('Email', sprintf(t('Although the group invitation was created successfully, the email failed to send. The server reported the following error: %s'), strip_tags($ex->getMessage())));
return false;
}
}

if ($returnRow) {
return (array)$this->getByGroupInvitationID($invitationID);
} else {
return true;
}
}
return false;
}



/**
* Send Group Invitation by Email
*
* @param $groupInvitationID
* @throws Exception
*/
public function send($groupInvitationID) {
$invitation = $this->getByGroupInvitationID($groupInvitationID);
$email = new Gdn_Email();
$email->subject($invitation->InvitedByName.' invited you to '.$invitation->GroupName);
$email->to($invitation->InviteeEmail);
$greeting = 'Hello!';
$message = $greeting.'<br/>'.
'You can accept or decline this invitation.';

$emailTemplate = $email->getEmailTemplate()
->setTitle($invitation->InvitedByName.' invited you to '.$invitation->GroupName)
->setMessage($message)
->setButton(externalUrl('/group/accept/'.$invitation->Token), 'Accept' );
$email->setEmailTemplate($emailTemplate);

try {
$email->send();
} catch (Exception $e) {
if (debug()) {
throw $e;
}
}
}

/**
* Validate token
* @param $token
* @param bool $returnData
* @return array|bool|stdClass
*/
public function validateToken($token, $returnData = true){
if(empty($token)){
$this->Validation->addValidationResult('Token', 'Invalid token');
return false;
}
$userID = Gdn::session()->UserID;
// One row only, token is unique
$testData = $this->getWhere(['Token' => $token])->firstRow(DATASET_TYPE_ARRAY);
if ($testData) {
if($testData['InviteeUserID'] != $userID) {
$this->Validation->addValidationResult('Token', 'Invalid token');
return false;
}
$now = Gdn_Format::toDateTime();
if($now > $testData['DateExpires']) {
$this->Validation->addValidationResult('Token', 'Your token has expired.');
return false;
}

if($returnData) {
return $testData;
} else {
return true;
}

} else {
$this->Validation->addValidationResult('Token', 'Invalid token.');
}
return false;
}

/**
* {@inheritdoc}
*/
public function delete($where = [], $options = []) {
throw new Exception("Not supported");
}

/**
* {@inheritdoc}
*/
public function deleteID($id, $options = []) {
throw new Exception("Not supported");
}
}
59 changes: 4 additions & 55 deletions models/class.groupmodel.php
Original file line number Diff line number Diff line change
Expand Up @@ -861,27 +861,6 @@ public function join($GroupID, $UserID, $watched = true, $followed = true ){
$discussionModel = new DiscussionModel();
$discussionModel->updateUserDiscussionCount($UserID, false);
}

/**
* Invite a new member
* @param $GroupID
* @param $UserID
* @return bool|Gdn_DataSet|object|string
*/
public function invite($GroupID, $UserID){
$this->sendInviteEmail($GroupID, $UserID);
}

/**
* Accept an invitation
* @param $GroupID
* @param $UserID
* @return bool|Gdn_DataSet|object|string
*/
public function accept($groupID, $userID){
$this->join($groupID, $userID);
}

/**
* Return true if user is a member of the group
* @param $userID
Expand Down Expand Up @@ -1503,6 +1482,10 @@ public function canManageMembers($group) {
*
*/
public function canInviteNewMember($group) {
if(is_numeric($group) && $group > 0) {
$group = $this->getByGroupID($group);
}

if((int)$group->Archived === 1) {
return false;
}
Expand Down Expand Up @@ -1753,40 +1736,6 @@ public function canDeleteDiscussion($discussion) {
return false;
}

/**
* Send invite email.
*
* @param int $userID
* @param string $password
*/
public function sendInviteEmail($GroupID, $userID) {
$Group = $this->getByGroupID($GroupID);
$session = Gdn::session();
$sender = Gdn::userModel()->getID($session->UserID);
$user = Gdn::userModel()->getID($userID);
$email = new Gdn_Email();
$email->subject($sender->Name.' invited you to '.$Group->Name);
$email->to($user->Email);
$greeting = 'Hello!';
$message = $greeting.'<br/>'.
'You can accept or decline this invitation.';

$emailTemplate = $email->getEmailTemplate()
->setTitle($sender->Name.' invited you to '.$Group->Name)
->setMessage($message)
->setButton(externalUrl('/group/accept/'.$Group->GroupID.'/'.$userID), 'Accept' );

$email->setEmailTemplate($emailTemplate);

try {
$email->send();
} catch (Exception $e) {
if (debug()) {
throw $e;
}
}
}

public function notifyNewGroup($groupID, $groupName) {
$activityModel = Gdn::getContainer()->get(ActivityModel::class);
$data = [
Expand Down
Loading