Skip to content
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

Fix email issues #171

Merged
merged 28 commits into from Oct 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a8b6022
Enrich and personalise the role request emails.
DeckChairs Jul 16, 2019
e1ef4cd
Factor out preparation and sending of email to a seperate function
jrha Aug 15, 2019
08b7a7a
Remove commented out code cruft
jrha Aug 15, 2019
3ee8160
Remove if statement from NotificationService call
gregcorbett Oct 1, 2021
a262b85
Pass newRole and user to initial call to roleRequest
jrha Aug 15, 2019
e69c8bb
Actually pass approving user to send_email
jrha Aug 15, 2019
6db804d
Factor out getting of web PortalURL to a private function
jrha Aug 15, 2019
3382f89
Add private mock mail function for debugging
jrha Aug 15, 2019
4462025
Read send_email from config file and act appropriately
jrha Aug 15, 2019
f2f02ac
Move headers next to where it is used
jrha Aug 15, 2019
3c9bbd9
Remove redundant code paths
jrha Aug 15, 2019
d755b31
Don't create single-use local variable for entity name
jrha Aug 15, 2019
7df9d51
Fix from header and set email address to admin list
jrha Aug 26, 2020
b156c28
Handle case where no user has a role over entity
gregcorbett Sep 30, 2021
9b8b9f2
Use the role requested object to populate email
gregcorbett Sep 30, 2021
443211e
Always recurse roleRequest when project role needed
gregcorbett Sep 30, 2021
845a027
Move enablingRoles initialisation closer to use
gregcorbett Sep 30, 2021
0deddb5
Use the Factory to access local config
gregcorbett Aug 26, 2021
eb54ec4
Remove un-needed code.
gregcorbett Sep 30, 2021
c49b00c
Check array is empty rather than null
gregcorbett Sep 30, 2021
6efb29b
Simplify determination of users with GRANT_ROLE
gregcorbett Sep 30, 2021
eac6b74
Improve comments around recursion
gregcorbett Sep 30, 2021
34bf0a8
Use camelCase throughout
gregcorbett Sep 30, 2021
569fcde
Factor out email sending into its own service
gregcorbett Sep 30, 2021
1e0ad98
Update documentation of NotificationService class
gregcorbett Sep 30, 2021
82abbed
Capitalise "GocDB" in lib/Gocdb_Services/NotificationService.php
gregcorbett Sep 30, 2021
6f6d342
Add requesting User's surname to emails
gregcorbett Oct 1, 2021
1dce398
Remove unneeded check for emptiness
gregcorbett Oct 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -95,9 +95,7 @@ function submitRoleRequest($roleName, $entityId, \User $user =null) {
// perfoms role validation and throws exceptios accordingly.
$newRole = \Factory::getRoleService()->addRole($roleName, $user, $entity);

if(\Factory::getConfigService()->getSendEmails()){
\Factory::getNotificationService()->roleRequest($entity);
}
\Factory::getNotificationService()->roleRequest($newRole, $user, $entity);

show_view('political_role/new_request.php');
}
47 changes: 47 additions & 0 deletions lib/Gocdb_Services/EmailService.php
@@ -0,0 +1,47 @@
<?php

namespace org\gocdb\services;

require_once __DIR__ . '/AbstractEntityService.php';
require_once __DIR__ . '/Factory.php';

/**

*/
class EmailService extends AbstractEntityService {
/**
* Depending on the configuration, either send an email or print what would
* have been sent.
* @param string $emailAddress A single email address to send to
* @param string $subject The subject of the email
* @param string $body The body of the email
* @param string $headers The headers of the email

*/
public function send($emailAddress, $subject, $body, $headers) {
if ($this->getConfigSendEmail()) {
mail($emailAddress, $subject, $body, $headers);
} else {
$this->mockMail($emailAddress, $subject, $body, $headers);
}
}

/**
* Return whether send_email is enabled in the config file
*/
private function getConfigSendEmail() {
return \Factory::getConfigService()->getSendEmails();
}

private function mockMail($to, $subject, $message, $additionalHeaders = "", $additionalParameters = "") {
echo "<!--\n";
echo "Sending mail disabled, but would have sent:\n";
echo "$additionalHeaders\n";
echo "To: $to\n";
echo "Subject: $subject\n";
echo "\n$message\n";
echo "\nAdditional Parameters: $additionalParameters\n";
echo "-->\n";
return True;
}
}
14 changes: 14 additions & 0 deletions lib/Gocdb_Services/Factory.php
Expand Up @@ -48,6 +48,7 @@ class Factory {
private static $OwnedEntityService = null;
private static $exService = null;
private static $notificationService = null;
private static $emailService = null;

public static $properties = array();
//private static $properties = null;
Expand Down Expand Up @@ -385,6 +386,19 @@ public static function getNotificationService() {
}
return self::$notificationService;
}

/**
* Singleton EmailService
* @return org\gocdb\services\EmailService
*/
public static function getEmailService() {
if (self::$emailService == null) {
require_once __DIR__ . '/EmailService.php';
self::$emailService = new org\gocdb\services\EmailService();
self::$emailService->setEntityManager(self::getEntityManager());
}
return self::$emailService;
}
}

?>
149 changes: 71 additions & 78 deletions lib/Gocdb_Services/NotificationService.php
Expand Up @@ -6,6 +6,7 @@
*/
require_once __DIR__ . '/AbstractEntityService.php';
require_once __DIR__ . '/Factory.php';
require_once __DIR__ . '/User.php';

/**
* A service layer to aid the sending of notification emails
Expand All @@ -25,65 +26,40 @@ class NotificationService extends AbstractEntityService {
* send an email to those users to approve. It does this by passing the parent entity back into this method recursively.
*
*
* @param Site/ServiceGroup/NGI/Project $entity
* @param OwnedEntity $entity An instance of Site,Service,NGI,Project or other OwnedEntity.
* @return void
*/
public function roleRequest($entity) {
public function roleRequest ($roleRequested, $requestingUser, $entity) {
$project = null;
$emails = null;
$authorisingUserIds = [];
$projectIds = null;

// Get the roles from the entity
foreach ( $entity->getRoles () as $role ) {
$roles [] = $role;
}
// For each role the entity has.
foreach ($entity->getRoles() as $role) {
// Get the corresponding user.
$user = $role->getUser();

// Now for each role get the user
foreach ( $roles as $role ) {
$enablingRoles = \Factory::getRoleActionAuthorisationService()->authoriseAction(\Action::GRANT_ROLE, $entity, $role->getUser())->getGrantingRoles();
if ($entity instanceof \Site) {
//$enablingRoles = \Factory::getSiteService ()->authorize Action ( \Action::GRANT_ROLE, $entity, $role->getUser () );
// Determine if that user has roles that can approve role requests,
// this role may not be the same as the one currently in the $role
// variable.
$enablingRoles = \Factory::getRoleActionAuthorisationService()->authoriseAction(\Action::GRANT_ROLE, $entity, $user)->getGrantingRoles();

// If the site has no site adminstrators to approve the role request then send an email to the parent NGI users to approve the request
if ($roles == null) {
$this->roleRequest ( $entity->getNgi () ); // Recursivly call this function to send email to the NGI users
}
} else if ($entity instanceof \ServiceGroup) {
//$enablingRoles = \Factory::getServiceGroupService ()->authorize Action ( \Action::GRANT_ROLE, $entity, $role->getUser () );
} else if ($entity instanceof \Project) {
//$enablingRoles = \Factory::getProjectService ()->authorize Action ( \Action::GRANT_ROLE, $entity, $role->getUser () );
} else if ($entity instanceof \NGI) {
//$enablingRoles = \Factory::getNgiService ()->authorize Action ( \Action::GRANT_ROLE, $entity, $role->getUser () );
$projects = $entity->getProjects (); // set project with the NGI's parent project and later recurse with this

// Only send emails to Project users if there are no users with grant_roles over the NGI
if ($roles == null) {
// Get the ID's of each project so we can remove duplicates
foreach ( $projects as $project ) {
$projectIds [] = $project->getId ();
}
$projectIds = array_unique ( $projectIds );
}
}

// remove admin from enabling roles
/*$position = array_search ( 'GOCDB_ADMIN', $enablingRoles );
if ($position != null) {
unset ( $enablingRoles [$position] );
}*/
// Get the users email and add it to the array if they have an enabling role
if (count ( $enablingRoles ) > 0) {
$emails [] = $role->getUser ()->getEmail ();
// If they can, add their user id to the list of authorising user
// ids.
if (count($enablingRoles) > 0) {
$authorisingUserIds [] = $user->getId();
}
}

/*
* No users are able to grant the role or there are no users over this entity. In this case we will email the parent entity for approval
*/
if ($emails == null || count($emails) == 0) {
// If there are no users that are able to grant the role over this entity,
// we will email the parent entity for approval.
if (count($authorisingUserIds) == 0) {
if ($entity instanceof \Site) {
$this->roleRequest ( $entity->getNgi () ); // Recursivly call this function to send email to the NGI users
// Sites can only have a single parent NGI.
$this->roleRequest ( $roleRequested, $requestingUser, $entity->getNgi () ); // Recursivly call this function to send email to the NGI users
} else if ($entity instanceof \NGI) {
/*
* NGIs can belong to multiple Projects.
* It is important to remove duplicate projects here otherwise we will spam the same addresses as we recursively call this method.
*/
$projects = $entity->getProjects (); // set project with the NGI's parent project and later recurse with this
Expand All @@ -97,34 +73,13 @@ public function roleRequest($entity) {
} else {
// If the entity has valid users who can approve the role then send the email notification.

// Remove duplicate emails from array
$emails = array_unique ( $emails );

// Get the PortalURL to create an accurate link to the role approval view
$localInfoLocation = __DIR__ . "/../../config/local_info.xml";
$localInfoXML = simplexml_load_file ( $localInfoLocation );
$webPortalURL = $localInfoXML->local_info->web_portal_url;

// Email content
$headers = "From: no-reply@goc.egi.eu";
$subject = "GocDB: A Role request requires attention";

$body = "Dear GOCDB User,\n\n" . "A user has requested a role that requires attention.\n\n" .
"You can approve or deny this request here:\n\n" . $webPortalURL . "/index.php?Page_Type=Role_Requests\n\n" .
"Note: This role may already have been approved or denied by another GocDB User";
// Remove duplicate user ids from array
$authorisingUserIds = array_unique ( $authorisingUserIds );

$sendMail = TRUE;
// Send email to all users who can approve this role request
if ($emails != null) {
foreach ( $emails as $email ) {
if($sendMail){
mail($email, $subject, $body, $headers);
} else {
echo "Email: " . $email . "<br>";
echo "Subject: " . $subject . "<br>";
echo "Body: " . $body . "<br>";
}
}
foreach ( $authorisingUserIds as $userId ) {
$approvingUser = \Factory::getUserService()->getUser($userId);
$this->sendEmail($roleRequested, $requestingUser, $entity->getName(), $approvingUser);
}
}

Expand All @@ -136,12 +91,50 @@ public function roleRequest($entity) {
if ($projectIds != null) {
foreach ( $projectIds as $pid ) {
$project = \Factory::getOwnedEntityService ()->getOwnedEntityById ( $pid );
if(sendMail){
$this->roleRequest ( $project );
} else {
echo $project->getName () . "<br>";
}
$this->roleRequest ( $roleRequested, $requestingUser, $project );

}
}
}


/**
* Return the PortalURL to enable an accurate link to the role approval view to be created
*/
private function getWebPortalURL() {
return \Factory::getConfigService()->GetPortalURL();
}

private function sendEmail($roleRequested, $requestingUser, $entityName, $approvingUser) {
$subject = sprintf(
'GOCDB: A Role request from %1$s %2$s over %3$s requires your attention',
$requestingUser->getForename(),
$requestingUser->getSurname(),
$roleRequested->getOwnedEntity()->getName()
);

$body = sprintf(
implode("\n", array(
'Dear %1$s,',
'',
'%2$s %3$s requested the "%4$s" role over %5$s which requires your attention.',
'',
'You can approve or deny the request here:',
' %6$s/index.php?Page_Type=Role_Requests',
'',
'Note: This role could already have been approved or denied by another GOCDB User',
)),
$approvingUser->getForename(),
$requestingUser->getForename(),
$requestingUser->getSurname(),
$roleRequested->getRoleType()->getName(),
$roleRequested->getOwnedEntity()->getName(),
$this->getWebPortalURL()
);

$emailAddress = $approvingUser->getEmail();
$headers = "From: GOCDB <gocdb-admins@mailman.egi.eu>";

\Factory::getEmailService()->send($emailAddress, $subject, $body, $headers);
}
}