Merge pull request #101 from colemanw/CRM-12054
[civicrm-core.git] / CRM / Campaign / BAO / Petition.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
26 */
27
28 /**
29 *
30 * @package CRM
31 * @copyright CiviCRM LLC (c) 2004-2013
32 * $Id$
33 *
34 */
35 Class CRM_Campaign_BAO_Petition extends CRM_Campaign_BAO_Survey {
36 function __construct() {
37 parent::__construct();
38 // expire cookie in one day
39 $this->cookieExpire = (1 * 60 * 60 * 24);
40 }
41
42 /**
43 * Function to get Petition Details for dashboard.
44 *
45 * @static
46 */
47 static function getPetitionSummary($params = array(
48 ), $onlyCount = FALSE) {
49 //build the limit and order clause.
50 $limitClause = $orderByClause = $lookupTableJoins = NULL;
51 if (!$onlyCount) {
52 $sortParams = array(
53 'sort' => 'created_date',
54 'offset' => 0,
55 'rowCount' => 10,
56 'sortOrder' => 'desc',
57 );
58 foreach ($sortParams as $name => $default) {
59 if (CRM_Utils_Array::value($name, $params)) {
60 $sortParams[$name] = $params[$name];
61 }
62 }
63
64 //need to lookup tables.
65 $orderOnPetitionTable = TRUE;
66 if ($sortParams['sort'] == 'campaign') {
67 $orderOnPetitionTable = FALSE;
68 $lookupTableJoins = '
69 LEFT JOIN civicrm_campaign campaign ON ( campaign.id = petition.campaign_id )';
70 $orderByClause = "ORDER BY campaign.title {$sortParams['sortOrder']}";
71 }
72 elseif ($sortParams['sort'] == 'activity_type') {
73 $orderOnPetitionTable = FALSE;
74 $lookupTableJoins = "
75 LEFT JOIN civicrm_option_value activity_type ON ( activity_type.value = petition.activity_type_id
76 OR petition.activity_type_id IS NULL )
77 INNER JOIN civicrm_option_group grp ON ( activity_type.option_group_id = grp.id AND grp.name = 'activity_type' )";
78 $orderByClause = "ORDER BY activity_type.label {$sortParams['sortOrder']}";
79 }
80 elseif ($sortParams['sort'] == 'isActive') {
81 $sortParams['sort'] = 'is_active';
82 }
83 if ($orderOnPetitionTable) {
84 $orderByClause = "ORDER BY petition.{$sortParams['sort']} {$sortParams['sortOrder']}";
85 }
86 $limitClause = "LIMIT {$sortParams['offset']}, {$sortParams['rowCount']}";
87 }
88
89 //build the where clause.
90 $queryParams = $where = array();
91
92 //we only have activity type as a
93 //difference between survey and petition.
94 $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name');
95 if ($petitionTypeID) {
96 $where[] = "( petition.activity_type_id = %1 )";
97 $queryParams[1] = array($petitionTypeID, 'Positive');
98 }
99 if (CRM_Utils_Array::value('title', $params)) {
100 $where[] = "( petition.title LIKE %2 )";
101 $queryParams[2] = array('%' . trim($params['title']) . '%', 'String');
102 }
103 if (CRM_Utils_Array::value('campaign_id', $params)) {
104 $where[] = '( petition.campaign_id = %3 )';
105 $queryParams[3] = array($params['campaign_id'], 'Positive');
106 }
107 $whereClause = NULL;
108 if (!empty($where)) {
109 $whereClause = ' WHERE ' . implode(" \nAND ", $where);
110 }
111
112 $selectClause = '
113 SELECT petition.id as id,
114 petition.title as title,
115 petition.is_active as is_active,
116 petition.result_id as result_id,
117 petition.is_default as is_default,
118 petition.campaign_id as campaign_id,
119 petition.activity_type_id as activity_type_id';
120
121 if ($onlyCount) {
122 $selectClause = 'SELECT COUNT(*)';
123 }
124 $fromClause = 'FROM civicrm_survey petition';
125
126 $query = "{$selectClause} {$fromClause} {$whereClause} {$orderByClause} {$limitClause}";
127
128 if ($onlyCount) {
129 return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams);
130 }
131
132 $petitions = array();
133 $properties = array(
134 'id',
135 'title',
136 'campaign_id',
137 'is_active',
138 'is_default',
139 'result_id',
140 'activity_type_id',
141 );
142
143 $petition = CRM_Core_DAO::executeQuery($query, $queryParams);
144 while ($petition->fetch()) {
145 foreach ($properties as $property) {
146 $petitions[$petition->id][$property] = $petition->$property;
147 }
148 }
149
150 return $petitions;
151 }
152
153 /**
154 * Get the petition count.
155 *
156 * @static
157 */
158 static function getPetitionCount() {
159 $whereClause = 'WHERE ( 1 )';
160 $queryParams = array();
161 $petitionTypeID = CRM_Core_OptionGroup::getValue('activity_type', 'petition', 'name');
162 if ($petitionTypeID) {
163 $whereClause = "WHERE ( petition.activity_type_id = %1 )";
164 $queryParams[1] = array($petitionTypeID, 'Positive');
165 }
166 $query = "SELECT COUNT(*) FROM civicrm_survey petition {$whereClause}";
167
168 return (int)CRM_Core_DAO::singleValueQuery($query, $queryParams);
169 }
170
171 /**
172 * takes an associative array and creates a petition signature activity
173 *
174 * @param array $params (reference ) an assoc array of name/value pairs
175 *
176 * @return object CRM_Campaign_BAO_Petition
177 * @access public
178 * @static
179 */
180 function createSignature(&$params) {
181 if (empty($params)) {
182 return;
183 }
184
185 if (!isset($params['sid'])) {
186 $statusMsg = ts('No survey sid parameter. Cannot process signature.');
187 CRM_Core_Session::setStatus($statusMsg, ts('Sorry'), 'error');
188 return;
189 }
190
191 if (isset($params['contactId'])) {
192
193 // add signature as activity with survey id as source id
194 // get the activity type id associated with this survey
195 $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo($params['sid']);
196
197 // create activity
198 // activity status id (from /civicrm/admin/optionValue?reset=1&action=browse&gid=25)
199 // 1-Schedule, 2-Completed
200
201 $activityParams = array(
202 'source_contact_id' => $params['contactId'],
203 'target_contact_id' => $params['contactId'],
204 'source_record_id' => $params['sid'],
205 'subject' => $surveyInfo['title'],
206 'activity_type_id' => $surveyInfo['activity_type_id'],
207 'activity_date_time' => date("YmdHis"),
208 'status_id' => $params['statusId'],
209 'activity_campaign_id' => $params['activity_campaign_id'],
210 );
211
212 //activity creation
213 // *** check for activity using source id - if already signed
214 $activity = CRM_Activity_BAO_Activity::create($activityParams);
215
216 // save activity custom data
217 if (CRM_Utils_Array::value('custom', $params) &&
218 is_array($params['custom'])
219 ) {
220 CRM_Core_BAO_CustomValueTable::store($params['custom'], 'civicrm_activity', $activity->id);
221 }
222
223 // set permanent cookie to indicate this petition already signed on the computer
224 setcookie('signed_' . $params['sid'], $activity->id, time() + $this->cookieExpire, '/');
225 }
226
227 return $activity;
228 }
229
230 function confirmSignature($activity_id, $contact_id, $petition_id) {
231 // change activity status to completed (status_id = 2)
232 // I wonder why do we need contact_id when we have activity_id anyway? [chastell]
233 $sql = 'UPDATE civicrm_activity SET status_id = 2 WHERE id = %1 AND source_contact_id = %2';
234 $params = array(1 => array($activity_id, 'Integer'), 2 => array($contact_id, 'Integer'));
235 CRM_Core_DAO::executeQuery($sql, $params);
236
237 // remove 'Unconfirmed' tag for this contact
238 $tag_name = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
239 'tag_unconfirmed',
240 NULL,
241 'Unconfirmed'
242 );
243
244 $sql = "
245 DELETE FROM civicrm_entity_tag
246 WHERE entity_table = 'civicrm_contact'
247 AND entity_id = %1
248 AND tag_id = ( SELECT id FROM civicrm_tag WHERE name = %2 )";
249 $params = array(1 => array($contact_id, 'Integer'),
250 2 => array($tag_name, 'String'),
251 );
252 CRM_Core_DAO::executeQuery($sql, $params);
253
254 // set permanent cookie to indicate this users email address now confirmed
255 setcookie("confirmed_{$petition_id}",
256 $activity_id,
257 time() + $this->cookieExpire,
258 '/'
259 );
260
261 return TRUE;
262 }
263
264 /**
265 * Function to get Petition Signature Total
266 *
267 * @param boolean $all
268 * @param int $id
269 * @static
270 */
271 static function getPetitionSignatureTotalbyCountry($surveyId) {
272 $countries = array();
273 $sql = "
274 SELECT count(civicrm_address.country_id) as total,
275 IFNULL(country_id,'') as country_id,IFNULL(iso_code,'') as country_iso, IFNULL(civicrm_country.name,'') as country
276 FROM civicrm_activity a, civicrm_survey, civicrm_contact
277 LEFT JOIN civicrm_address ON civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1
278 LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id
279 WHERE
280 a.source_contact_id = civicrm_contact.id AND
281 a.activity_type_id = civicrm_survey.activity_type_id AND
282 civicrm_survey.id = %1 AND
283 a.source_record_id = %1 ";
284
285 $params = array(1 => array($surveyId, 'Integer'));
286 $sql .= " GROUP BY civicrm_address.country_id";
287 $fields = array('total', 'country_id', 'country_iso', 'country');
288
289 $dao = CRM_Core_DAO::executeQuery($sql, $params);
290 while ($dao->fetch()) {
291 $row = array();
292 foreach ($fields as $field) {
293 $row[$field] = $dao->$field;
294 }
295 $countries[] = $row;
296 }
297 return $countries;
298 }
299
300 /**
301 * Function to get Petition Signature Total
302 *
303 * @param boolean $all
304 * @param int $id
305 * @static
306 */
307 static function getPetitionSignatureTotal($surveyId) {
308 $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo((int) $surveyId);
309 //$activityTypeID = $surveyInfo['activity_type_id'];
310 $signature = array();
311
312 $sql = "
313 SELECT
314 status_id,count(id) as total
315 FROM civicrm_activity
316 WHERE
317 source_record_id = " . (int) $surveyId . " AND activity_type_id = " . (int) $surveyInfo['activity_type_id'] . " GROUP BY status_id";
318
319 $statusTotal = array();
320 $total = 0;
321 $dao = CRM_Core_DAO::executeQuery($sql);
322 while ($dao->fetch()) {
323 $total += $dao->total;
324 $statusTotal['status'][$dao->status_id] = $dao->total;
325 }
326 $statusTotal['count'] = $total;
327 return $statusTotal;
328 }
329
330
331 public function getSurveyInfo($surveyId = NULL) {
332 $surveyInfo = array();
333
334 $sql = "
335 SELECT activity_type_id,
336 campaign_id,
337 s.title,
338 ov.label AS activity_type
339 FROM civicrm_survey s, civicrm_option_value ov, civicrm_option_group og
340 WHERE s.id = " . (int) $surveyId ."
341 AND s.activity_type_id = ov.value
342 AND ov.option_group_id = og.id
343 AND og.name = 'activity_type'";
344
345 $dao = CRM_Core_DAO::executeQuery($sql);
346 while ($dao->fetch()) {
347 //$survey['campaign_id'] = $dao->campaign_id;
348 //$survey['campaign_name'] = $dao->campaign_name;
349 $surveyInfo['activity_type'] = $dao->activity_type;
350 $surveyInfo['activity_type_id'] = $dao->activity_type_id;
351 $surveyInfo['title'] = $dao->title;
352 }
353
354 return $surveyInfo;
355 }
356
357 /**
358 * Function to get Petition Signature Details
359 *
360 * @param boolean $all
361 * @param int $id
362 * @static
363 */
364 static function getPetitionSignature($surveyId, $status_id = NULL) {
365
366 // sql injection protection
367 $surveyId = (int)$surveyId;
368 $signature = array();
369
370 $sql = "
371 SELECT a.id,
372 a.source_record_id as survey_id,
373 a.activity_date_time,
374 a.status_id,
375 civicrm_contact.id as contact_id,
376 civicrm_contact.contact_type,civicrm_contact.contact_sub_type,image_URL,
377 first_name,last_name,sort_name,
378 employer_id,organization_name,
379 household_name,
380 IFNULL(gender_id,'') AS gender_id,
381 IFNULL(state_province_id,'') AS state_province_id,
382 IFNULL(country_id,'') as country_id,IFNULL(iso_code,'') as country_iso, IFNULL(civicrm_country.name,'') as country
383 FROM civicrm_activity a, civicrm_survey, civicrm_contact
384 LEFT JOIN civicrm_address ON civicrm_address.contact_id = civicrm_contact.id AND civicrm_address.is_primary = 1
385 LEFT JOIN civicrm_country ON civicrm_address.country_id = civicrm_country.id
386 WHERE
387 a.source_contact_id = civicrm_contact.id AND
388 a.activity_type_id = civicrm_survey.activity_type_id AND
389 civicrm_survey.id = %1 AND
390 a.source_record_id = %1 ";
391
392 $params = array(1 => array($surveyId, 'Integer'));
393
394 if ($status_id) {
395 $sql .= " AND status_id = %2";
396 $params[2] = array($status_id, 'Integer');
397 }
398 $sql .= " ORDER BY a.activity_date_time";
399
400 $fields = array(
401 'id', 'survey_id', 'contact_id',
402 'activity_date_time', 'activity_type_id',
403 'status_id', 'first_name', 'last_name',
404 'sort_name', 'gender_id', 'country_id',
405 'state_province_id', 'country_iso', 'country',
406 );
407
408
409 $dao = CRM_Core_DAO::executeQuery($sql, $params);
410 while ($dao->fetch()) {
411 $row = array();
412 foreach ($fields as $field) {
413 $row[$field] = $dao->$field;
414 }
415 $signature[] = $row;
416 }
417 return $signature;
418 }
419
420 /**
421 * This function returns all entities assigned to a specific tag
422 *
423 * @param object $tag an object of a tag.
424 *
425 * @return array $contactIds array of contact ids
426 * @access public
427 */
428 function getEntitiesByTag($tag) {
429 $contactIds = array();
430 $entityTagDAO = new CRM_Core_DAO_EntityTag();
431 $entityTagDAO->tag_id = $tag['id'];
432 $entityTagDAO->find();
433
434 while ($entityTagDAO->fetch()) {
435 $contactIds[] = $entityTagDAO->entity_id;
436 }
437 return $contactIds;
438 }
439
440 /**
441 * Function to check if contact has signed this petition
442 *
443 * @param int $surveyId
444 * @param int $contactId
445 * @static
446 */
447 static function checkSignature($surveyId, $contactId) {
448
449 $surveyInfo = CRM_Campaign_BAO_Petition::getSurveyInfo($surveyId);
450 $signature = array();
451
452 $sql = "
453 SELECT a.id AS id,
454 a.source_record_id AS source_record_id,
455 a.source_contact_id AS source_contact_id,
456 a.activity_date_time AS activity_date_time,
457 a.activity_type_id AS activity_type_id,
458 a.status_id AS status_id,
459 %1 AS survey_title
460 FROM civicrm_activity a
461 WHERE a.source_record_id = %2
462 AND a.activity_type_id = %3
463 AND a.source_contact_id = %4
464 ";
465 $params = array(1 => array($surveyInfo['title'], 'String'),
466 2 => array($surveyId, 'Integer'),
467 3 => array($surveyInfo['activity_type_id'], 'Integer'),
468 4 => array($contactId, 'Integer'),
469 );
470
471 $dao = CRM_Core_DAO::executeQuery($sql, $params);
472 while ($dao->fetch()) {
473 $signature[$dao->id]['id'] = $dao->id;
474 $signature[$dao->id]['source_record_id'] = $dao->source_record_id;
475 $signature[$dao->id]['source_contact_id'] = CRM_Contact_BAO_Contact::displayName($dao->source_contact_id);
476 $signature[$dao->id]['activity_date_time'] = $dao->activity_date_time;
477 $signature[$dao->id]['activity_type_id'] = $dao->activity_type_id;
478 $signature[$dao->id]['status_id'] = $dao->status_id;
479 $signature[$dao->id]['survey_title'] = $dao->survey_title;
480 $signature[$dao->id]['contactId'] = $dao->source_contact_id;
481 }
482
483 return $signature;
484 }
485
486 /**
487 * takes an associative array and sends a thank you or email verification email
488 *
489 * @param array $params (reference ) an assoc array of name/value pairs
490 *
491 * @return
492 * @access public
493 * @static
494 */
495 function sendEmail($params, $sendEmailMode) {
496
497 /* sendEmailMode
498 * CRM_Campaign_Form_Petition_Signature::EMAIL_THANK
499 * connected user via login/pwd - thank you
500 * or dedupe contact matched who doesn't have a tag CIVICRM_TAG_UNCONFIRMED - thank you
501 * or login using fb connect - thank you + click to add msg to fb wall
502 *
503 * CRM_Campaign_Form_Petition_Signature::EMAIL_CONFIRM
504 * send a confirmation request email
505 */
506
507 // check if the group defined by CIVICRM_PETITION_CONTACTS exists, else create it
508 $petitionGroupName = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::SYSTEM_PREFERENCES_NAME,
509 'petition_contacts',
510 NULL,
511 'Petition Contacts'
512 );
513
514 $dao = new CRM_Contact_DAO_Group();
515 $dao->title = $petitionGroupName;
516 if (!$dao->find(TRUE)) {
517 $dao->is_active = 1;
518 $dao->visibility = 'Public Pages';
519 $dao->save();
520 }
521 $group_id = $dao->id;
522
523 // get petition info
524 $petitionParams['id'] = $params['sid'];
525 $petitionInfo = array();
526 CRM_Campaign_BAO_Survey::retrieve($petitionParams, $petitionInfo);
527 if (empty($petitionInfo)) {
528 CRM_Core_Error::fatal('Petition doesn\'t exist.');
529 }
530
531 //get the default domain email address.
532 list($domainEmailName, $domainEmailAddress) = CRM_Core_BAO_Domain::getNameAndEmail();
533
534 $emailDomain = CRM_Core_BAO_MailSettings::defaultDomain();
535
536 $toName = CRM_Contact_BAO_Contact::displayName($params['contactId']);
537
538 $replyTo = "do-not-reply@$emailDomain";
539
540 // set additional general message template params (custom tokens to use in email msg templates)
541 // tokens then available in msg template as {$petition.title}, etc
542 $petitionTokens['title'] = $petitionInfo['title'];
543 $petitionTokens['petitionId'] = $params['sid'];
544 $tplParams['petition'] = $petitionTokens;
545
546 switch ($sendEmailMode) {
547 case CRM_Campaign_Form_Petition_Signature::EMAIL_THANK:
548
549 // add this contact to the CIVICRM_PETITION_CONTACTS group
550 // Cannot pass parameter 1 by reference
551 $p = array($params['contactId']);
552 CRM_Contact_BAO_GroupContact::addContactsToGroup($p, $group_id, 'API');
553
554 if ($params['email-Primary']) {
555 CRM_Core_BAO_MessageTemplates::sendTemplate(
556 array(
557 'groupName' => 'msg_tpl_workflow_petition',
558 'valueName' => 'petition_sign',
559 'contactId' => $params['contactId'],
560 'tplParams' => $tplParams,
561 'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
562 'toName' => $toName,
563 'toEmail' => $params['email-Primary'],
564 'replyTo' => $replyTo,
565 'petitionId' => $params['sid'],
566 'petitionTitle' => $petitionInfo['title'],
567 )
568 );
569 }
570 break;
571
572 case CRM_Campaign_Form_Petition_Signature::EMAIL_CONFIRM:
573 // create mailing event subscription record for this contact
574 // this will allow using a hash key to confirm email address by sending a url link
575 $se = CRM_Mailing_Event_BAO_Subscribe::subscribe($group_id,
576 $params['email-Primary'],
577 $params['contactId']
578 );
579
580 // require_once 'CRM/Core/BAO/Domain.php';
581 // $domain = CRM_Core_BAO_Domain::getDomain();
582 $config = CRM_Core_Config::singleton();
583 $localpart = CRM_Core_BAO_MailSettings::defaultLocalpart();
584
585 $replyTo = implode($config->verpSeparator,
586 array(
587 $localpart . 'c',
588 $se->contact_id,
589 $se->id,
590 $se->hash,
591 )
592 ) . "@$emailDomain";
593
594
595 $confirmUrl = CRM_Utils_System::url('civicrm/petition/confirm',
596 "reset=1&cid={$se->contact_id}&sid={$se->id}&h={$se->hash}&a={$params['activityId']}&p={$params['sid']}",
597 TRUE
598 );
599 $confirmUrlPlainText = CRM_Utils_System::url('civicrm/petition/confirm',
600 "reset=1&cid={$se->contact_id}&sid={$se->id}&h={$se->hash}&a={$params['activityId']}&p={$params['sid']}",
601 TRUE,
602 NULL,
603 FALSE
604 );
605
606 // set email specific message template params and assign to tplParams
607 $petitionTokens['confirmUrl'] = $confirmUrl;
608 $petitionTokens['confirmUrlPlainText'] = $confirmUrlPlainText;
609 $tplParams['petition'] = $petitionTokens;
610
611 if ($params['email-Primary']) {
612 CRM_Core_BAO_MessageTemplates::sendTemplate(
613 array(
614 'groupName' => 'msg_tpl_workflow_petition',
615 'valueName' => 'petition_confirmation_needed',
616 'contactId' => $params['contactId'],
617 'tplParams' => $tplParams,
618 'from' => "\"{$domainEmailName}\" <{$domainEmailAddress}>",
619 'toName' => $toName,
620 'toEmail' => $params['email-Primary'],
621 'replyTo' => $replyTo,
622 'petitionId' => $params['sid'],
623 'petitionTitle' => $petitionInfo['title'],
624 'confirmUrl' => $confirmUrl,
625 )
626 );
627 }
628 break;
629 }
630 }
631 }
632