petitionemail.php 57.3 KB
Newer Older
1 2 3 4
<?php

require_once 'petitionemail.civix.php';

5 6 7 8 9
// You can define multiple pairs of target groups to
// matching field. This constant defines how many are 
// presented in the user interface.
define('PETITIONEMAIL_ALLOWED_GROUP_FIELD_COMBINATIONS_COUNT', 3);

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**
 * Implementation of hook_civicrm_config
 */
function petitionemail_civicrm_config(&$config) {
  _petitionemail_civix_civicrm_config($config);
}

/**
 * Implementation of hook_civicrm_xmlMenu
 *
 * @param $files array(string)
 */
function petitionemail_civicrm_xmlMenu(&$files) {
  _petitionemail_civix_civicrm_xmlMenu($files);
}

/**
 * Implementation of hook_civicrm_install
 */
function petitionemail_civicrm_install() {
  return _petitionemail_civix_civicrm_install();
}

/**
 * Implementation of hook_civicrm_uninstall
 */
function petitionemail_civicrm_uninstall() {
37
  // Clear out our variables.
38
  petitionemail_remove_profiles();
39
  petitionemail_remove_custom_fields();
40
  petitionemail_remove_variables();
41 42 43 44 45 46 47
  return _petitionemail_civix_civicrm_uninstall();
}

/**
 * Implementation of hook_civicrm_enable
 */
function petitionemail_civicrm_enable() {
48
  // Ensure the profile id is created.
49 50 51 52
  petitionemail_create_custom_fields();
  petitionemail_get_profile_id('petitionemail_profile_matching_fields');
  petitionemail_get_profile_id('petitionemail_profile_default_contact');
  petitionemail_get_profile_id('petitionemail_profile_default_activity');
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
  return _petitionemail_civix_civicrm_enable();
}

/**
 * Implementation of hook_civicrm_disable
 */
function petitionemail_civicrm_disable() {
  return _petitionemail_civix_civicrm_disable();
}

/**
 * Implementation of hook_civicrm_upgrade
 *
 * @param $op string, the type of operation being performed; 'check' or 'enqueue'
 * @param $queue CRM_Queue_Queue, (for 'enqueue') the modifiable list of pending up upgrade tasks
 *
 * @return mixed  based on op. for 'check', returns array(boolean) (TRUE if upgrades are pending)
 *                for 'enqueue', returns void
 */
function petitionemail_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
  return _petitionemail_civix_civicrm_upgrade($op, $queue);
}

/**
 * Implementation of hook_civicrm_managed
 *
 * Generate a list of entities to create/deactivate/delete when this module
 * is installed, disabled, uninstalled.
 */
function petitionemail_civicrm_managed(&$entities) {
  return _petitionemail_civix_civicrm_managed($entities);
}
85

Jamie McClelland's avatar
Jamie McClelland committed
86 87 88
/**
 * Implemention of hook_civicrm_buildForm
 */
89
function petitionemail_civicrm_buildForm( $formName, &$form ) {
90

91 92 93
  if ($formName == 'CRM_Campaign_Form_Petition_Signature') {  
    $survey_id = $form->getVar('_surveyId');
    if ($survey_id) {
Jamie McClelland's avatar
Jamie McClelland committed
94 95
      $sql = "SELECT petition_id, 
                  default_message, 
96
                  subject, 
Jamie McClelland's avatar
Jamie McClelland committed
97
                  message_field, 
98
                  subject_field,
Jamie McClelland's avatar
Jamie McClelland committed
99 100 101 102 103
                  subject 
             FROM civicrm_petition_email 
             WHERE petition_id = %1";
      $params = array( 1 => array( $survey_id, 'Integer' ) );
      $dao = CRM_Core_DAO::executeQuery( $sql, $params );
104 105
      $defaults = array();
      $dao->fetch();
106 107 108 109
      if($dao->N == 0) {
        // Not a email enabled petition
        return;
      }
110
      $message_field = $dao->message_field;
111
      $subject_field = $dao->subject_field;
112
      $defaults[$message_field] = $dao->default_message;
113
      $defaults[$subject_field] = $dao->subject;
114
      $form->setDefaults($defaults);
115 116 117
    }
  }

118
  if ($formName == 'CRM_Campaign_Form_Petition') {
119
    CRM_Core_Resources::singleton()->addScriptFile('cc.tadpole.petitionemail', 'petitionemail.js');
120 121
    $survey_id = $form->getVar('_surveyId');
    if ($survey_id) {
122
      // Set default values for saved petitions.
123 124 125
      $sql = "SELECT petition_id, 
                default_message, 
                message_field, 
126
                subject_field,
127 128
                subject,
                recipients,
129
                location_type_id
130 131 132 133
              FROM civicrm_petition_email 
              WHERE petition_id = %1";
      $params = array( 1 => array( $survey_id, 'Integer' ) );
      $dao = CRM_Core_DAO::executeQuery( $sql, $params );
134
      $dao->fetch();
135 136 137 138 139
      if($dao->N > 0) {
        // Base table values.
        $defaults['email_petition'] = 1;
        $defaults['recipients'] = $dao->recipients;
        $defaults['default_message'] = $dao->default_message;
140
        $defaults['message_field'] = $dao->message_field;
141
        $defaults['subject_field'] = $dao->subject_field;
142 143 144 145
        $defaults['subject'] = $dao->subject;
        $defaults['location_type_id'] = $dao->location_type_id;
        
        // Now get matching fields.
146 147
        $sql = "SELECT matching_field, matching_group_id FROM
          civicrm_petition_email_matching_field WHERE petition_id = %1";
148 149
        $dao = CRM_Core_DAO::executeQuery($sql, $params);
        $matching_fields = array();
150
        $i = 1;
151
        while($dao->fetch()) {
152 153 154
          $defaults['matching_field' . $i] = $dao->matching_field;
          $defaults['matching_group_id' . $i] = $dao->matching_group_id;
          $i++;
155
        }
156 157
        // We have to build this URL by hand to avoid having the curly 
        // braces get escaped.
Jamie McClelland's avatar
Jamie McClelland committed
158 159
        $base_url = preg_match('#/$#', CIVICRM_UF_BASEURL) ? CIVICRM_UF_BASEURL : CIVICRM_UF_BASEURL . '/';
        $base_url = $base_url . "civicrm/petition/sign?sid=$survey_id&reset=1";
160
        $personal_url = $base_url . '&{contact.checksum}&cid={contact.contact_id}';
161 162
        $defaults['links'] = ts("Personal link (use this link if you are sending it via CiviMail,
          it will auto fill with the user's address): ") . "\n" . 
163
          $personal_url . "\n\n" .  ts("General link: ") . $base_url;
164
        $form->setDefaults($defaults);
165
      }
166
    }
167 168 169
    else {
      $form->setDefaults(
        array(
170 171
          'links' => ts("Please save the petition first, then you can copy and
             paste the link to sign the petition.")
172 173 174
        )
      );
    }
175
    // Now add our extra fields to the form.
176
    $form->add('checkbox', 'email_petition', ts('Send an email to a target'));
177

178 179 180
    // Get the Profiles in use by this petition so we can find out
    // if there are any potential fields for an extra message to the
    // petition target.
Jamie McClelland's avatar
Jamie McClelland committed
181
    $params = array('module' => 'CiviCampaign', 
182
                    'entity_table' => 'civicrm_survey', 
Jamie McClelland's avatar
Jamie McClelland committed
183
                    'entity_id' => $survey_id,
184
                    'rowCount' => 0);
Jamie McClelland's avatar
Jamie McClelland committed
185
    $join_results = civicrm_api3('UFJoin','get', $params);
186
    $custom_fields = array();
187
    $profile_ids = array();
188 189
    if ($join_results['is_error'] == 0) {
      foreach ($join_results['values'] as $join_value) {
190
        $profile_ids[] = $join_value['uf_group_id'];
191 192
      }
    }
193
    $custom_fields = petitionemail_get_text_fields($profile_ids);
194
    
195
    $custom_field_options = array();
196
    if(count($custom_fields) == 0) {
197
      $custom_field_options = array(
Jamie McClelland's avatar
Jamie McClelland committed
198 199
        '' => t('- No Text or TextArea fields defined in your profiles -')
      );
200 201
    }
    else {
202 203
      $custom_field_options = array('' => t('- Select -'));
      $custom_field_options = $custom_field_options + $custom_fields;
204
    }
205
    $choose_one = array('0' => ts('Primary'));
206
    $group_options = $choose_one + CRM_Core_PseudoConstant::group('Mailing');
Jamie McClelland's avatar
Jamie McClelland committed
207 208
    $location_options = $choose_one + 
      CRM_Core_PseudoConstant::get('CRM_Core_DAO_Address', 'location_type_id');
209

210
    $field_options = petitionemail_get_matching_field_options();
211
    $field_options_count = count($field_options);
212 213 214 215 216 217 218
    if($field_options_count == 0) {
      // No matching fields!
      $field_options[''] = ts("No fields are configured");
    }
    else {
      array_unshift($field_options, ts("--Choose one--"));
    }
219 220
    $form->assign('petitionemail_matching_fields_count', $field_options_count);
    $url_params = array(
221
      'gid' => petitionemail_get_profile_id('petitionemail_profile_matching_fields'),
222 223 224 225
      'action' => 'browse'
    );
    $url = CRM_Utils_System::url("civicrm/admin/uf/group/field", $url_params);
    $form->assign('petitionemail_profile_edit_link', $url);
226 227 228 229 230 231 232

    $i = 1;
    while($i <= PETITIONEMAIL_ALLOWED_GROUP_FIELD_COMBINATIONS_COUNT) {
      $form->add('select', 'matching_group_id' . $i, ts('Matching Target Group'), $group_options);
      $form->add('select', 'matching_field' . $i, ts('Matching field(s)'), $field_options); 
      $i++;
    }
233 234 235 236 237 238 239
    // We can't make default message and default subject required,
    // otherwise users will get an error if they submit a petition
    // that doesn't want to send an email to the target. So we have
    // our own custom validation checking that only complains if 
    // the user wants to send an email and we have to insert the 
    // asterisk ourselves, manually.
    $required = ' <span title="This field is required." class="crm-marker">*</span>';
240
    $form->add('select', 'location_type_id', ts('Email'), $location_options);
241
    $form->add('textarea', 'recipients', ts("Send petitions to"), 'rows=20 cols=100');
242
    $form->add('select', 'message_field', ts('Custom Message Field'),
243 244 245
      $custom_field_options);
    $form->add('select', 'subject_field', ts('Custom Subject Field'),
      $custom_field_options);
246 247
    $form->add('textarea', 'default_message', ts('Default Message') . $required, 'rows=20 cols=100');
    $form->add('text', 'subject', ts('Default Email Subject Line') . $required, array('size' => 70));
248
    $form->add('textarea', 'links', ts('Links to sign the petition'), 'rows=5')->freeze();
249 250 251
  }
}

252 253 254 255 256
/**
 * Get fields from the special petition email profile.
 *
 * Filter out un-supported fields.
 */
257
function petitionemail_get_matching_field_options() {
258 259
  $session = CRM_Core_Session::singleton();
  $ret = array();
260
  $uf_group_id = petitionemail_get_profile_id('petitionemail_profile_matching_fields');
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
  $fields = CRM_Core_BAO_UFGroup::getFields($uf_group_id); 
  $allowed = petitionemail_get_allowed_matching_fields();
  if(is_array($fields)) {
    reset($fields);
    while(list($id, $value) = each($fields)) {
      $include = FALSE;
      // Check to see if it's a custom field
      if(preg_match('/^custom_/', $id)) {
        $ret[$id] = $value['title'];
        continue;
      }
      else {
        // Check to see if it's an address field
        $field_pieces = petitionemail_split_address_field($id);
        if($field_pieces) {
          if($field_pieces['location_name'] != 'Primary') {
            $session->setStatus(ts("Only primary address fields are support at this time."));
            continue;
          }
          if(array_key_exists($field_pieces['field_name'], $allowed)) {
            $ret[$id] = $value['title'];
            continue;
          }
        }
      }
      // Warn the user about a field that is not allowed
      $session->setStatus(ts("The field $id is not supported as a matching field at this time."));
    }
  }
290
  
291 292 293
  return $ret;
}

294 295 296 297 298 299
/**
 * Validate the petition form
 *
 * Ensure our values are consistent to avoid broken petitions.
 */
function petitionemail_civicrm_validateForm($formName, &$fields, &$files, &$form, &$errors) {
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
  if ($formName == 'CRM_Campaign_Form_Petition_Signature') {  
    // Do some basic sanity checking to prevent spammers
    if(empty($form->_surveyId)) {
      // Can't do much without the survey_id
      return;
    }
    $survey_id = $form->_surveyId;

    // Check to see if it's an email petition
    $sql = "SELECT message_field FROM civicrm_petition_email WHERE
      petition_id = %0";
    $dao = CRM_Core_DAO::executeQuery($sql, array(0 => array($survey_id, 'Integer')));
    $dao->fetch();
    if($dao->N == 0) {
      // Nothing to do
      return;
    }

    if(!empty($dao->message_field)) {
      $field_name = 'custom_' . $dao->message_field;
      // If we are allowing a user-supplied message field, ensure it doesn't
      // have any URLs or HTML in it.
      if(array_key_exists($field_name, $fields)) {
        if(preg_match('#https?://#i', $fields[$field_name])) {
          $errors[$field_name] = ts("To avoid spammers, you are not allowed to put web addresses in your message. Please revise your message and try again.");
        }
        // Now ensure we have no html tag
        if (preg_match('/([\<])([^\>]{1,})*([\>])/i', $fields[$field_name] )) {
          $errors[$field_name] = ts("To avoid spammers, you are not allowed to put HTML code in your message. Please revise your message and try again.");
        }
      }
    }
  }

334 335
  if($formName == 'CRM_Campaign_Form_Petition') {
    if(CRM_Utils_Array::value('email_petition', $fields)) {
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
      // Make sure we have a subject field and a default message.
      if(!CRM_Utils_Array::value('subject', $fields)) {
        $msg = ts("You must enter an email subject line.");
        $errors['subject'] = $msg;
      }
      if(!CRM_Utils_Array::value('default_message', $fields)) {
        $msg = ts("You must enter a default message.");
        $errors['default_message'] = $msg;
      }
      // For each matching_group_id, make sure we have a corresponding
      // matching field. 
      $i = 1;
      $using_dynamic_method = FALSE;
      while($i <= PETITIONEMAIL_ALLOWED_GROUP_FIELD_COMBINATIONS_COUNT) {
        $matching_group_id = CRM_Utils_Array::value('matching_group_id' . $i, $fields);
        $matching_field = CRM_Utils_Array::value('matching_field' . $i, $fields);

        if(!empty($matching_group_id) && empty($matching_field)) {
354
          $msg = ts("If you select a matching target group you must select
355 356 357 358 359 360 361 362 363 364 365 366
            a corresponding matching field.");
          $errors['matching_field' . $i] = $msg; 
        }
        if(empty($matching_group_id) && !empty($matching_field)) {
          $msg = ts("If you select a matching field you must select a 
            corresponding matching target group.");
          $errors['matching_group_id' . $i] = $msg; 
        }

        // Keep track to see if there are using the dynamic method
        if(!empty($matching_group_id)) {
          $using_dynamic_method = TRUE;
367
        }
368
        $i++;
369
      }
370

371 372 373 374 375 376 377 378 379 380 381 382
      // If additional email targets have been provided, make sure they are
      // all syntactically correct.
      $recipients = CRM_Utils_Array::value('recipients', $fields);
      if(!empty($recipients)) {
        $recipient_array = explode("\n", $recipients);
        while(list(,$line) = each($recipient_array)) {
          if(FALSE === petitionemail_parse_email_line($line)) {
            $errors['recipients'] = ts("Invalid email address listed: %1.", array(1 => $line));
          }
        }
      }

383 384
      if(!$using_dynamic_method && empty($recipients)) {
        $msg = ts("You must select either one target matching group/field or list
385 386 387 388 389 390 391
          at least one address to send all petitions to.");
        $errors['recipients'] = $msg;
      }
    }
  }
}

392 393 394
/**
 * Given an array of profile ids, list all text area fields
 */
395
function petitionemail_get_text_fields($profile_ids) {
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
  // Now get all fields in this profile
  $custom_fields = array();
  while(list(,$uf_group_id) = each($profile_ids)) {
    $params = array('uf_group_id' => $uf_group_id, 'rowCount' => 0);
    $field_results = civicrm_api3('UFField', 'get', $params);
    if ($field_results['is_error'] == 0) {
      foreach ($field_results['values'] as $field_value) {
        $field_name = $field_value['field_name'];
        if(!preg_match('/^custom_[0-9]+/', $field_name)) {
          // We only know how to lookup field types for custom
          // fields. Skip core fields.
          continue;
        }

        $id = substr(strrchr($field_name, '_'), 1);
        // Finally, see if this is a text or textarea field.
        $params = array('id' => $id);
        $custom_results = civicrm_api3('CustomField', 'get', $params);
        if ($custom_results['is_error'] == 0) {
          $field_value = array_pop($custom_results['values']);
          $html_type = $field_value['html_type'];
          $label = $field_value['label'];
          $id = $field_value['id'];
          if($html_type == 'Text' || $html_type == 'TextArea') {
420
            $custom_fields['custom_' . $id] = $label;
421 422 423 424 425 426 427 428 429
          }
        }
      }
    }
  }
  return $custom_fields;
}


430
function petitionemail_civicrm_postProcess( $formName, &$form ) {
431 432 433
  if ($formName != 'CRM_Campaign_Form_Petition') { 
    return; 
  }
434
  $email_petition = CRM_Utils_Array::value('email_petition', $form->_submitValues);
435
  $survey_id = $form->getVar('_surveyId');
436
  if($email_petition && $email_petition  == 1 ) {
437 438
    $lastmoddate = 0;
    if (!$survey_id) {  // Ugly hack because the form doesn't return the id
Jamie McClelland's avatar
Jamie McClelland committed
439 440
      $params = array('title' =>$form->_submitValues['title']);
      $surveys = civicrm_api3("Survey", "get", $params);
441 442
      if (is_array($surveys['values'])) {
        foreach($surveys['values'] as $survey) {
443 444 445
          if ($lastmoddate > strtotime($survey['last_modified_date'])) { 
            continue; 
          }
446 447 448 449 450 451
          $lastmoddate = strtotime($survey['last_modified_date']);
          $survey_id = $survey['id'];
        }
      }
    }
    if (!$survey_id) {
Jamie McClelland's avatar
Jamie McClelland committed
452 453
      $msg = ts('Cannot find the petition for saving email delivery fields.');
      CRM_Core_Session::setStatus($msg);
454 455 456 457
      return;
    }

    $default_message =  $form->_submitValues['default_message'];
458
    $message_field = $form->_submitValues['message_field'];
459
    $subject_field = $form->_submitValues['subject_field'];
460 461 462
    $subject = $form->_submitValues['subject'];
    $recipients = $form->_submitValues['recipients'];
    $location_type_id = $form->_submitValues['location_type_id'];
463

464
    $sql = "REPLACE INTO civicrm_petition_email (
Jamie McClelland's avatar
Jamie McClelland committed
465 466 467
             petition_id,
             default_message, 
             message_field, 
468
             subject_field, 
Jamie McClelland's avatar
Jamie McClelland committed
469 470 471 472 473 474 475 476 477
             subject,
             recipients,
             location_type_id
           ) VALUES ( 
             %1, 
             %2, 
             %3, 
             %4,
             %5,
478 479
             %6,
             %7
Jamie McClelland's avatar
Jamie McClelland committed
480
    )";
481 482 483
    $params = array( 
      1 => array( $survey_id, 'Integer' ),
      2 => array( $default_message, 'String' ),
484
      3 => array( $message_field, 'String' ),
485 486 487 488
      4 => array( $subject_field, 'String' ),
      5 => array( $subject, 'String' ),
      6 => array( $recipients, 'String' ),
      7 => array( $location_type_id, 'Integer' ),
489 490
    );
    $petitionemail = CRM_Core_DAO::executeQuery( $sql, $params );
491
    
492
    // delete any existing ones
Jamie McClelland's avatar
Jamie McClelland committed
493 494
    $sql = "DELETE FROM civicrm_petition_email_matching_field WHERE
      petition_id = %0";
495 496
    $params = array(0 => array($survey_id, 'Integer'));
    CRM_Core_DAO::executeQuery($sql, $params);
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512

    $i = 1;
    while($i <= PETITIONEMAIL_ALLOWED_GROUP_FIELD_COMBINATIONS_COUNT) {
      $matching_group_id = CRM_Utils_Array::value('matching_group_id' . $i, $form->_submitValues);
      $matching_field = CRM_Utils_Array::value('matching_field' . $i, $form->_submitValues);
      if(!empty($matching_group_id) && !empty($matching_field)) {
        $sql = "INSERT INTO civicrm_petition_email_matching_field SET
          petition_id = %0, matching_field = %1, matching_group_id = %2";
        $params = array(
          0 => array($survey_id, 'Integer'),
          1 => array($matching_field, 'String'),
          2 => array($matching_group_id, 'Integer')
        );
        CRM_Core_DAO::executeQuery($sql, $params);
      }
      $i++;
513
    }
514 515 516 517 518 519 520 521 522 523
  } else {
    // This removes targets from petition
    // If a petitions is initially configured to have targets, but they need to be removed.
    $target_delete_params = array(0 => array($survey_id, 'Integer'));

    $matching_target_delete_sql = "DELETE FROM civicrm_petition_email_matching_field WHERE petition_id = %0";
    CRM_Core_DAO::executeQuery($matching_target_delete_sql, $target_delete_params);

    $target_delete_sql = "DELETE FROM civicrm_petition_email WHERE petition_id = %0";
    CRM_Core_DAO::executeQuery($target_delete_sql, $target_delete_params);
524 525 526
  }
}

527 528 529 530
/**
 * Implementation of hook_civicrm_post
 *
 * Run everytime a post is made to see if it's a new profile/activity
531 532
 * that should trigger a petition email to be sent. Also clean up 
 * our tables if a petition is deleted.
533
 */
534
function petitionemail_civicrm_post( $op, $objectName, $objectId, &$objectRef ) {
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
  static $profile_fields = NULL;
  if($objectName == 'Profile' && is_array($objectRef)) {
    // This is hacky but seems to be unavoidable. We really want to run 
    // on the activity post create hook. However, the activity post create
    // hook is called *before* the custom fields are saved for the activity
    // record. That means that none of the custom fields are available when
    // it is called, so we can't provide a custom subject or custom message
    // field to the petitionemail_process_signature function.
    //
    // However, the profile post hook is called before the activity post
    // hook is called. So, we set a static variable when the profile post
    // hook is called to save all the fields being submitted and then make
    // that available when the activity post hook is called.
    $profile_fields = $objectRef;
  }
550 551 552
  if ($objectName == 'Activity') {
    $activity_id = $objectId;

553
    // Only run on creation. For petitions that require a confirmation,
554 555 556
    // after the petition has been created, see petitionemail_civicrm_pageRun().
    if($op == 'create') {
      if(petitionemail_is_actionable_activity($activity_id)) {
557
        petitionemail_process_signature($activity_id, $profile_fields);
558 559
      }
    }
560
  }
561
}
562

563 564 565 566 567 568 569 570 571 572 573 574 575 576
/**
 * Implementation of hook_civicrm_pageRun
 */
function petitionemail_civicrm_pageRun(&$page) {
  // This should be fired after most of the parent run()
  // code is done, which means the activity status should
  // be converted to "complete" if it has been properly
  // verified.
  $pageName = $page->getVar('_name');
  if ($pageName == 'CRM_Campaign_Page_Petition_Confirm') { 
    // Get the activity id from the URL
    $activity_id  = CRM_Utils_Request::retrieve('a', 'String', CRM_Core_DAO::$_nullObject);
    if(petitionemail_is_actionable_activity($activity_id)) {
      petitionemail_process_signature($activity_id);
577 578 579
    }
  }
}
580

581 582
function petitionemail_get_petition_details($petition_id) {
  $ret = array();
Jamie McClelland's avatar
Jamie McClelland committed
583
  $sql = "SELECT default_message, 
584
               message_field, 
585
               subject_field,
586 587 588 589 590
               subject,
               location_type_id,
               recipients
         FROM civicrm_petition_email
         WHERE petition_id = %1 GROUP BY petition_id";
591
  $params = array( 1 => array( $petition_id, 'Integer' ) );
592 593
  $petition_email = CRM_Core_DAO::executeQuery( $sql, $params );
  $petition_email->fetch();
Jamie McClelland's avatar
Jamie McClelland committed
594
  if($petition_email->N == 0) {
595
    // Must not be a petition with a target.
Jamie McClelland's avatar
Jamie McClelland committed
596
    return FALSE;;
597
  }
598

599
  // Store variables we need
600 601 602 603
  $ret['default_message'] = $petition_email->default_message;
  $ret['subject'] = $petition_email->subject;
  $ret['location_type_id'] = $petition_email->location_type_id;
  $ret['message_field'] = $petition_email->message_field;
604
  $ret['subject_field'] = $petition_email->subject_field;
605
  $ret['recipients'] = $petition_email->recipients;
606

607
  // Now retrieve the matching fields, if any
608 609
  $sql = "SELECT matching_field, matching_group_id FROM
    civicrm_petition_email_matching_field WHERE petition_id = %1";
610
  $params = array( 1 => array( $petition_id, 'Integer' ) );
611
  $dao = CRM_Core_DAO::executeQuery($sql, $params);
612
  $ret['matching'] = array();
613
  while($dao->fetch()) {
614
    $ret['matching'][$dao->matching_field] = $dao->matching_group_id;
615
  }
616 617 618
  return $ret;
}

619 620 621 622 623 624 625 626
/**
 * This function handles all petition signature processing.
 *
 * @activity_id integer The activity id of the signature activity
 * @profile_fields array An array of fields submitted by the user, which
 *   may include the custom subject and custom message values.
 */
function petitionemail_process_signature($activity_id, $profile_fields = NULL) {
627 628 629 630 631 632 633
  $petition_id = petitionemail_get_petition_id_for_activity($activity_id);
  if(empty($petition_id)) {
    $log = "Failed to find petition id for activity id: $activity_id";
    CRM_Core_Error::debug_log_message($log);
    return FALSE;
  }
  $petition_vars = petitionemail_get_petition_details($petition_id);
Jamie McClelland's avatar
Jamie McClelland committed
634 635 636 637
  if(!$petition_vars) {
    // Nothing to process, this isn't an email target enabled petition
    return;
  }
638
  $default_message = $petition_vars['default_message'];
639
  $default_subject = $petition_vars['subject'];
640
  $message_field = $petition_vars['message_field'];
641
  $subject_field = $petition_vars['subject_field'];
642

643 644 645 646
  $activity = civicrm_api3("Activity", "getsingle", array ('id' => $activity_id));
  $contact_id = $activity['source_contact_id'];
  $contact = civicrm_api3("Contact", "getsingle", array ('id' => $contact_id));

647 648
  // Figure out whether to use the user-supplied message/subject or the default
  // message/subject.
649
  $petition_message = NULL;
650
  $subject = NULL;
651 652
  // If the petition has specified a message field
  if(!empty($message_field)) {
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
    // Check for a custom message field value in the passed in profile fields.
    // This field will be populated if we are operating on a new activity via
    // the post hook.
    if(is_array($profile_fields) && !empty($profile_fields[$message_field])) {
      $petition_message = $profile_fields[$message_field];
    }
    else {
      // Retrieve the value of the field for this activity (this may happen
      // if we are operating on a confirmation click from pageRun hook).
      $params = array(
        'id' => $activity_id, 
        'return' => $message_field
      );
      $result = civicrm_api3('Activity', 'getsingle', $params);
      if(!empty($result[$message_field])) {
        $petition_message = $result[$message_field];
      }
670 671
    }
  } 
672 673 674
  if(is_null($petition_message)) {
    $petition_message = $default_message;
  }
675 676 677 678
  // CiviCRM seems to htmlentitize everything submitted, but we are
  // preventing any html tags in our validation and we want to avoid
  // weird htmlentites being added to text messages. 
  $petition_message = html_entity_decode($petition_message);
679

680 681 682 683 684 685
  // Add the sending contacts address info
  $address_block = petitionemail_get_address_block($contact_id);
  if($address_block) {
    $petition_message = strip_tags($address_block) . "\n\n" . $petition_message;
  }

686 687
  // If the petition has specified a subject field
  if(!empty($subject_field)) {
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704
    // Check for a custom subject field value in the passed in profile fields.
    // This field will be populated if we are operating on a new activity via
    // the post hook.
    if(is_array($profile_fields) && !empty($profile_fields[$subject_field])) {
      $subject = $profile_fields[$subject_field];
    }
    else {
      // Retrieve the value of the field for this activity (this may happen
      // if we are operating on a confirmation click from pageRun hook).
      $params = array(
        'id' => $activity_id, 
        'return' => $subject_field
      );
      $result = civicrm_api3('Activity', 'getsingle', $params);
      if(!empty($result[$subject_field])) {
        $subject = $result[$subject_field];
      }
705 706 707
    }
  }
  // No user supplied message/subject, use the default
708
  
709 710 711 712
  if(is_null($subject)) {
    $subject = $default_subject;
  }

713 714 715
  // CiviCRM seems to htmlentitize everything submitted, but we don't
  // want 3 > 1 in a subject line get converted to 3 &gt; 1 
  $subject = html_entity_decode($subject);
716

Jamie McClelland's avatar
Jamie McClelland committed
717
  $from = NULL;
718
  if (empty($contact['email'])) {
719 720 721
    $domain = civicrm_api3("Domain", "get", array ());
    if ($domain['is_error'] != 0 || !is_array($domain['values'])) { 
      // Can't send email without a from address.
722 723
      $msg = "petition_email: Failed to send petition email because from
        address not sent.";
724 725 726
      CRM_Core_Error::debug_log_message($msg);
      return; 
    }
727
    $contact['email'] = $domain['values']['from_email'];
728
  }
729
  $from = $contact['display_name'] . ' <' . $contact['email'] . '>';
730 731 732 733 734 735

  // Setup email message (except to address)
  $email_params = array( 
    'from'    => $from,
    'toName'  => NULL,
    'toEmail' => NULL,
Jamie McClelland's avatar
Jamie McClelland committed
736
    'subject' => $subject,
737
    'text'    => $petition_message, 
738
    'html'    => NULL, 
739 740 741
  );

  // Get array of recipients
742
  $recipients = petitionemail_get_recipients($contact_id, $petition_id);
743 744 745
  // Keep track of the targets we actually send the message to so we can 
  // email the petition signer to let them now.
  $message_sent_to = array();
746 747
  while(list(, $recipient) = each($recipients)) {
    if(!empty($recipient['email'])) {
748 749 750 751
      $log = "petition email: contact id ($contact_id) sending to email (" .
        $recipient['email'] . ")";
      CRM_Core_Error::debug_log_message($log);
      if(!empty($recipient['contact_id'])) {
752 753 754 755 756 757
        // Since we're sending to a recipient in the database, create an
        // email activity. Note: we are not using the built-in
        // function to create (and send) and email activity because it won't
        // send if the contact has DoNotEmail they won't get it. However, it's
        // normal to have DoNotEmail for your targets, but you still want them
        // to get the petition.
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

        $log = "petition email: recording email as activity against ".
          "target contact id: " . $recipient['contact_id'];
        CRM_Core_Error::debug_log_message($log);

        $contactDetails = array(0 => $recipient);
        // We are sending a text message, so ensure it's the preferred one
        $contactDetails[0]['preferred_mail_format'] = 'Text';
        $subject = $email_params['subject'];
        $text = $email_params['text'];
        $html = $email_params['html'];
        $emailAddress = $recipient['email'];
        $userID = $contact_id;
        $from = NULL; // This will be pulled from $contact_id,
        $attachments = NULL;
        $cc = NULL;
        $bcc = NULL;
        $contactIds = array($recipient['contact_id']);

777 778 779 780 781 782 783 784 785 786 787 788
        // Create the activity first, then we will send the email.
        $activityTypes = CRM_Core_PseudoConstant::activityType(TRUE, TRUE, FALSE, 'name');
        $activity_type_id = array_search('Email', $activityTypes);
        $activity_status = CRM_Core_PseudoConstant::activityStatus();
        $status_id = array_search('Completed', $activity_status);
        $params = array(
          'activity_type_id' => $activity_type_id,
          'subject' => $subject,
          'details' => $text,
          'source_contact_id' => $contact_id,
          'target_contact_id' => $recipient['contact_id'],
          'status_id' => $status_id
789
        );
790 791 792 793 794 795 796 797 798
        $activity_id = NULL;
        try {
          $ret = civicrm_api3('Activity', 'create', $params);
          $value = array_pop($ret['values']);
          $activity_id = $value['id']; 
        }
        catch (CiviCRM_API3_Exception $e) {
          $log = "petition email: email activity not created";
          $log .= $e->getMessage();
799
          CRM_Core_Error::debug_log_message($log);
800 801 802
          return FALSE;
        }
        if($activity_id) {
803 804 805 806 807 808 809 810 811 812 813 814 815 816
          // Update the activity with the petition id so we can properly
          // report on the email messages sent as a result of this petition.
          $params = array(
            'activity_id' => $activity_id,
            'source_record_id' => $petition_id
          );
          $result = civicrm_api3('Activity', 'update', $params);
          if($result['is_error'] != 0) {
            $log = "civicrm petition: failed to update activity with ".
              "source_record_id";
            CRM_Core_Error::debug_log_message($log);
          }
        }
      }
817 818 819 820 821
      // Now send all email.
      // Handle targets not in the database.
      $email_params['toName'] = $recipient['name'];
      $email_params['toEmail'] = $recipient['email'];
      $to = $email_params['toName'] . ' <' . $email_params['toEmail'] . '>';
822

823 824
      $log = "petition_email: sending petition to '$to' via mail function.";
      CRM_Core_Error::debug_log_message($log);
825

826
      $success = CRM_Utils_Mail::send($email_params);
827

828 829 830 831 832 833
      if($success == 1) {
        CRM_Core_Session::setStatus( ts('Message sent successfully to: ') . htmlentities($to), '', 'success' );
        $log = "petition_email: message sent.";
        $message_sent_to[] = $to;
      } else {
        $log = "petition_email: message was not sent.";
834
      }
835
      CRM_Core_Error::debug_log_message($log);
836 837 838
    }
  }
}
839 840 841

function petitionemail_get_address_block($contact_id) {
  $sql = "SELECT display_name, street_address, city, ".
842
    "s.abbreviation AS state_province, postal_code FROM civicrm_contact c JOIN ".
843 844 845 846 847 848 849 850 851
    "civicrm_address a ON c.id = a.contact_id JOIN civicrm_state_province s ".  
    "on a.state_province_id = s.id WHERE is_primary = 1 ".
    "AND c.id = %0";
  $params = array(0 => array($contact_id, 'Integer'));
  $dao = CRM_Core_DAO::executeQuery($sql, $params);
  $dao->fetch();
  if($dao->N == 0) {
    return NULL;
  }
852 853 854 855 856 857
  $block = $dao->display_name . "\n" .
    $dao->street_address . "\n" .
    $dao->city . ", " .
    $dao->state_province .
    " " .
    $dao->postal_code;
858 859 860
  return $block;
}

861 862 863 864 865 866 867 868 869 870 871 872 873 874
/**
 * Non custom data fields allowed to be a matching field.
 *
 * All custom fields can be used as matching fields, but only
 * a subset of non-custom fields (so we can be sure to build
 * a working query to retrieve them).
 */
function petitionemail_get_allowed_matching_fields() {
  $ret = array(
    'street_name' => 'civicrm_address',
    'street_number' => 'civicrm_address',
    'street_name' => 'civicrm_address',
    'city' => 'civicrm_address',
    'county_id' => 'civicrm_address',
875
    'state_province' => 'civicrm_address',
876 877 878 879 880 881 882
    'postal_code' => 'civicrm_address',
    'postal_code_suffix' => 'civicrm_address',
    'country_id' => 'civicrm_address',
  );
  return $ret;
}

883 884
function petitionemail_get_recipients($contact_id, $petition_id) {
  $petition_vars = petitionemail_get_petition_details($petition_id);
Jamie McClelland's avatar
Jamie McClelland committed
885 886 887 888
  if(!$petition_vars) {
    // Not an email target enabled petition
    return;
  }
889 890 891 892 893 894 895 896 897
  $ret = array();
  // First, parse the additional recipients, if any. These get the email
  // regarldess of who signs it.
  if(!empty($petition_vars['recipients'])) {
    $recipients = explode("\n", $petition_vars['recipients']);
    while(list(,$recipient) = each($recipients)) {
      $email_parts = petitionemail_parse_email_line($recipient); 
      if(FALSE !== $email_parts) {
        $ret[] = array(
898
          'contact_id' => NULL,
899 900 901 902 903 904
          'name' => $email_parts['name'],
          'email' => $email_parts['email']
        );
      }
    }
  }
905 906 907
  // If there are any matching criteria (for a dynamic lookup) we do a
  // complex query to figure out which members of the group should be
  // included as recipients.
Jamie McClelland's avatar
Jamie McClelland committed
908
  if(count($petition_vars['matching']) > 0) {
909 910 911 912
    // This comes as an array with the key being the matching field and
    // the value being the matching_group_id.
    $matching_fields = $petition_vars['matching'];

913 914 915
    // Get the values of the matching fields for the contact. These values
    // are used to match the contact who signed the petition with the 
    // contact or contacts in the target group.
916 917 918 919 920 921

    // Given the matching fields, we're going to do an API call against
    // the contact to get the values that we will be matching on.

    // Build a return_fields array that we will pass to the api call to 
    // specify the fields we want returned with this query.
922
    $field_names = array_keys($matching_fields);
923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945
    $return_fields = array();
    reset($field_names);
    while(list(, $field_name) = each($field_names)) {
      // If the field_name starts with custom_ we can add it straight 
      // away.
      if(preg_match('/^custom_/', $field_name)) {
        $return_fields[] = $field_name;
        continue;
      }

      // Look for field names with a - in them - that's an indication 
      // that it's an address field which will have the location part
      // stuck into the name.
      $field_pieces = petitionemail_split_address_field($field_name);
      if($field_pieces) {
        if($field_pieces['location_name'] == 'Primary') {
          // Primary will be included via the api call, so we just need
          // the field name. If it's not primary, we'll have to do a 
          // manual SQL call below to get the value.
          $return_fields[] = $field_pieces['field_name'];
          continue;
        }
      }
946
      // FIXME If we get here, this is an error
947 948
    }
    $contact_params = array('return' => $return_fields, 'id' => $contact_id);
949 950
    $contact = civicrm_api3('Contact', 'getsingle', $contact_params);
    while(list($matching_field) = each($matching_fields)) {
951 952 953 954 955 956 957 958
      // Check if the field was returned. If not, it's probably an address field
      if(array_key_exists($matching_field, $contact)) {
        $matching_fields[$matching_field] = $contact[$matching_field];
        continue;
      }
      // This means it's probably an address field.
      $field_pieces = petitionemail_split_address_field($matching_field);
      if(!$field_pieces) {
959
        // FIXME This is an error
960 961 962 963
        continue;
      }
      $location_name = $field_pieces['location_name'];
      $field_name = $field_pieces['field_name'];
964
      // NOTE: we only work with primary fields.
965
      if($location_name == 'Primary' && array_key_exists($field_name, $contact)) {
966 967
        // The field name returned by the API won't have the -location part.
        $matching_fields[$matching_field] = $contact[$field_name];
968 969 970
        continue;
      }
      else {
971
        // FIXME This is an error
972 973 974
        continue;
      }
    } 
975 976

    // Initialize variables to build the SQL statement
977
    $from = array();
978 979
    // The master $where clause will be put together using AND
    $where = array();
980
    $params = array();
981
    $added_tables = array();
982

983
    // Initialize the from clause and where clause
984
    $from[] = 'civicrm_contact c';
985
    $where[] = 'c.is_deleted = 0';
986

987 988 989 990 991
    // We build a sub where clause that limits results based on the 
    // matching group and matching field that will be put together using
    // OR since we match any any of the matching field => group
    // combinations.
    $sub_where = array();
992
    reset($matching_fields);
993
    $id = 0;
994
    while(list($matching_field, $value) = each($matching_fields)) {
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
      // The $where_fragment will be put together using AND because
      // you have to match both the group and the field.
      $where_fragment = array();

      // Gather information about the group that is paired with this
      // matching field.
      $group_id = $petition_vars['matching'][$matching_field];
      // Retrieve details (specifically, find out if it's a smart group)
      $results = civicrm_api3('Group', 'getsingle', array('id' => $group_id));
      if(!empty($results['id'])) {
        if(!empty($results['saved_search_id'])) {
          // Populate the cache
          CRM_Contact_BAO_GroupContactCache::check($group_id);
          if(!in_array('civicrm_group_contact_cache', $added_tables)) {
Jamie McClelland's avatar
Jamie McClelland committed
1009
            $from[] = 'LEFT JOIN civicrm_group_contact_cache cc ON
1010 1011 1012 1013 1014 1015
              c.id = cc.contact_id';
            $added_tables[] = 'civicrm_group_contact_cache';
          }
          $where_fragment[] = 'cc.group_id = %' . $id;
          $params[$id] = array($group_id, 'Integer');
          $id++;
1016 1017
        }
        else {
1018
          if(!in_array('civicrm_group_contact', $added_tables)) {
Jamie McClelland's avatar
Jamie McClelland committed
1019
            $from[] = 'LEFT JOIN civicrm_group_contact gc ON
1020 1021 1022 1023 1024 1025 1026
              c.id = gc.contact_id';
            $added_tables[] = 'civicrm_group_contact';
          }
          $where_fragment[] = 'gc.group_id = %' . $id;
          $where_fragment[] = 'gc.status = "Added"';
          $params[$id] = array($group_id, 'Integer');
          $id++;
1027
        }
1028 1029 1030 1031 1032
      
        // Now add in the matching field
        if(empty($value)) {
          // We should never match in this case
          $where_fragment[] = "(0)";
1033 1034
        }
        else {
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
          if(preg_match('/^custom_/', $matching_field)) {
            $sql = "SELECT column_name, table_name FROM civicrm_custom_group g 
              JOIN civicrm_custom_field f ON g.id = f.custom_group_id WHERE 
              f.id = %0";
            $custom_field_id = str_replace('custom_', '', $matching_field);
            $dao = CRM_Core_DAO::executeQuery($sql, array(0 => array($custom_field_id, 'Integer')));
            $dao->fetch();
            if(!in_array($dao->table_name, $added_tables)) {
              $from[] = "LEFT JOIN " . $dao->table_name . " ON " . $dao->table_name . ".entity_id = 
                c.id";
              $added_tables[] = $dao->table_name;
            }
            $where_fragment[] = $dao->column_name . ' = %' . $id;
            // Fixme - we should use the proper data type for each custom field
            $params[$id] = array($value, 'String');
            $id++;
          }
          else {
            // Handle non-custom fields (address fields)
1054 1055 1056
            // We only support primary address.
            $field_pieces = petitionemail_split_address_field($matching_field);
            $field_name = $field_pieces['field_name'];
1057 1058 1059 1060
            if(!in_array('civicrm_address', $added_tables)) {
              $from[] = "LEFT JOIN civicrm_address a ON a.contact_id = c.id";
              $added_tables[] = 'civicrm_address';
            }
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071

            // We have to make a special case for states, since the value we get
            // from the user is the abbreviation rather than the state_province_id
            // that is in the civicrm_address table.
            if($field_name == 'state_province') {
              if(!in_array('civicrm_state_province', $added_tables)) {
                $from[] = "LEFT JOIN civicrm_state_province sp ON a.state_province_id = sp.id";
                $added_tables[] = 'civicrm_state_province';
              }
              $field_name = 'sp.abbreviation';
            }
1072 1073
            $where_fragment[] = $field_name . ' = %' . $id;
            $where_fragment[] = 'a.is_primary = 1';
1074 1075 1076
            $params[$id] = array($value, 'String');
            $id++;
          }
1077
        }
1078
        $sub_where[] = '(' . implode(' AND ', $where_fragment) . ')';
1079
      }
1080 1081 1082 1083 1084 1085 1086
      else {
        // This is an error
      }
    }

    if(count($sub_where) > 0) {
      $where[] = '(' . implode(' OR ', $sub_where) . ')';
1087 1088 1089
    }

    // put it all together
1090
    $sql = "SELECT DISTINCT c.id, c.display_name ";
1091 1092
    $sql .= "FROM " . implode("\n", $from) . " ";
    $sql .= "WHERE " . implode(" AND\n", $where);
1093
    $dao = CRM_Core_DAO::executeQuery($sql, $params);
1094
    $location_type_id = $petition_vars['location_type_id'];
1095
    while($dao->fetch()) {
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
      // Lookup the best email address. 
      // ORDER BY FIELD allows us to arbitrarily set the location type id
      // we want to be set the highest.
      $sql = "SELECT e.email FROM civicrm_email e WHERE contact_id = %0 ".
        "AND (location_type_id = %1 OR is_primary = 1) ".
        "ORDER BY FIELD(e.location_type_id, %2) DESC, e.is_primary LIMIT 1";
      
      $email_params = array(
        0 => array($dao->id, 'Integer'),
        1 => array($petition_vars['location_type_id'], 'Integer'),
        2 => array($petition_vars['location_type_id'], 'Integer')
      );
      
      $email_dao = CRM_Core_DAO::executeQuery($sql, $email_params);
      $email_dao->fetch();
1111
      $ret[] = array(
1112
        'contact_id' => $dao->id,
1113
        'name' => $dao->display_name,
1114
        'email' => $email_dao->email
1115 1116 1117 1118 1119 1120
      );
    }
  }
  return $ret; 
}

1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142
/**
 * Split address field name
 * 
 * Field names in profiles are stored in the format
 * fieldname-locationame (e.g. postal_code-Primary).
 * This function breaks that string into the field name
 * and location name or returns FALSE if it's not a
 * location field.
 */
function petitionemail_split_address_field($field_name) {
  $ret = FALSE;
  if(preg_match('/([a-zA-Z0-9_]+)-([a-zA-Z0-9_]+)/', $field_name, $matches)) {
    if(!empty($matches[1]) && !empty($matches[2])) {
      $ret = array(
        'field_name' => $matches[1],
        'location_name' => $matches[2],
      );
    }
  }
  return $ret;
}

1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167
/**
 * Convert name + email line into name and email parts
 *
 * Thanks: http://www.regular-expressions.info/email.html
 */
function petitionemail_parse_email_line($line) {
  $ret = array();
  $recipient = trim($line);
  // First attempt to extract a valid email address
  if(preg_match('/([A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6})/i', $recipient, $matches)) {
    $email = $matches[1];
    // Now remove the matching email from the string, along with any <> characters
    $remainder = trim(str_replace(array($email, '>', '<'), '', $recipient)); 
    // Trim off any opening/closing quotes
    $name = trim($remainder, '"');
    $ret['name'] = $name;
    $ret['email'] = $email;
  }
  else {
    // Could not find an email address in there any where.
    $ret = FALSE;
  }
  return $ret;
}

1168 1169 1170 1171 1172 1173 1174
/**
 * Given an activity id, return the related petition id 
 *
 * Return FALSE if this is not an activity that is a petition
 * signature. 
 */
function petitionemail_get_petition_id_for_activity($activity_id) {
1175 1176 1177
  // If there is a related civicrm_petition_email record and it is the right
  // activity type, then we are good to go.  NOTE: source_record_id stores the
  // survey_id which is the same thing as the petition_id for our purposes.
1178 1179
  $sql = "SELECT a.source_record_id FROM civicrm_activity a JOIN
    civicrm_petition_email pe ON a.source_record_id = pe.petition_id
1180 1181 1182
    JOIN civicrm_option_value ov ON a.activity_type_id = ov.value 
    JOIN civicrm_option_group og ON ov.option_group_id = og.id 
    WHERE a.id = %0 AND og.name = 'activity_type' AND ov.name = 'Petition'";
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
  $params = array(0 => array($activity_id, 'Integer'));
  $dao = CRM_Core_DAO::executeQuery($sql, $params);
  $dao->fetch();
  if($dao->N == 0) return FALSE;
  return $dao->source_record_id; 
}

/**
 * Ensure activity_id should generate an email 
 *
 * Should have a related petition_email record and should have
 * a status of complete and should have a date.
 */
function petitionemail_is_actionable_activity($activity_id) {
  if(!petitionemail_get_petition_id_for_activity($activity_id)) {
    return FALSE;
1199
  }
1200 1201 1202 1203 1204 1205 1206
  $completed = CRM_Core_OptionGroup::getValue('activity_status', 'Completed', 'name');
  $sql = "SELECT id FROM civicrm_activity WHERE id = %0 AND status_id = %1";
  $params = array(0 => array($activity_id, 'Integer'), 1 => array($completed, 'Integer'));
  $dao = CRM_Core_DAO::executeQuery($sql, $params);
  $dao->fetch();
  if($dao->N == 0) return FALSE;
  return TRUE;
1207
}
1208

1209
/**
1210
 *  Provide profile parameters based on the keys passed. 
1211
 *
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
 * This function returns the parameters used to create profiles
 * in the petitionemail_get_profile_id function.
 * 
 **/
function petitionemail_get_profile_params($key) {
  $params = array();
  if($key == 'petitionemail_profile_matching_fields') {
    $description = ts('This profile controls which fields are available as
      matching fields when using the petition email extension. Please do
      not delete this profile.');
    $params = array(
      'name' => $key,
      'title' => ts('Petition Email Available Matching fields'),
      'description' => $description,
    );
  }
  elseif($key == 'petitionemail_profile_default_contact') {
    $description = ts('This profile was created by the petition email extension for use in petitions.');
    $params = array (
        'version' => 3,
        'name' => 'Petition_Email_Contact_Info',
        'title' => 'Petition Email Contact Info',
        'description' => $description,
        'is_active' => 1,
        'api.uf_field.create' => array(
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'postal_code',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'Zip Code',
            'field_type' => 'Contact',
          ),
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'state_province',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'State',
            'field_type' => 'Contact',
          ),
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'city',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'City',
            'field_type' => 'Contact',
          ),
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'street_address',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'Street Address',
            'field_type' => 'Contact',
          ),
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'email',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'Email',
            'field_type' => 'Contact',
          ),
          array(
            'uf_group_id' => '$value.id',
            'field_name' => 'last_name',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'Last Name',
            'field_type' => 'Individual',
          ),
           array(
            'uf_group_id' => '$value.id',
            'field_name' => 'first_name',
            'is_active' => 1,
            'is_required' => 1,
            'label' => 'First Name',
            'field_type' => 'Individual',
          ),
        )
      );
  }
  elseif($key == 'petitionemail_profile_default_activity') {
   // Lookup the custom field names we are supposed to use.
   $sql = "SELECT id FROM civicrm_custom_field WHERE name = 'Petition_Email_Custom_Subject'";
   $dao = CRM_Core_DAO::executeQuery($sql);
   $dao->fetch();
   if($dao->N == 0) {
     // The custom fields have not yet been created.
     return NULL;
   }
   $custom_subject_field = 'custom_' . $dao->id;  
   $sql = "SELECT id FROM civicrm_custom_field WHERE name = 'Petition_Email_Custom_Message'";
   $dao = CRM_Core_DAO::executeQuery($sql);
   $dao->fetch();
   if($dao->N == 0) {
     // The custom fields have not yet been created.
     return NULL;
   }
   $custom_message_field = 'custom_' . $dao->id;  

   $description = ts('This profile was created by the petition email extension for use in petitions.');
   $params = array (
     'version' => 3,
     'name' => 'Petition_Email_Activity_Fields',
     'title' => 'Petition Email Activity Fields',
     'description' => $description,
     'is_active' => 1,
     'api.uf_field.create' => array(
       array(
         'uf_group_id' => '$value.id',
         'field_name' => $custom_message_field,
         'is_active' => 1,
         'is_required' => 1,
         'label' => ts('Customize the message'),
1329
         'help_post' => ts('Your postal address will be automatically added to your message when it is sent.'),
1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
         'field_type' => 'Activity',
       ),
       array(
         'uf_group_id' => '$value.id',
         'field_name' => $custom_subject_field,
         'is_active' => 1,
         'is_required' => 1,
         'label' => ts('Customize the email subject'),
         'field_type' => 'Activity',
       ),
      )
    );
  }
  return $params;
}

/**
 * Helper function to ensure a profile is created.
1348 1349 1350 1351 1352 1353
 *
 * This function ensures that the profile is created and if not, it
 * creates it. 
 *
 * @return integer profile id 
 */
1354
function petitionemail_get_profile_id($key) {
1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
  $group = 'petitionemail';
  $ret = CRM_Core_BAO_Setting::getItem($group, $key);
  if(!empty($ret)) {
    // Ensure it exists
    $sql = "SELECT id FROM civicrm_uf_group WHERE id = %0";
    $dao = CRM_Core_DAO::executeQuery($sql, array(0 => array($ret, 'Integer')));
    $dao->fetch();
    if($dao->N == 1) {
      return $ret;
    }
    // Delete this variable - probably the user deleted the profile not knowing
    // what it was used for.
    $sql = "DELETE FROM civicrm_setting WHERE group_name = %0 AND name = %1";
    $params = array(
      0 => array($group, 'String'),
      1 => array($key, 'String')
    );
    CRM_Core_DAO::executeQuery($sql, $params);
  }

  // Create the profile
  // We have to manually set created_id if the current user is not set
  $session = CRM_Core_Session::singleton();
  $contact_id = $session->get('userID');
  if(empty($contact_id)) {
    // Maybe we are running via drush?
    // Try the contact associated with uid 1
    $contact_id = CRM_Core_BAO_UFMatch::getContactId(1);
    if(empty($contact_id)) {
      // Last ditch effort
      $sql = "SELECT MIN(id) FROM civicrm_contact WHERE is_active = 1 AND is_deleted = 0";
      $dao = CRM_Core_DAO::executeQuery($sql);
      $dao->fetch();
      $contact_id = $dao->id;
    }
  }

1392 1393 1394 1395 1396
  $params = petitionemail_get_profile_params($key);
  if(is_null($params)) return NULL;

  $params['created_id'] = $contact_id;
  
1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
  $results = civicrm_api3('UFGroup', 'create', $params);
  if($results['is_error'] != 0) {
    $session->setStatus(ts("Error creating the petition email profile group."));
    return FALSE;
  }
  $value = array_pop($results['values']);
  $id = $value['id'];

  CRM_Core_BAO_Setting::setItem($id, $group, $key);
  return $id;
}

1409 1410 1411 1412
/**
 * Remove any profiles we automatically created.
 */
function petitionemail_remove_profiles() {
1413 1414 1415 1416 1417
  $profiles_to_remove = array(
    'petitionemail_profile_matching_fields', 
    'petitionemail_profile_default_contact', 
    'petitionemail_profile_default_activity'
  );