Merge branch '4.6' into master
[civicrm-core.git] / CRM / Campaign / Form / Petition / Signature.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
7e9e8871 4 | CiviCRM version 4.7 |
6a488035 5 +--------------------------------------------------------------------+
e7112fa7 6 | Copyright CiviCRM LLC (c) 2004-2015 |
6a488035
TO
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 +--------------------------------------------------------------------+
d25dd0ee 26 */
6a488035
TO
27
28/**
29 *
30 * @package CRM
e7112fa7 31 * @copyright CiviCRM LLC (c) 2004-2015
6a488035
TO
32 */
33
34/**
ce064e4f 35 * This class generates form components for processing a petition signature.
6a488035
TO
36 */
37class CRM_Campaign_Form_Petition_Signature extends CRM_Core_Form {
7da04cde 38 const EMAIL_THANK = 1, EMAIL_CONFIRM = 2, MODE_CREATE = 4;
6a488035
TO
39
40 protected $_mode;
41
42 /**
100fef9d 43 * The id of the contact associated with this signature
6a488035
TO
44 *
45 * @var int
6a488035
TO
46 */
47 public $_contactId;
48
49 /**
50 * Is this a logged in user
51 *
52 * @var int
53 */
54 protected $_loggedIn = FALSE;
55
56 /**
57 * The contact type
58 *
353ffa53 59 * @var string ("Individual"/"Household"/"Organization"). Never been tested for something else than Individual
6a488035
TO
60 */
61 protected $_ctype = 'Individual';
62
63 /**
64 * The contact profile id attached with this petition
65 *
66 * @var int
67 */
68 protected $_contactProfileId;
69
70 /**
100fef9d 71 * The contact profile fields used for this petition
6a488035
TO
72 *
73 * @var array
74 */
75 public $_contactProfileFields;
76
77 /**
78 * The activity profile id attached with this petition
79 *
80 * @var int
81 */
82 protected $_activityProfileId;
83
84 /**
100fef9d 85 * The activity profile fields used for this petition
6a488035
TO
86 *
87 * @var array
88 */
89 public $_activityProfileFields;
90
91 /**
100fef9d 92 * The id of the survey (petition) we are proceessing
6a488035
TO
93 *
94 * @var int
6a488035
TO
95 */
96 public $_surveyId;
97
98 /**
99 * The tag id used to set against contacts with unconfirmed email
100 *
101 * @var int
102 */
103 protected $_tagId;
104
105 /**
100fef9d 106 * Values to use for custom profiles
6a488035
TO
107 *
108 * @var array
6a488035
TO
109 */
110 public $_values;
111
112 /**
113 * The params submitted by the form
114 *
115 * @var array
6a488035
TO
116 */
117 protected $_params;
118
119 /**
100fef9d 120 * Which email send mode do we use
6a488035
TO
121 *
122 * @var int
123 * EMAIL_THANK = 1,
124 * connected user via login/pwd - thank you
125 * or dedupe contact matched who doesn't have a tag CIVICRM_TAG_UNCONFIRMED - thank you
126 * or login using fb connect - thank you + click to add msg to fb wall
127 * EMAIL_CONFIRM = 2;
128 * send a confirmation request email
129 */
130 protected $_sendEmailMode;
131
132 protected $_image_URL;
133
30c4e065 134 /**
30c4e065 135 */
00be9182 136 public function __construct() {
6a488035
TO
137 parent::__construct();
138 // this property used by civicrm_fb module and if true, forces thank you email to be sent
139 // for users signing in via Facebook connect; also sets Fb email to check against
140 $this->forceEmailConfirmed['flag'] = FALSE;
141 $this->forceEmailConfirmed['email'] = '';
142 }
143
30c4e065
EM
144 /**
145 * @return mixed
146 */
00be9182 147 public function getContactID() {
6a488035
TO
148 $tempID = CRM_Utils_Request::retrieve('cid', 'Positive', $this);
149
150 // force to ignore the authenticated user
151 if ($tempID === '0') {
152 return $tempID;
153 }
154
155 //check if this is a checksum authentication
156 $userChecksum = CRM_Utils_Request::retrieve('cs', 'String', $this);
157 if ($userChecksum) {
158 //check for anonymous user.
159 $validUser = CRM_Contact_BAO_Contact_Utils::validChecksum($tempID, $userChecksum);
160 if ($validUser) {
161 return $tempID;
162 }
163 }
164
165 // check if the user is registered and we have a contact ID
166 $session = CRM_Core_Session::singleton();
167 return $session->get('userID');
168 }
169
170 public function preProcess() {
171 $this->bao = new CRM_Campaign_BAO_Petition();
172 $this->_mode = self::MODE_CREATE;
173
174 //get the survey id
175 $this->_surveyId = CRM_Utils_Request::retrieve('sid', 'Positive', $this);
176
177 //some sanity checks
178 if (!$this->_surveyId) {
179 CRM_Core_Error::fatal('Petition id is not valid. (it needs a "sid" in the url).');
180 return;
181 }
182 //check petition is valid and active
183 $params['id'] = $this->_surveyId;
184 $this->petition = array();
185 CRM_Campaign_BAO_Survey::retrieve($params, $this->petition);
186 if (empty($this->petition)) {
187 CRM_Core_Error::fatal('Petition doesn\'t exist.');
188 }
189 if ($this->petition['is_active'] == 0) {
190 CRM_Core_Error::fatal('Petition is no longer active.');
191 }
192
193 //get userID from session
194 $session = CRM_Core_Session::singleton();
195
196 //get the contact id for this user if logged in
197 $this->_contactId = $this->getContactId();
198 if (isset($this->_contactId)) {
199 $this->_loggedIn = TRUE;
200 }
201
202 // add the custom contact and activity profile fields to the signature form
203
204 $ufJoinParams = array(
205 'entity_id' => $this->_surveyId,
206 'entity_table' => 'civicrm_survey',
207 'module' => 'CiviCampaign',
208 'weight' => 2,
209 );
210
211 $this->_contactProfileId = CRM_Core_BAO_UFJoin::findUFGroupId($ufJoinParams);
212 if ($this->_contactProfileId) {
213 $this->_contactProfileFields = CRM_Core_BAO_UFGroup::getFields($this->_contactProfileId, FALSE, CRM_Core_Action::ADD);
214 }
215 if (!isset($this->_contactProfileFields['email-Primary'])) {
216 CRM_Core_Error::fatal('The contact profile needs to contain the primary email address field');
217 }
218
6a488035
TO
219 $ufJoinParams['weight'] = 1;
220 $this->_activityProfileId = CRM_Core_BAO_UFJoin::findUFGroupId($ufJoinParams);
221
222 if ($this->_activityProfileId) {
223 $this->_activityProfileFields = CRM_Core_BAO_UFGroup::getFields($this->_activityProfileId, FALSE, CRM_Core_Action::ADD);
224 }
225
226 $this->setDefaultValues();
227 CRM_Utils_System::setTitle($this->petition['title']);
228 }
229
230 /**
c490a46a 231 * Set default values for the form.
6a488035 232 */
00be9182 233 public function setDefaultValues() {
6a488035
TO
234 $this->_defaults = array();
235 if ($this->_contactId) {
236 CRM_Core_BAO_UFGroup::setProfileDefaults($this->_contactId, $this->_contactProfileFields, $this->_defaults, TRUE);
237 if ($this->_activityProfileId) {
238 CRM_Core_BAO_UFGroup::setProfileDefaults($this->_contactId, $this->_activityProfileFields, $this->_defaults, TRUE);
239 }
240 }
241
242 //set custom field defaults
243
244 foreach ($this->_contactProfileFields as $name => $field) {
245 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
246 $htmlType = $field['html_type'];
247
248 if (!isset($this->_defaults[$name])) {
249 CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID,
250 $name,
251 $this->_defaults,
252 $this->_contactId,
253 $this->_mode
254 );
255 }
256 }
257 }
258
259 if ($this->_activityProfileFields) {
260 foreach ($this->_activityProfileFields as $name => $field) {
261 if ($customFieldID = CRM_Core_BAO_CustomField::getKeyID($name)) {
262 $htmlType = $field['html_type'];
263
264 if (!isset($this->_defaults[$name])) {
265 CRM_Core_BAO_CustomField::setProfileDefaults($customFieldID,
266 $name,
267 $this->_defaults,
268 $this->_contactId,
269 $this->_mode
270 );
271 }
272 }
273 }
274 }
275
276 $this->setDefaults($this->_defaults);
277 }
278
279 public function buildQuickForm() {
280 $this->assign('survey_id', $this->_surveyId);
281 $this->assign('petitionTitle', $this->petition['title']);
282 if (isset($_COOKIE['signed_' . $this->_surveyId])) {
283 if (isset($_COOKIE['confirmed_' . $this->_surveyId])) {
284 $this->assign('duplicate', "confirmed");
285 }
286 else {
287 $this->assign('duplicate', "unconfirmed");
288 }
289 return;
290 }
291
292 $this->applyFilter('__ALL__', 'trim');
293
294 $this->buildCustom($this->_contactProfileId, 'petitionContactProfile');
295 if ($this->_activityProfileId) {
296 $this->buildCustom($this->_activityProfileId, 'petitionActivityProfile');
297 }
298 // add buttons
299 $this->addButtons(array(
300 array(
301 'type' => 'next',
302 'name' => ts('Sign the Petition'),
303 'isDefault' => TRUE,
304 ),
305 )
306 );
307 }
308
309 /**
dc195289 310 * add the rules (mainly global rules) for form.
6a488035
TO
311 * All local rules are added near the element
312 *
da6b46f4
EM
313 * @param $fields
314 * @param $files
315 * @param $errors
316 *
6a488035 317 * @see valid_date
ce064e4f 318 * @return array|bool
6a488035 319 */
00be9182 320 public static function formRule($fields, $files, $errors) {
6a488035
TO
321 $errors = array();
322
323 return empty($errors) ? TRUE : $errors;
324 }
325
326 /**
fe482240 327 * Form submission of petition signature.
6a488035
TO
328 */
329 public function postProcess() {
330 $tag_name = CRM_Core_BAO_Setting::getItem(CRM_Core_BAO_Setting::CAMPAIGN_PREFERENCES_NAME,
331 'tag_unconfirmed'
332 );
333
6a488035
TO
334 if ($tag_name) {
335 // Check if contact 'email confirmed' tag exists, else create one
336 // This should be in the petition module initialise code to create a default tag for this
337 $tag_params['name'] = $tag_name;
338 $tag_params['version'] = 3;
339 $tag = civicrm_api('tag', 'get', $tag_params);
340 if ($tag['count'] == 0) {
341 //create tag
342 $tag_params['description'] = $tag_name;
343 $tag_params['is_reserved'] = 1;
344 $tag_params['used_for'] = 'civicrm_contact';
345 $tag = civicrm_api('tag', 'create', $tag_params);
346 }
347 $this->_tagId = $tag['id'];
348 }
349
350 // export the field values to be used for saving the profile form
351 $params = $this->controller->exportValues($this->_name);
352
353 $session = CRM_Core_Session::singleton();
354 // format params
355 $params['last_modified_id'] = $session->get('userID');
356 $params['last_modified_date'] = date('YmdHis');
357
358 if ($this->_action & CRM_Core_Action::ADD) {
359 $params['created_id'] = $session->get('userID');
360 $params['created_date'] = date('YmdHis');
361 }
362
363 if (isset($this->_surveyId)) {
364 $params['sid'] = $this->_surveyId;
365 }
366
367 if (isset($this->_contactId)) {
368 $params['contactId'] = $this->_contactId;
369 }
370
371 // if logged in user, skip dedupe
372 if ($this->_loggedIn) {
373 $ids[0] = $this->_contactId;
374 }
375 else {
376 // dupeCheck - check if contact record already exists
377 // code modified from api/v2/Contact.php-function civicrm_contact_check_params()
378 $params['contact_type'] = $this->_ctype;
379 //TODO - current dedupe finds soft deleted contacts - adding param is_deleted not working
380 // ignore soft deleted contacts
381 //$params['is_deleted'] = 0;
382 $dedupeParams = CRM_Dedupe_Finder::formatParams($params, $params['contact_type']);
383 $dedupeParams['check_permission'] = '';
384
385 //dupesByParams($params, $ctype, $level = 'Unsupervised', $except = array())
386 $ids = CRM_Dedupe_Finder::dupesByParams($dedupeParams, $params['contact_type']);
387 }
388
353ffa53
TO
389 $petition_params['id'] = $this->_surveyId;
390 $petition = array();
391 CRM_Campaign_BAO_Survey::retrieve($petition_params, $petition);
6a488035
TO
392
393 switch (count($ids)) {
394 case 0:
395 //no matching contacts - create a new contact
396 // Add a source for this new contact
397 $params['source'] = ts('Petition Signature') . ' ' . $this->petition['title'];
398
399 if ($this->petition['bypass_confirm']) {
400 // send thank you email directly, bypassing confirmation
401 $this->_sendEmailMode = self::EMAIL_THANK;
402 // Set status for signature activity to completed
403 $params['statusId'] = 2;
404 }
405 else {
353ffa53 406 $this->_sendEmailMode = self::EMAIL_CONFIRM;
6a488035 407
353ffa53
TO
408 // Set status for signature activity to scheduled until email is verified
409 $params['statusId'] = 1;
6a488035
TO
410 }
411 break;
412
413 case 1:
414 $this->_contactId = $params['contactId'] = $ids[0];
415
416 // check if user has already signed this petition - redirects to Thank You if true
417 $this->redirectIfSigned($params);
418
419 if ($this->petition['bypass_confirm']) {
420 // send thank you email directly, bypassing confirmation
421 $this->_sendEmailMode = self::EMAIL_THANK;
422 // Set status for signature activity to completed
423 $params['statusId'] = 2;
424 break;
425 }
426
427 // dedupe matched single contact, check for 'unconfirmed' tag
428 if ($tag_name) {
353ffa53 429 $tag = new CRM_Core_DAO_EntityTag();
6a488035 430 $tag->entity_id = $this->_contactId;
353ffa53 431 $tag->tag_id = $this->_tagId;
6a488035
TO
432
433 if (!($tag->find())) {
434 // send thank you email directly, the user is known and validated
435 $this->_sendEmailMode = self::EMAIL_THANK;
436 // Set status for signature activity to completed
437 $params['statusId'] = 2;
438 }
439 else {
440 // send email verification email
441 $this->_sendEmailMode = self::EMAIL_CONFIRM;
442 // Set status for signature activity to scheduled until email is verified
443 $params['statusId'] = 1;
444 }
445 }
446 break;
447
448 default:
449 // more than 1 matching contact
450 // for time being, take the first matching contact (not sure that's the best strategy, but better than creating another duplicate)
451 $this->_contactId = $params['contactId'] = $ids[0];
452
453 // check if user has already signed this petition - redirects to Thank You if true
454 $this->redirectIfSigned($params);
455
456 if ($this->petition['bypass_confirm']) {
457 // send thank you email directly, bypassing confirmation
458 $this->_sendEmailMode = self::EMAIL_THANK;
459 // Set status for signature activity to completed
460 $params['statusId'] = 2;
461 break;
462 }
463
464 if ($tag_name) {
353ffa53 465 $tag = new CRM_Core_DAO_EntityTag();
6a488035 466 $tag->entity_id = $this->_contactId;
353ffa53 467 $tag->tag_id = $this->_tagId;
6a488035
TO
468
469 if (!($tag->find())) {
470 // send thank you email
471 $this->_sendEmailMode = self::EMAIL_THANK;
472 // Set status for signature activity to completed
473 $params['statusId'] = 2;
474 }
475 else {
476 // send email verification email
477 $this->_sendEmailMode = self::EMAIL_CONFIRM;
478 // Set status for signature activity to scheduled until email is verified
479 $params['statusId'] = 1;
480 }
481 }
482 break;
483 }
484
6a488035
TO
485 $transaction = new CRM_Core_Transaction();
486
487 $addToGroupID = isset($this->_addToGroupID) ? $this->_addToGroupID : NULL;
488 $this->_contactId = CRM_Contact_BAO_Contact::createProfileContact($params, $this->_contactProfileFields,
489 $this->_contactId, $addToGroupID,
490 $this->_contactProfileId, $this->_ctype,
491 TRUE
492 );
493
494 // get additional custom activity profile field data
495 // to save with new signature activity record
496 $surveyInfo = $this->bao->getSurveyInfo($this->_surveyId);
497 $customActivityFields = CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE,
498 $surveyInfo['activity_type_id']
499 );
500 $customActivityFields = CRM_Utils_Array::crmArrayMerge($customActivityFields,
501 CRM_Core_BAO_CustomField::getFields('Activity', FALSE, FALSE,
502 NULL, NULL, TRUE
503 )
504 );
505
506 $params['custom'] = CRM_Core_BAO_CustomField::postProcess($params,
6a488035
TO
507 NULL,
508 'Activity'
509 );
510
511 // create the signature activity record
512 $params['contactId'] = $this->_contactId;
43427a24 513 $params['activity_campaign_id'] = CRM_Utils_Array::value('campaign_id', $this->petition);
6a488035
TO
514 $result = $this->bao->createSignature($params);
515
516 // send thank you or email verification emails
517
518 // if logged in using Facebook connect and email on form matches Fb email,
519 // no need for email confirmation, send thank you email
520 if ($this->forceEmailConfirmed['flag'] &&
521 ($this->forceEmailConfirmed['email'] == $params['email-Primary'])
522 ) {
523 $this->_sendEmailMode = self::EMAIL_THANK;
524 }
525
526 switch ($this->_sendEmailMode) {
527 case self::EMAIL_THANK:
528 // mark the signature activity as completed and set confirmed cookie
529 $this->bao->confirmSignature($result->id, $this->_contactId, $this->_surveyId);
530 break;
531
532 case self::EMAIL_CONFIRM:
533 // set 'Unconfirmed' tag for this new contact
534 if ($tag_name) {
535 unset($tag_params);
536 $tag_params['contact_id'] = $this->_contactId;
537 $tag_params['tag_id'] = $this->_tagId;
83b0a3cc 538 $tag_params['version'] = 3;
6a488035
TO
539 $tag_value = civicrm_api('entity_tag', 'create', $tag_params);
540 }
541 break;
542 }
543
544 //send email
545 $params['activityId'] = $result->id;
546 $params['tagId'] = $this->_tagId;
6a488035
TO
547
548 $transaction->commit();
549
83b0a3cc 550 $this->bao->sendEmail($params, $this->_sendEmailMode);
551
6a488035
TO
552 if ($result) {
553 // call the hook before we redirect
554 $this->postProcessHook();
555
556 // set the template to thank you
8d7a9d07
CB
557 $url = CRM_Utils_System::url(
558 'civicrm/petition/thankyou',
559 'pid=' . $this->_surveyId . '&id=' . $this->_sendEmailMode . '&reset=1'
560 );
6a488035
TO
561 CRM_Utils_System::redirect($url);
562 }
563 }
564
565 /**
fe482240 566 * Build the petition profile form.
6a488035 567 *
100fef9d
CW
568 * @param int $id
569 * @param string $name
2a6da8d7 570 * @param bool $viewOnly
6a488035 571 */
00be9182 572 public function buildCustom($id, $name, $viewOnly = FALSE) {
6a488035
TO
573 if ($id) {
574 $session = CRM_Core_Session::singleton();
575 $this->assign("petition", $this->petition);
576 //$contactID = $this->_contactId;
577 $contactID = NULL;
578 $this->assign('contact_id', $this->_contactId);
579
580 $fields = NULL;
581 // TODO: contactID is never set (commented above)
582 if ($contactID) {
583 if (CRM_Core_BAO_UFGroup::filterUFGroups($id, $contactID)) {
584 $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD);
585 }
586 }
587 else {
588 $fields = CRM_Core_BAO_UFGroup::getFields($id, FALSE, CRM_Core_Action::ADD);
589 }
590
591 if ($fields) {
6a488035
TO
592 $this->assign($name, $fields);
593
594 $addCaptcha = FALSE;
595 foreach ($fields as $key => $field) {
596 if ($viewOnly &&
597 isset($field['data_type']) &&
598 $field['data_type'] == 'File' || ($viewOnly && $field['name'] == 'image_URL')
599 ) {
600 // ignore file upload fields
601 continue;
602 }
2efcf0c2 603
604 // if state or country in the profile, create map
2c6b0601 605 list($prefixName, $index) = CRM_Utils_System::explode('-', $key, 2);
6a488035
TO
606
607 CRM_Core_BAO_UFGroup::buildProfile($this, $field, CRM_Profile_Form::MODE_CREATE, $contactID, TRUE);
608 $this->_fields[$key] = $field;
71fc6ea4
DG
609 // CRM-11316 Is ReCAPTCHA enabled for this profile AND is this an anonymous visitor
610 if ($field['add_captcha'] && !$this->_contactId) {
6a488035
TO
611 $addCaptcha = TRUE;
612 }
613 }
614
71fc6ea4 615 if ($addCaptcha && !$viewOnly) {
6a488035
TO
616 $captcha = CRM_Utils_ReCAPTCHA::singleton();
617 $captcha->add($this);
618 $this->assign("isCaptcha", TRUE);
619 }
620 }
621 }
622 }
623
30c4e065
EM
624 /**
625 * @return string
626 */
00be9182 627 public function getTemplateFileName() {
6a488035
TO
628 if (isset($this->thankyou)) {
629 return ('CRM/Campaign/Page/Petition/ThankYou.tpl');
630 }
353ffa53
TO
631 else {
632 }
6a488035
TO
633 return parent::getTemplateFileName();
634 }
635
30c4e065 636 /**
fe482240 637 * check if user has already signed this petition.
c490a46a 638 * @param array $params
30c4e065 639 */
00be9182 640 public function redirectIfSigned($params) {
6a488035
TO
641 $signature = $this->bao->checkSignature($this->_surveyId, $this->_contactId);
642 //TODO: error case when more than one signature found for this petition and this contact
643 if (!empty($signature) && (count($signature) == 1)) {
644 $signature_id = array_keys($signature);
645 switch ($signature[$signature_id[0]]['status_id']) {
646 case 1:
647 //status is scheduled - email is unconfirmed
648 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId . '&id=4&reset=1'));
649 break;
650
651 case 2:
652 //status is completed
653 $this->bao->sendEmail($params, 1);
654 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId . '&id=5&reset=1'));
655 break;
656 }
657 }
658 }
96025800 659
6a488035 660}