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