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