Commit 52b5b63e authored by jaapjansma's avatar jaapjansma

tested send e-mail action, added create/update relationship action and several improvements.

parent 0842aba3
......@@ -11,5 +11,9 @@ Version 1.2
** New actions**
* Added action to send an e-mail to event participants
* Send E-mail
* Send E-mail To Participants
* Find message template by name
* Create or Update relationship
......@@ -7,7 +7,7 @@ use \Civi\ActionProvider\Condition\AbstractCondition;
use \Civi\ActionProvider\Parameter\ParameterBagInterface;
use \Civi\ActionProvider\Parameter\ParameterBag;
use \Civi\ActionProvider\Parameter\SpecificationBag;
use \Civi\ActionProvider\Exception\InvalidParameterException;
use \Civi\ActionProvider\Parameter\InvalidParameterException;
use \Civi\ActionProvider\Exception\InvalidConfigurationException;
/**
......@@ -115,11 +115,15 @@ abstract class AbstractAction implements \JsonSerializable {
* @throws \Exception
*/
public function execute(ParameterBagInterface $parameters, ParameterBagInterface $conditionParameters, ParameterBagInterface $invalidConditionOutput) {
if (!$this->validateConfiguration()) {
throw new InvalidConfigurationException("Found invalid configuration for the action: ".get_class($this));
try {
$this->validateConfiguration();
} catch (InvalidParameterException $e) {
throw new InvalidConfigurationException("Found invalid configuration for the action: ".get_class($this).' '.$e->getMessage());
}
if (!$this->validateParameters($parameters)) {
throw new InvalidParameterException("Found invalid parameters for the action: ".get_class($this));
try {
$this->validateParameters($parameters);
} catch (InvalidParameterException $e) {
throw new InvalidParameterException("Found invalid parameters for the action: ".get_class($this).' '.$e->getMessage());
}
if ($this->condition && !$this->condition->isConditionValid($conditionParameters)) {
......
......@@ -41,7 +41,7 @@ class CreateActivity extends AbstractAction {
new Specification('source_contact_id', 'Integer', E::ts('Source Contact ID'), TRUE),
new Specification('target_contact_id', 'Integer', E::ts('Target Contact ID'), TRUE),
new Specification('assignee_contact_id', 'Integer', E::ts('Assignee Contact ID'), FALSE),
new Specification('activity_date', 'Date', E::ts('Activity Date'), TRUE),
new Specification('activity_date', 'Timestamp', E::ts('Activity Date'), TRUE),
new Specification('id', 'Integer', E::ts('Activity ID'), false),
new Specification('campaign_id', 'Integer', E::ts('Campaign'), false),
]);
......
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\ActionProvider\Action\Communication;
use Civi\ActionProvider\Action\AbstractAction;
use \Civi\ActionProvider\Parameter\ParameterBagInterface;
use Civi\ActionProvider\Parameter\SpecificationBag;
use Civi\ActionProvider\Parameter\Specification;
use CRM_ActionProvider_ExtensionUtil as E;
class MessageTemplateByName extends AbstractAction {
/**
* Run the action
*
* @param ParameterInterface $parameters
* The parameters to this action.
* @param ParameterBagInterface $output
* The parameters this action can send back
* @return void
*/
protected function doAction(ParameterBagInterface $parameters, ParameterBagInterface $output) {
$messageTemplateBao = new \CRM_Core_DAO_MessageTemplate();
$messageTemplateBao->is_active = 1;
$messageTemplateBao->find();
$messageTemplateBao->msg_title = $this->configuration->getParameter('name');
if ($messageTemplateBao->find(TRUE)) {
$output->setParameter('subject', $messageTemplateBao->msg_subject);
$output->setParameter('body_html', $messageTemplateBao->msg_html);
$output->setParameter('body_text', $messageTemplateBao->msg_text);
}
}
/**
* Returns the specification of the configuration options for the actual action.
*
* @return SpecificationBag
*/
public function getConfigurationSpecification() {
$messageTemplates = array();
$messageTemplateBao = new \CRM_Core_DAO_MessageTemplate();
$messageTemplateBao->is_active = 1;
$messageTemplateBao->find();
while($messageTemplateBao->fetch()) {
$messageTemplates[$messageTemplateBao->msg_title] = $messageTemplateBao->msg_title;
}
return new SpecificationBag(array(
new Specification('name', 'String', E::ts('Name'), true, null, null, $messageTemplates),
));
}
/**
* Returns the specification of the parameters of the actual action.
*
* @return SpecificationBag
*/
public function getParameterSpecification() {
return new SpecificationBag();
}
/**
* Returns the specification of the output parameters of this action.
*
* This function could be overriden by child classes.
*
* @return SpecificationBag
*/
public function getOutputSpecification() {
return new SpecificationBag(array(
new Specification('subject', 'String', E::ts('Subject')),
new Specification('body_html', 'String', E::ts('HTML Body')),
new Specification('body_text', 'String', E::ts('Plain text Body')),
));
}
}
\ No newline at end of file
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\ActionProvider\Action\Communication;
use Civi\ActionProvider\Action\AbstractAction;
use \Civi\ActionProvider\Parameter\ParameterBagInterface;
use Civi\ActionProvider\Parameter\SpecificationBag;
use Civi\ActionProvider\Parameter\Specification;
use CRM_ActionProvider_ExtensionUtil as E;
class SendEmail extends AbstractAction {
/**
* Run the action
*
* @param ParameterInterface $parameters
* The parameters to this action.
* @param ParameterBagInterface $output
* The parameters this action can send back
* @return void
*/
protected function doAction(ParameterBagInterface $parameters, ParameterBagInterface $output) {
$mailer = new \Civi\ActionProvider\Utils\SendEmail();
if ($this->configuration->getParameter('use_sender_as') == 'from' && $parameters->doesParameterExists('sender_contact_id')) {
$mailer->setSenderContactId($parameters->getParameter('sender_contact_id'), false, true);
} elseif ($this->configuration->getParameter('use_sender_as') == 'from' && $parameters->doesParameterExists('sender_contact_id')) {
$mailer->setSenderContactId($parameters->getParameter('sender_contact_id'), true, false);
}
if ($parameters->doesParameterExists('case_id')) {
$mailer->setCaseId($parameters->getParameter('case_id'));
}
if ($parameters->doesParameterExists('contribution_id')) {
$mailer->setContributionId($parameters->getParameter('contribution_id'));
}
if ($parameters->doesParameterExists('activity_id')) {
$mailer->setActivityId($parameters->getParameter('activity_id'));
}
$mailer->send(array($parameters->getParameter('contact_id')), $parameters->getParameter('subject'), $parameters->getParameter('body_text'), $parameters->getParameter('body_html'));
}
/**
* Returns the specification of the configuration options for the actual action.
*
* @return SpecificationBag
*/
public function getConfigurationSpecification() {
$sender_options = array(
'from' => E::ts('Send E-mail from E-mail adress of Sender Contact ID'),
'reply_to' => E::ts('Set E-mail address of Sender Contact ID as Reply To'),
'none' => E::ts('Do not use Sender Contact ID')
);
return new SpecificationBag(array(
new Specification('use_sender_as', 'String', E::ts('Use Sender Contact ID as'), true, 'none', null, $sender_options),
));
}
/**
* Returns the specification of the parameters of the actual action.
*
* @return SpecificationBag
*/
public function getParameterSpecification() {
return new SpecificationBag(array(
new Specification('contact_id', 'Integer', E::ts('Receiver Contact ID'), true),
new Specification('subject', 'String', E::ts('Subject'), true),
new Specification('body_html', 'String', E::ts('HTML Body'), true),
new Specification('body_text', 'String', E::ts('Plain text Body'), true),
new Specification('sender_contact_id', 'Integer', E::ts('Sender Contact ID'), false),
new Specification('activity_id', 'Integer', E::ts('Activity ID'), false),
new Specification('contribution_id', 'Integer', E::ts('Contribution ID'), false),
new Specification('case_id', 'Integer', E::ts('Case ID'), false),
));
}
/**
* Returns the specification of the output parameters of this action.
*
* This function could be overriden by child classes.
*
* @return SpecificationBag
*/
public function getOutputSpecification() {
return new SpecificationBag();
}
}
\ No newline at end of file
......@@ -42,10 +42,10 @@ class SendEmailToParticipants extends AbstractAction {
foreach($participants['values'] as $participant) {
$contactIds[] = $participant['contact_id'];
}
$senderContact = civicrm_api3('Contact', 'getsingle', array('id' => $parameters->getParameter('sender_contact_id')));
$email = new \Civi\ActionProvider\Utils\SendEmail($senderContact['email'], $senderContact['display_name']);
$email->send($contactIds, $parameters->getParameter('subject'), $parameters->getParameter('message'), $parameters->getParameter('message'));
$senderContactId = $parameters->getParameter('sender_contact_id');
$mailer = new \Civi\ActionProvider\Utils\SendEmail();
$mailer->setSenderContactId($senderContactId);
$mailer->send($contactIds, $parameters->getParameter('subject'), $parameters->getParameter('message'), $parameters->getParameter('message'));
}
/**
......
......@@ -26,6 +26,10 @@ class SetDateValue extends AbstractAction {
$date->setDescription('Set the date value follow the formats from <a href="https://secure.php.net/manual/en/datetime.formats.php">PHP.net date time</a>.');
return new SpecificationBag(array(
$date,
new Specification('include_time', 'Boolean', E::ts('Include time'), true, '0', '', array(
'0' => E::ts('No'),
'1' => E::ts('Yes')
)),
));
}
......@@ -36,7 +40,7 @@ class SetDateValue extends AbstractAction {
* @throws \Exception
*/
public function getParameterSpecification() {
return new SpecificationBag();
return new SpecificationBag(array());
}
/**
......@@ -64,7 +68,11 @@ class SetDateValue extends AbstractAction {
*/
protected function doAction(ParameterBagInterface $parameters, ParameterBagInterface $output) {
$date = new \DateTime($this->configuration->getParameter('date'));
$output->setParameter('date', $date->format('Ymd'));
if ($this->configuration->doesParameterExists('include_time') && $this->configuration->getParameter('include_time')) {
$output->setParameter('date', $date->format('YmdHis'));
} else {
$output->setParameter('date', $date->format('Ymd'));
}
}
}
\ No newline at end of file
<?php
/**
* @author Jaap Jansma <jaap.jansma@civicoop.org>
* @license AGPL-3.0
*/
namespace Civi\ActionProvider\Action\Relationship;
use \Civi\ActionProvider\Action\AbstractAction;
use \Civi\ActionProvider\Parameter\ParameterBagInterface;
use \Civi\ActionProvider\Parameter\SpecificationBag;
use \Civi\ActionProvider\Parameter\Specification;
use \Civi\ActionProvider\Utils\CustomField;
use CRM_ActionProvider_ExtensionUtil as E;
class CreateOrUpdateRelationship extends CreateRelationship {
/**
* Returns the specification of the configuration options for the actual action.
*
* @return SpecificationBag
*/
public function getConfigurationSpecification() {
$specs = parent::getConfigurationSpecification();
$specs->addSpecification(new Specification('also_update_inactive', 'Boolean', E::ts('Update inactive relationships'), false, 0, null, null, false));
return $specs;
}
/**
* Find existing relationship
*
* @param $contact_id_a
* @param $contact_id_b
* @param $type_id
* @param bool $also_inactive
*
* @return mixed
*/
protected function findExistingRelationshipId($contact_id_a, $contact_id_b, $type_id, $also_inactive=false) {
$relationshipFindParams = array();
$relationshipFindParams['contact_id_a'] = $contact_id_a;
$relationshipFindParams['contact_id_b'] = $contact_id_b;
$relationshipFindParams['relationship_type_id'] = $type_id;
$relationshipFindParams['is_active'] = '1';
try {
$relationship = civicrm_api3('Relationship', 'getsingle', $relationshipFindParams);
return $relationship['id'];
} catch (\Exception $e) {
// Do nothing
}
if ($also_inactive) {
$relationshipFindParams = array();
$relationshipFindParams['contact_id_a'] = $contact_id_a;
$relationshipFindParams['contact_id_b'] = $contact_id_b;
$relationshipFindParams['relationship_type_id'] = $type_id;
$relationshipFindParams['is_active'] = '0';
try {
$relationship = civicrm_api3('Relationship', 'getsingle', $relationshipFindParams);
return $relationship['id'];
} catch (\Exception $e) {
// Do nothing
}
}
return false;
}
/**
* Run the action
*
* @param ParameterBagInterface $parameters
* The parameters to this action.
* @param ParameterBagInterface $output
* The parameters this action can send back
* @return void
* @throws \Exception
*/
protected function doAction(ParameterBagInterface $parameters, ParameterBagInterface $output) {
$relationship_id = false;
$alsoUpdateInactiveOne = false;
if ($this->configuration->doesParameterExists('also_update_inactive') && $this->configuration->getParameter('also_update_inactive')) {
$alsoUpdateInactiveOne = true;
}
$relationship_id = $this->findExistingRelationshipId($parameters->getParameter('contact_id_a'), $parameters->getParameter('contact_id_b'), $parameters->getParameter('relationship_type_id'), $alsoUpdateInactiveOne);
if ($relationship_id) {
$relationshipParams['id'] = $relationship_id;
}
// Get the contact and the event.
$relationshipParams['contact_id_a'] = $parameters->getParameter('contact_id_a');
$relationshipParams['contact_id_b'] = $parameters->getParameter('contact_id_b');
$relationshipParams['relationship_type_id'] = $this->configuration->getParameter('relationship_type_id');
$relationshipParams['is_active'] = '1';
if ($this->configuration->getParameter('set_start_date') && !$relationship_id) {
$today = new \DateTime();
$relationshipParams['start_date'] = $today->format('Ymd');
}
if ($relationship_id) {
$relationshipParams['end_date'] = 'null';
}
$relationshipParams['custom'] = array();
foreach($this->getParameterSpecification() as $spec) {
if (stripos($spec->getName(), 'custom_')!==0) {
continue;
}
if ($parameters->doesParameterExists($spec->getName())) {
list($customFieldID, $customValueID) = \CRM_Core_BAO_CustomField::getKeyID($spec->getApiFieldName(), TRUE);
$value = $parameters->getParameter($spec->getName());
if (is_array($value)) {
$value = \CRM_Core_DAO::VALUE_SEPARATOR . implode(\CRM_Core_DAO::VALUE_SEPARATOR, $value) . \CRM_Core_DAO::VALUE_SEPARATOR;
}
\CRM_Core_BAO_CustomField::formatCustomField($customFieldID, $relationshipParams['custom'], $value, 'Relationship', $customValueID);
}
}
try {
// Do not use api as the api checks for an existing relationship.
$relationship = \CRM_Contact_BAO_Relationship::add($relationshipParams);
$output->setParameter('id', $relationship->id);
} catch (\Exception $e) {
// Do nothing.
}
}
}
\ No newline at end of file
......@@ -98,17 +98,20 @@ class CreateRelationship extends AbstractAction {
$relationshipParams['start_date'] = $today->format('Ymd');
}
$relationshipParams['custom'] = array();
foreach($this->getParameterSpecification() as $spec) {
if (stripos($spec->getName(), 'custom_')!==0) {
continue;
}
$relationshipParams['custom'] = array();
if ($parameters->doesParameterExists($spec->getName())) {
list($customFieldID, $customValueID) = \CRM_Core_BAO_CustomField::getKeyID($spec->getApiFieldName(), TRUE);
\CRM_Core_BAO_CustomField::formatCustomField($customFieldID, $relationshipParams['custom'], $parameters->getParameter($spec->getName()), 'Relationship', $customValueID);
$value = $parameters->getParameter($spec->getName());
if (is_array($value)) {
$value = \CRM_Core_DAO::VALUE_SEPARATOR . implode(\CRM_Core_DAO::VALUE_SEPARATOR, $value) . \CRM_Core_DAO::VALUE_SEPARATOR;
}
\CRM_Core_BAO_CustomField::formatCustomField($customFieldID, $relationshipParams['custom'], $value, 'Relationship', $customValueID);
}
}
try {
// Do not use api as the api checks for an existing relationship.
$relationship = \CRM_Contact_BAO_Relationship::add($relationshipParams);
......
......@@ -2,6 +2,9 @@
namespace Civi\ActionProvider\Parameter;
use \Civi\ActionProvider\Exception\InvalidParameterException;
use CRM_ActionProvider_ExtensionUtil as E;
class SpecificationBag implements \IteratorAggregate {
protected $parameterSpecifications = array();
......@@ -17,13 +20,15 @@ class SpecificationBag implements \IteratorAggregate {
*
* @param ParameterBagInterface $parameters
* @param SpecificationBag $specification
*
* @return bool
* @throws \Civi\ActionProvider\Exception\InvalidParameterException
*/
public static function validate(ParameterBagInterface $parameters, SpecificationBag $specification) {
foreach($specification as $spec) {
// First check whether the value is present and should be present.
if ($spec->isRequired() && !$parameters->doesParameterExists($spec->getName())) {
return FALSE;
throw new InvalidParameterException($spec->getName(). ' is required');
}
if($parameters->doesParameterExists($spec->getName()) && $spec->isMultiple()) {
......@@ -31,21 +36,21 @@ class SpecificationBag implements \IteratorAggregate {
if (is_array($values)) {
foreach ($values as $value) {
if ($value && \CRM_Utils_Type::validate($value, $spec->getDataType(), FALSE) === NULL) {
return FALSE;
throw new InvalidParameterException($spec->getName(). ' is invalid');
}
}
} else {
if ($values && \CRM_Utils_Type::validate($values, $spec->getDataType(), FALSE) === NULL) {
return FALSE;
throw new InvalidParameterException($spec->getName(). ' is invalid');
}
}
} elseif($parameters->doesParameterExists($spec->getName()) && !$spec->isMultiple()) {
$value = $parameters->getParameter($spec->getName());
if (is_array($value)) {
return FALSE;
throw new InvalidParameterException($spec->getName(). ' requires a single value a multiple value is given');
}
if ($value && \CRM_Utils_Type::validate($value, $spec->getDataType(), FALSE) === NULL) {
return FALSE;
throw new InvalidParameterException($spec->getName(). ' is invalid');
}
}
}
......
......@@ -173,6 +173,10 @@ class Provider {
AbstractAction::MULTIPLE_CONTACTS_ACTION_TAG,
AbstractAction::DATA_MANIPULATION_TAG,
));
$this->addActionWithoutFiltering('CreateOrUpdateRelationship', '\Civi\ActionProvider\Action\Relationship\CreateOrUpdateRelationship',E::ts('Creat/Update relationship') , array(
AbstractAction::MULTIPLE_CONTACTS_ACTION_TAG,
AbstractAction::DATA_MANIPULATION_TAG,
));
$this->addActionWithoutFiltering('EndRelationship', '\Civi\ActionProvider\Action\Relationship\EndRelationship',E::ts('End relationship') , array(
AbstractAction::MULTIPLE_CONTACTS_ACTION_TAG,
AbstractAction::DATA_MANIPULATION_TAG,
......@@ -201,6 +205,14 @@ class Provider {
AbstractAction::WITHOUT_CONTACT_ACTION_TAG,
AbstractAction::DATA_RETRIEVAL_TAG,
));
$this->addActionWithoutFiltering('MessageTemplateByName', '\Civi\ActionProvider\Action\Communication\MessageTemplateByName', E::ts('Find message template by name'), array(
AbstractAction::WITHOUT_CONTACT_ACTION_TAG,
AbstractAction::DATA_RETRIEVAL_TAG
));
$this->addActionWithoutFiltering('SendEmail', '\Civi\ActionProvider\Action\Communication\SendEmail', E::ts('Send E-mail'), array(
AbstractAction::SINGLE_CONTACT_ACTION_TAG,
AbstractAction::SEND_MESSAGES_TO_CONTACTS
));
$conditions = array(
new \Civi\ActionProvider\Condition\ParameterIsEmpty(),
......
......@@ -90,6 +90,9 @@ class CustomField {
$title = trim($titlePrefix.$customField['label']);
$is_required = isset($customField['is_required']) && $customField['is_required'] && $useRequiredFromCustomField ? true : false;
$multiple = false;
if ($customField['html_type'] == 'CheckBox') {
$multiple = true;
}
$default = null;
$spec = null;
......
......@@ -12,10 +12,16 @@ class SendEmail {
private $from_email;
private $reply_to_email;
private $sender_contact_id;
private $case_id;
private $contribution_id;
private $activity_id;
public function __construct($from_email=null, $from_name=null) {
$this->from_email = $from_email;
$this->from_name = $from_name;
......@@ -29,6 +35,41 @@ class SendEmail {
$this->contribution_id = $contribution_id;
}
public function setActivityId($activity_id) {
$this->activity_id = $activity_id;
}
/**
* Set the sender contact ID. The sender contact ID is used as the source contact ID
* for the e-mail activity.
* The e-mail address of the sender is used as ReplyTo
* Alternatively you could also set From Header
*
*
* @param int $senderContactId
* @param bool $useAsReplyTo
* @param bool $useAsFrom
*/
public function setSenderContactId($senderContactId, $useAsReplyTo=true, $useAsFrom=false) {
try {
$senderContact = civicrm_api3('Contact', 'getsingle', ['id' => $senderContactId]);
$this->sender_contact_id = $senderContactId;
if ($senderContact['email']) {
if ($useAsReplyTo) {
$this->reply_to_email = $senderContact['email'];
}
if ($useAsFrom) {
$this->from_email = $senderContact['email'];
if ($senderContact['display_name'] != $senderContact['email']) {
$this->from_name = $senderContact['display_name'];
}
}
}
} catch (\Exception $e) {
// Do nothing
}
}
/**
* Send e-mail
*
......@@ -76,11 +117,14 @@ class SendEmail {
\CRM_Utils_Token::getTokens($subject));
if ($this->case_id) {
$contact['case.id'] = $this->case_id;
$contact['case_id'] = $this->case_id;
}
if ($this->contribution_id) {
$contact['contribution_id'] = $this->contribution_id;
}
if ($this->activity_id) {
$contact['activity_id'] = $this->activity_id;
}
if ($extra_data) {
$contact['extra_data'] = $extra_data;
}
......@@ -165,11 +209,8 @@ class SendEmail {
if ($html && ($contact['preferred_mail_format'] == 'HTML' || $contact['preferred_mail_format'] == 'Both')) {
$mailParams['html'] = $html;
}
if (isset($params['cc']) && !empty($params['cc'])) {
$mailParams['cc'] = $params['cc'];
}
if (isset($params['bcc']) && !empty($params['bcc'])) {
$mailParams['bcc'] = $params['bcc'];
if ($this->from_email) {
$mailParams['replyTo'] = $this->reply_to_email;
}
$result = \CRM_Utils_Mail::send($mailParams);
if (!$result) {
......@@ -193,10 +234,11 @@ class SendEmail {
'activity_date_time' => date('YmdHis'),
'subject' => $messageSubject,
'details' => $details,
// FIXME: check for name Completed and get ID from that lookup
'status_id' => 2,
'status_id' => "Completed",
);
if ($this->sender_contact_id) {
$activityParams['source_contact_id'] = $this->sender_contact_id;
}
$activity = \CRM_Activity_BAO_Activity::create($activityParams);
$activityContacts = \CRM_Core_OptionGroup::values('activity_contacts', FALSE, FALSE, FALSE, NULL, 'name');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment