petitionemail.php 54.2 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 206
    }
    $choose_one = array('0' => ts('--choose one--'));
    $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
    $form->add('select', 'location_type_id', ts('Email'), $location_options);
234
    $form->add('textarea', 'recipients', ts("Send petitions to"), 'rows=20 cols=100');
235
    $form->add('select', 'message_field', ts('Custom Message Field'),
236 237 238
      $custom_field_options);
    $form->add('select', 'subject_field', ts('Custom Subject Field'),
      $custom_field_options);
239
    $form->add('textarea', 'default_message', ts('Default Message'), 'rows=20 cols=100');
240
    $form->add('text', 'subject', ts('Default Email Subject Line'), array('size' => 70));
241
    $form->add('textarea', 'links', ts('Links to sign the petition'), 'rows=5')->freeze();
242 243 244
  }
}

245 246 247 248 249
/**
 * Get fields from the special petition email profile.
 *
 * Filter out un-supported fields.
 */
250
function petitionemail_get_matching_field_options() {
251 252
  $session = CRM_Core_Session::singleton();
  $ret = array();
253
  $uf_group_id = petitionemail_get_profile_id('petitionemail_profile_matching_fields');
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
  $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."));
    }
  }
283
  
284 285 286
  return $ret;
}

287 288 289 290 291 292
/**
 * Validate the petition form
 *
 * Ensure our values are consistent to avoid broken petitions.
 */
function petitionemail_civicrm_validateForm($formName, &$fields, &$files, &$form, &$errors) {
293 294 295 296 297 298 299 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
  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.");
        }
      }
    }
  }

327 328
  if($formName == 'CRM_Campaign_Form_Petition') {
    if(CRM_Utils_Array::value('email_petition', $fields)) {
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
      // 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)) {
347
          $msg = ts("If you select a matching target group you must select
348 349 350 351 352 353 354 355 356 357 358 359
            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;
360
        }
361
        $i++;
362
      }
363

364 365 366 367 368 369 370 371 372 373 374 375
      // 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));
          }
        }
      }

376 377
      if(!$using_dynamic_method && empty($recipients)) {
        $msg = ts("You must select either one target matching group/field or list
378 379 380 381 382 383 384
          at least one address to send all petitions to.");
        $errors['recipients'] = $msg;
      }
    }
  }
}

385 386 387
/**
 * Given an array of profile ids, list all text area fields
 */
388
function petitionemail_get_text_fields($profile_ids) {
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
  // 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') {
413
            $custom_fields['custom_' . $id] = $label;
414 415 416 417 418 419 420 421 422
          }
        }
      }
    }
  }
  return $custom_fields;
}


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

    $default_message =  $form->_submitValues['default_message'];
451
    $message_field = $form->_submitValues['message_field'];
452
    $subject_field = $form->_submitValues['subject_field'];
453 454 455
    $subject = $form->_submitValues['subject'];
    $recipients = $form->_submitValues['recipients'];
    $location_type_id = $form->_submitValues['location_type_id'];
456

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

    $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++;
506
    }
507 508 509
  }
}

510 511 512 513
/**
 * Implementation of hook_civicrm_post
 *
 * Run everytime a post is made to see if it's a new profile/activity
514 515
 * that should trigger a petition email to be sent. Also clean up 
 * our tables if a petition is deleted.
516
 */
517
function petitionemail_civicrm_post( $op, $objectName, $objectId, &$objectRef ) {
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532
  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;
  }
533 534 535
  if ($objectName == 'Activity') {
    $activity_id = $objectId;

536
    // Only run on creation. For petitions that require a confirmation,
537 538 539
    // after the petition has been created, see petitionemail_civicrm_pageRun().
    if($op == 'create') {
      if(petitionemail_is_actionable_activity($activity_id)) {
540
        petitionemail_process_signature($activity_id, $profile_fields);
541 542
      }
    }
543
  }
544
}
545

546 547 548 549 550 551 552 553 554 555 556 557 558 559
/**
 * 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);
560 561 562
    }
  }
}
563

564 565
function petitionemail_get_petition_details($petition_id) {
  $ret = array();
Jamie McClelland's avatar
Jamie McClelland committed
566
  $sql = "SELECT default_message, 
567
               message_field, 
568
               subject_field,
569 570 571 572 573
               subject,
               location_type_id,
               recipients
         FROM civicrm_petition_email
         WHERE petition_id = %1 GROUP BY petition_id";
574
  $params = array( 1 => array( $petition_id, 'Integer' ) );
575 576
  $petition_email = CRM_Core_DAO::executeQuery( $sql, $params );
  $petition_email->fetch();
Jamie McClelland's avatar
Jamie McClelland committed
577
  if($petition_email->N == 0) {
578
    // Must not be a petition with a target.
Jamie McClelland's avatar
Jamie McClelland committed
579
    return FALSE;;
580
  }
581

582
  // Store variables we need
583 584 585 586
  $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;
587
  $ret['subject_field'] = $petition_email->subject_field;
588
  $ret['recipients'] = $petition_email->recipients;
589

590
  // Now retrieve the matching fields, if any
591 592
  $sql = "SELECT matching_field, matching_group_id FROM
    civicrm_petition_email_matching_field WHERE petition_id = %1";
593
  $params = array( 1 => array( $petition_id, 'Integer' ) );
594
  $dao = CRM_Core_DAO::executeQuery($sql, $params);
595
  $ret['matching'] = array();
596
  while($dao->fetch()) {
597
    $ret['matching'][$dao->matching_field] = $dao->matching_group_id;
598
  }
599 600 601
  return $ret;
}

602 603 604 605 606 607 608 609
/**
 * 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) {
610 611 612 613 614 615 616
  $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
617 618 619 620
  if(!$petition_vars) {
    // Nothing to process, this isn't an email target enabled petition
    return;
  }
621
  $default_message = $petition_vars['default_message'];
622
  $default_subject = $petition_vars['subject'];
623
  $message_field = $petition_vars['message_field'];
624
  $subject_field = $petition_vars['subject_field'];
625

626 627
  // Figure out whether to use the user-supplied message/subject or the default
  // message/subject.
628
  $petition_message = NULL;
629
  $subject = NULL;
630 631
  // If the petition has specified a message field
  if(!empty($message_field)) {
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
    // 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];
      }
649 650
    }
  } 
651 652 653 654
  if(is_null($petition_message)) {
    $petition_message = $default_message;
  }

655 656
  // If the petition has specified a subject field
  if(!empty($subject_field)) {
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
    // 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];
      }
674 675 676
    }
  }
  // No user supplied message/subject, use the default
677
  
678 679 680 681
  if(is_null($subject)) {
    $subject = $default_subject;
  }

682 683
  $activity = civicrm_api3("Activity", "getsingle", array ('id' => $activity_id));
  $contact_id = $activity['source_contact_id'];
Jamie McClelland's avatar
Jamie McClelland committed
684
  $contact = civicrm_api3("Contact", "getsingle", array ('id' => $contact_id));
685

Jamie McClelland's avatar
Jamie McClelland committed
686
  $from = NULL;
687
  if (empty($contact['email'])) {
688 689 690
    $domain = civicrm_api3("Domain", "get", array ());
    if ($domain['is_error'] != 0 || !is_array($domain['values'])) { 
      // Can't send email without a from address.
691 692
      $msg = "petition_email: Failed to send petition email because from
        address not sent.";
693 694 695
      CRM_Core_Error::debug_log_message($msg);
      return; 
    }
696
    $contact['email'] = $domain['values']['from_email'];
697
  }
698
  $from = $contact['display_name'] . ' <' . $contact['email'] . '>';
699 700 701 702 703 704

  // Setup email message (except to address)
  $email_params = array( 
    'from'    => $from,
    'toName'  => NULL,
    'toEmail' => NULL,
Jamie McClelland's avatar
Jamie McClelland committed
705
    'subject' => $subject,
706
    'text'    => $petition_message, 
707
    'html'    => NULL, 
708 709 710
  );

  // Get array of recipients
711
  $recipients = petitionemail_get_recipients($contact_id, $petition_id);
712 713 714
  // 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();
715 716
  while(list(, $recipient) = each($recipients)) {
    if(!empty($recipient['email'])) {
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
      $log = "petition email: contact id ($contact_id) sending to email (" .
        $recipient['email'] . ")";
      CRM_Core_Error::debug_log_message($log);
      if(!empty($recipient['contact_id'])) {
        // Since we're sending to a recipient in the database, create this
        // as an email activity so we record it properly.

        $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']);

        // Create/Send away.
        $ret = CRM_Activity_BAO_Activity::sendEmail(
          $contactDetails, $subject, $text, $html, $emailAddress, $userID,
          $from, $attachments, $cc, $bcc, $contactIds
        );
747

748 749 750
        $activity_id = array_pop($ret);
        $status = array_pop($ret);
        if($status === TRUE) {
751 752
          $to = $recipient['name'] . ' <' . $emailAddress . '>';
          CRM_Core_Session::setStatus( ts('Message sent successfully to: ') . htmlentities($to), '', 'success' );
753 754
          $log = "petition email: email sent successfully";
          CRM_Core_Error::debug_log_message($log);
755
          $message_sent_to[] = $to;
756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779

          // 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);
          }
        }
        else {
          $log = "petition email: failed to send email as activity.";
          CRM_Core_Error::debug_log_message($log);
          CRM_Core_Error::debug_log_message(print_r($ret, TRUE));
        }
      }
      else {
        // Handle targets not in the database.
        $email_params['toName'] = $recipient['name'];
        $email_params['toEmail'] = $recipient['email'];
780
        $to = $email_params['toName'] . ' <' . $email_params['toEmail'] . '>';
781 782 783 784 785 786 787

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

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

        if($success == 1) {
788
          CRM_Core_Session::setStatus( ts('Message sent successfully to: ') . htmlentities($to), '', 'success' );
789
          $log = "petition_email: message sent.";
790
          $message_sent_to[] = $to;
791 792 793 794
        } else {
          $log = "petition_email: message was not sent.";
        }
        CRM_Core_Error::debug_log_message($log);
795 796 797
      }
    }
  }
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
  // Now send a copy to the petition signer, that tells them who it was
  // sent to.
  $prepend_msg = ts("Below is a copy of your message. It was sent to the following people.") . "\n\n" .
    implode("\n", $message_sent_to);

  // Modify our email_params to send to the petition signer.
  $email_params['toEmail'] = $contact['email'];
  $email_params['toName'] = $contact['display_name'];
  $email_params['text'] = $prepend_msg . "\n\n---------\n\n" . $email_params['text'];

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

  if($success == 1) {
    $log = "petition_email: message sent to petition signer.";
  } else {
    $log = "petition_email: message not sent to petition signer.";
  }
  CRM_Core_Error::debug_log_message($log);
816 817
}
 
818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
/**
 * 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',
    'state_province_id' => 'civicrm_address',
    'postal_code' => 'civicrm_address',
    'postal_code_suffix' => 'civicrm_address',
    'country_id' => 'civicrm_address',
  );
  return $ret;
}

840 841
function petitionemail_get_recipients($contact_id, $petition_id) {
  $petition_vars = petitionemail_get_petition_details($petition_id);
Jamie McClelland's avatar
Jamie McClelland committed
842 843 844 845
  if(!$petition_vars) {
    // Not an email target enabled petition
    return;
  }
846 847 848 849 850 851 852 853 854
  $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(
855
          'contact_id' => NULL,
856 857 858 859 860 861
          'name' => $email_parts['name'],
          'email' => $email_parts['email']
        );
      }
    }
  }
862 863 864
  // 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
865
  if(count($petition_vars['matching']) > 0) {
866 867 868 869
    // 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'];

870 871 872
    // 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.
873 874 875 876 877 878

    // 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.
879
    $field_names = array_keys($matching_fields);
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
    $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;
        }
      }
903
      // FIXME If we get here, this is an error
904 905
    }
    $contact_params = array('return' => $return_fields, 'id' => $contact_id);
906 907
    $contact = civicrm_api3('Contact', 'getsingle', $contact_params);
    while(list($matching_field) = each($matching_fields)) {
908 909 910 911 912 913 914 915
      // 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) {
916
        // FIXME This is an error
917 918 919 920 921 922 923
        continue;
      }
      $location_name = $field_pieces['location_name'];
      $field_name = $field_pieces['field_name'];
      if($location_name == 'Primary' && array_key_exists($field_name, $contact)) {
        // We have to unset the field that was saved as fieldname-locatiname
        unset($matching_fields[$matching_field]);
924

925 926 927 928 929 930
        // And now set the proper key
        $matching_field = $field_name;
        $matching_fields[$matching_field] = $contact[$matching_field];
        continue;
      }
      else {
931
        // FIXME This is an error
932 933 934
        continue;
      }
    } 
935 936

    // Initialize variables to build the SQL statement
937
    $from = array();
938 939
    // The master $where clause will be put together using AND
    $where = array();
940
    $params = array();
941
    $added_tables = array();
942

943 944
    // Initialize the from clause
    $from[] = 'civicrm_contact c';
945

946 947 948 949 950
    // 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();
951
    reset($matching_fields);
952
    $id = 0;
953
    while(list($matching_field, $value) = each($matching_fields)) {
954 955 956 957 958 959 960 961 962 963 964 965 966 967
      // 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
968
            $from[] = 'LEFT JOIN civicrm_group_contact_cache cc ON
969 970 971 972 973 974
              c.id = cc.contact_id';
            $added_tables[] = 'civicrm_group_contact_cache';
          }
          $where_fragment[] = 'cc.group_id = %' . $id;
          $params[$id] = array($group_id, 'Integer');
          $id++;
975 976
        }
        else {
977
          if(!in_array('civicrm_group_contact', $added_tables)) {
Jamie McClelland's avatar
Jamie McClelland committed
978
            $from[] = 'LEFT JOIN civicrm_group_contact gc ON
979 980 981 982 983 984 985
              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++;
986
        }
987 988 989 990 991
      
        // Now add in the matching field
        if(empty($value)) {
          // We should never match in this case
          $where_fragment[] = "(0)";
992 993
        }
        else {
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
          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)
            if(!in_array('civicrm_address', $added_tables)) {
              $from[] = "LEFT JOIN civicrm_address a ON a.contact_id = c.id";
              $added_tables[] = 'civicrm_address';
            }
            $field_where[] = '(' . $matching_field . ' = %' . $id . ')';
            $params[$id] = array($value, 'String');
            $id++;
          }
1021
        }
1022
        $sub_where[] = '(' . implode(' AND ', $where_fragment) . ')';
1023
      }
1024 1025 1026 1027 1028 1029 1030
      else {
        // This is an error
      }
    }

    if(count($sub_where) > 0) {
      $where[] = '(' . implode(' OR ', $sub_where) . ')';
1031 1032 1033
    }

    // put it all together
1034
    $sql = "SELECT DISTINCT c.id, c.display_name ";
1035 1036
    $sql .= "FROM " . implode("\n", $from) . " ";
    $sql .= "WHERE " . implode(" AND\n", $where);
1037
    $dao = CRM_Core_DAO::executeQuery($sql, $params);
1038
    $location_type_id = $petition_vars['location_type_id'];
1039
    while($dao->fetch()) {
1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054
      // 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();
1055
      $ret[] = array(
1056
        'contact_id' => $dao->id,
1057
        'name' => $dao->display_name,
1058
        'email' => $email_dao->email
1059 1060 1061 1062 1063 1064
      );
    }
  }
  return $ret; 
}

1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
/**
 * 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;
}

1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
/**
 * 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;
}

1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
/**
 * 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) {
  // If there is a related civicrm_petition_email record, 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.
  $sql = "SELECT a.source_record_id FROM civicrm_activity a JOIN
    civicrm_petition_email pe ON a.source_record_id = pe.petition_id
    WHERE a.id = %0";
  $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;
1141
  }
1142 1143 1144 1145 1146 1147 1148
  $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;
1149
}
1150

1151
/**
1152
 *  Provide profile parameters based on the keys passed. 
1153
 *
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 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
 * 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'),
         '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.
1289 1290 1291 1292 1293 1294
 *
 * This function ensures that the profile is created and if not, it
 * creates it. 
 *
 * @return integer profile id 
 */
1295
function petitionemail_get_profile_id($key) {
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 1329 1330 1331 1332
  $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;
    }
  }

1333 1334 1335 1336 1337
  $params = petitionemail_get_profile_params($key);
  if(is_null($params)) return NULL;

  $params['created_id'] = $contact_id;
  
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
  $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;
}

1350 1351 1352 1353
/**
 * Remove any profiles we automatically created.
 */
function petitionemail_remove_profiles() {
1354 1355 1356 1357 1358
  $profiles_to_remove = array(
    'petitionemail_profile_matching_fields', 
    'petitionemail_profile_default_contact', 
    'petitionemail_profile_default_activity'
  );
1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
  while(list(,$key) = each($profiles_to_remove)) {
    $group = 'petitionemail';
    $ret = CRM_Core_BAO_Setting::getItem($group, $key);
    if($ret) {
      // Get a list of existing profile fields and remove those 
      // first.
      $params = array(
        'uf_group_id' => $ret,
        'return' => array('id')
      );
      $results = civicrm_api3('UFField', 'get', $params);
      if(is_array($results['values'])) {
        while(list($id) = each($results['values'])) {
          $params = array('id' => $id);
          civicrm_api3('UFField', 'delete', $params);
        }
      }
      $params = array('id' => $ret);
      civicrm_api3('UFGroup', 'delete', $params);
    }
  }
}

1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
/**
 * Remove any custom fields we automatically created.
 */
function petitionemail_remove_custom_fields() {
  $groups_to_remove = array(
    'petitionemail_custom_message_fields'
  );
  while(list(,$key) = each($groups_to_remove)) {
    $group = 'petitionemail';
    $ret = CRM_Core_BAO_Setting::getItem($group, $key);
    if($ret) {
      // Get a list of existing profile fields and remove those 
      // first.
      $params = array(
        'custom_group_id' => $ret,
        'return' => array('id')
      );
      $results = civicrm_api3('CustomField', 'get', $params);
      if(is_array($results['values'])) {
        while(list($id) = each($results['values'])) {
          $params = array('id' => $id);
          civicrm_api3('CustomField', 'delete', $params);
        }
      }
      $params = array('id' => $ret);
      civicrm_api3('CustomGroup', 'delete', $params);
    }
  }
}
/**
 * Create the custom fields used to record subject and body
 *
 */
function petitionemail_create_custom_fields() {
  $group = 'petitionemail';
  $key = 'petitionemail_custom_message_fields';
  $ret = CRM_Core_BAO_Setting::getItem($group, $key);
  if(!empty($ret)) {
    // Ensure it exists
    $sql = "SELECT id FROM civicrm_custom_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);
  }
  // Get the value of the petition activity id so our custom group
  // will only extend Activities of type Petition.
  $sql = "SELECT v.value FROM civicrm_option_group g JOIN 
    civicrm_option_value v ON g.id = v.option_group_id WHERE g.name = 'activity_type'
    AND v.name = 'petition'";
  $dao = CRM_Core_DAO::executeQuery($sql);
  $dao->fetch();
  if($dao->N > 0) {
    $activity_type_id = $dao->value;
    $params = array (
      'version' => 3,
      'name' => 'PetitionEmailMessageFields',
      'title' => 'Petition Email Message Fields',
      'extends' => 'Activity',
      'extends_entity_column_value' => array($activity_type_id),
      'style' => 'Inline',
      'collapse_display' => 1,
      'is_active' => 1,
      'api.custom_field.create' => array(
        array(
          'custom_group_id' => '$value.id',
          'label' => 'Custom Message',
          'name' => 'Petition_Email_Custom_Message',
          'data_type' => 'String',
          'html_type' => 'TextArea',
          'is_required' => 0,
          'is_searchable' => 0,
          'is_active' => 1,
        ),
        array(
          'custom_group_id' => '$value.id',
          'label' => 'Custom Subject',
          'name' => 'Petition_Email_Custom_Subject',
          'data_type' => 'String',
          'html_type' => 'Text',
          'is_required' => 0,
          'is_searchable' => 0,
          'is_active' => 1,
        ),
        
      ),
    );
    try {
      $results = civicrm_api3('CustomGroup', 'create', $params);
    }
    catch (CiviCRM_API3_Exception $e) {
      $session = CRM_Core_Session::singleton();
      $session->setStatus(ts("Error creating the petition custom fields."));
      $session->setStatus($e->getMessage());
      return FALSE;
    }
    $values = array_pop($results['values']);
    $id = $values['id'];
    CRM_Core_BAO_Setting::setItem($id, $group, $key);
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504

    // Start complex process for clearing the cache of available fields. 
    // We need to clear the cache so that when we create a profile that
    // depends on these fields, we won't get an error that it's an invalid field.

    // First clear the static array of exportableFields which is used to determine
    // if a field is valid when being used in a profile.
    CRM_Activity_BAO_Activity::$_exportableFields = NULL;

    // Next clear the cache so we don't pull from an already populated cache.
    CRM_Utils_System::flushCache();

    // Lastly, we have to call the function that is called to validate fields,
    // but specifying that we want to force the re-fecthing of fields to unset
    // yet another static variable.
1505
    CRM_Core_BAO_UFField::getAvailableFieldsFlat(TRUE);
1506 1507

    return $id;
1508
  }
1509
  return FALSE;
1510 1511
}

1512 1513 1514 1515
/**
 * Helper to remove any extension created variables
 */
function petitionemail_remove_variables() {
1516
  $group = 'petitionemail';
1517 1518 1519 1520 1521 1522
  $sql = "DELETE FROM civicrm_setting WHERE group_name = %0";
  $params = array(
    0 => array($group, 'String')
  );
  CRM_Core_DAO::executeQuery($sql, $params);
}