3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2014 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2014
37 * This class generates form components for processing a petition signature
40 class CRM_Campaign_Form_Petition_Signature
extends CRM_Core_Form
{
41 CONST EMAIL_THANK
= 1, EMAIL_CONFIRM
= 2, MODE_CREATE
= 4;
46 * the id of the contact associated with this signature
54 * Is this a logged in user
58 protected $_loggedIn = FALSE;
63 * @var string ("Individual"/"Household"/"Organization"). Never been tested for something else than Individual
65 protected $_ctype = 'Individual';
68 * The contact profile id attached with this petition
72 protected $_contactProfileId;
75 * the contact profile fields used for this petition
79 public $_contactProfileFields;
82 * The activity profile id attached with this petition
86 protected $_activityProfileId;
89 * the activity profile fields used for this petition
93 public $_activityProfileFields;
96 * the id of the survey (petition) we are proceessing
104 * The tag id used to set against contacts with unconfirmed email
111 * values to use for custom profiles
119 * The params submitted by the form
127 * which email send mode do we use
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
135 * send a confirmation request email
137 protected $_sendEmailMode;
139 protected $_image_URL;
141 protected $_defaults = NULL;
146 function __construct() {
147 parent
::__construct();
148 // this property used by civicrm_fb module and if true, forces thank you email to be sent
149 // for users signing in via Facebook connect; also sets Fb email to check against
150 $this->forceEmailConfirmed
['flag'] = FALSE;
151 $this->forceEmailConfirmed
['email'] = '';
157 function getContactID() {
158 $tempID = CRM_Utils_Request
::retrieve('cid', 'Positive', $this);
160 // force to ignore the authenticated user
161 if ($tempID === '0') {
165 //check if this is a checksum authentication
166 $userChecksum = CRM_Utils_Request
::retrieve('cs', 'String', $this);
168 //check for anonymous user.
169 $validUser = CRM_Contact_BAO_Contact_Utils
::validChecksum($tempID, $userChecksum);
175 // check if the user is registered and we have a contact ID
176 $session = CRM_Core_Session
::singleton();
177 return $session->get('userID');
180 public function preProcess() {
181 $this->bao
= new CRM_Campaign_BAO_Petition();
182 $this->_mode
= self
::MODE_CREATE
;
185 $this->_surveyId
= CRM_Utils_Request
::retrieve('sid', 'Positive', $this);
188 if (!$this->_surveyId
) {
189 CRM_Core_Error
::fatal('Petition id is not valid. (it needs a "sid" in the url).');
192 //check petition is valid and active
193 $params['id'] = $this->_surveyId
;
194 $this->petition
= array();
195 CRM_Campaign_BAO_Survey
::retrieve($params, $this->petition
);
196 if (empty($this->petition
)) {
197 CRM_Core_Error
::fatal('Petition doesn\'t exist.');
199 if ($this->petition
['is_active'] == 0) {
200 CRM_Core_Error
::fatal('Petition is no longer active.');
203 //get userID from session
204 $session = CRM_Core_Session
::singleton();
206 //get the contact id for this user if logged in
207 $this->_contactId
= $this->getContactId();
208 if (isset($this->_contactId
)) {
209 $this->_loggedIn
= TRUE;
212 // add the custom contact and activity profile fields to the signature form
214 $ufJoinParams = array(
215 'entity_id' => $this->_surveyId
,
216 'entity_table' => 'civicrm_survey',
217 'module' => 'CiviCampaign',
221 $this->_contactProfileId
= CRM_Core_BAO_UFJoin
::findUFGroupId($ufJoinParams);
222 if ($this->_contactProfileId
) {
223 $this->_contactProfileFields
= CRM_Core_BAO_UFGroup
::getFields($this->_contactProfileId
, FALSE, CRM_Core_Action
::ADD
);
225 if (!isset($this->_contactProfileFields
['email-Primary'])) {
226 CRM_Core_Error
::fatal('The contact profile needs to contain the primary email address field');
230 $ufJoinParams['weight'] = 1;
231 $this->_activityProfileId
= CRM_Core_BAO_UFJoin
::findUFGroupId($ufJoinParams);
233 if ($this->_activityProfileId
) {
234 $this->_activityProfileFields
= CRM_Core_BAO_UFGroup
::getFields($this->_activityProfileId
, FALSE, CRM_Core_Action
::ADD
);
237 $this->setDefaultValues();
238 CRM_Utils_System
::setTitle($this->petition
['title']);
242 * This function sets the default values for the form.
248 function setDefaultValues() {
249 $this->_defaults
= array();
250 if ($this->_contactId
) {
251 CRM_Core_BAO_UFGroup
::setProfileDefaults($this->_contactId
, $this->_contactProfileFields
, $this->_defaults
, TRUE);
252 if ($this->_activityProfileId
) {
253 CRM_Core_BAO_UFGroup
::setProfileDefaults($this->_contactId
, $this->_activityProfileFields
, $this->_defaults
, TRUE);
257 //set custom field defaults
259 foreach ($this->_contactProfileFields
as $name => $field) {
260 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($name)) {
261 $htmlType = $field['html_type'];
263 if (!isset($this->_defaults
[$name])) {
264 CRM_Core_BAO_CustomField
::setProfileDefaults($customFieldID,
274 if ($this->_activityProfileFields
) {
275 foreach ($this->_activityProfileFields
as $name => $field) {
276 if ($customFieldID = CRM_Core_BAO_CustomField
::getKeyID($name)) {
277 $htmlType = $field['html_type'];
279 if (!isset($this->_defaults
[$name])) {
280 CRM_Core_BAO_CustomField
::setProfileDefaults($customFieldID,
291 $this->setDefaults($this->_defaults
);
293 // add in all state country selectors for enabled countries
294 CRM_Core_BAO_Address
::fixAllStateSelects($this, $this->_defaults
);
297 public function buildQuickForm() {
298 $this->assign('survey_id', $this->_surveyId
);
299 $this->assign('petitionTitle', $this->petition
['title']);
300 if (isset($_COOKIE['signed_' . $this->_surveyId
])) {
301 if (isset($_COOKIE['confirmed_' . $this->_surveyId
])) {
302 $this->assign('duplicate', "confirmed");
305 $this->assign('duplicate', "unconfirmed");
310 $this->applyFilter('__ALL__', 'trim');
312 $this->buildCustom($this->_contactProfileId
, 'petitionContactProfile');
313 if ($this->_activityProfileId
) {
314 $this->buildCustom($this->_activityProfileId
, 'petitionActivityProfile');
317 $this->addButtons(array(
320 'name' => ts('Sign the Petition'),
328 * This function is used to add the rules (mainly global rules) for form.
329 * All local rules are added near the element
340 static function formRule($fields, $files, $errors) {
343 return empty($errors) ?
TRUE : $errors;
347 * Form submission of petition signature
353 public function postProcess() {
354 $tag_name = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::CAMPAIGN_PREFERENCES_NAME
,
360 // Check if contact 'email confirmed' tag exists, else create one
361 // This should be in the petition module initialise code to create a default tag for this
362 $tag_params['name'] = $tag_name;
363 $tag_params['version'] = 3;
364 $tag = civicrm_api('tag', 'get', $tag_params);
365 if ($tag['count'] == 0) {
367 $tag_params['description'] = $tag_name;
368 $tag_params['is_reserved'] = 1;
369 $tag_params['used_for'] = 'civicrm_contact';
370 $tag = civicrm_api('tag', 'create', $tag_params);
372 $this->_tagId
= $tag['id'];
375 // export the field values to be used for saving the profile form
376 $params = $this->controller
->exportValues($this->_name
);
378 $session = CRM_Core_Session
::singleton();
380 $params['last_modified_id'] = $session->get('userID');
381 $params['last_modified_date'] = date('YmdHis');
383 if ($this->_action
& CRM_Core_Action
::ADD
) {
384 $params['created_id'] = $session->get('userID');
385 $params['created_date'] = date('YmdHis');
388 if (isset($this->_surveyId
)) {
389 $params['sid'] = $this->_surveyId
;
392 if (isset($this->_contactId
)) {
393 $params['contactId'] = $this->_contactId
;
396 // if logged in user, skip dedupe
397 if ($this->_loggedIn
) {
398 $ids[0] = $this->_contactId
;
401 // dupeCheck - check if contact record already exists
402 // code modified from api/v2/Contact.php-function civicrm_contact_check_params()
403 $params['contact_type'] = $this->_ctype
;
404 //TODO - current dedupe finds soft deleted contacts - adding param is_deleted not working
405 // ignore soft deleted contacts
406 //$params['is_deleted'] = 0;
407 $dedupeParams = CRM_Dedupe_Finder
::formatParams($params, $params['contact_type']);
408 $dedupeParams['check_permission'] = '';
410 //dupesByParams($params, $ctype, $level = 'Unsupervised', $except = array())
411 $ids = CRM_Dedupe_Finder
::dupesByParams($dedupeParams, $params['contact_type']);
414 $petition_params['id'] = $this->_surveyId
;
416 CRM_Campaign_BAO_Survey
::retrieve($petition_params, $petition);
418 switch (count($ids)) {
420 //no matching contacts - create a new contact
421 // Add a source for this new contact
422 $params['source'] = ts('Petition Signature') . ' ' . $this->petition
['title'];
424 if ($this->petition
['bypass_confirm']) {
425 // send thank you email directly, bypassing confirmation
426 $this->_sendEmailMode
= self
::EMAIL_THANK
;
427 // Set status for signature activity to completed
428 $params['statusId'] = 2;
431 $this->_sendEmailMode
= self
::EMAIL_CONFIRM
;
433 // Set status for signature activity to scheduled until email is verified
434 $params['statusId'] = 1;
439 $this->_contactId
= $params['contactId'] = $ids[0];
441 // check if user has already signed this petition - redirects to Thank You if true
442 $this->redirectIfSigned($params);
444 if ($this->petition
['bypass_confirm']) {
445 // send thank you email directly, bypassing confirmation
446 $this->_sendEmailMode
= self
::EMAIL_THANK
;
447 // Set status for signature activity to completed
448 $params['statusId'] = 2;
452 // dedupe matched single contact, check for 'unconfirmed' tag
454 $tag = new CRM_Core_DAO_EntityTag();
455 $tag->entity_id
= $this->_contactId
;
456 $tag->tag_id
= $this->_tagId
;
458 if (!($tag->find())) {
459 // send thank you email directly, the user is known and validated
460 $this->_sendEmailMode
= self
::EMAIL_THANK
;
461 // Set status for signature activity to completed
462 $params['statusId'] = 2;
465 // send email verification email
466 $this->_sendEmailMode
= self
::EMAIL_CONFIRM
;
467 // Set status for signature activity to scheduled until email is verified
468 $params['statusId'] = 1;
474 // more than 1 matching contact
475 // for time being, take the first matching contact (not sure that's the best strategy, but better than creating another duplicate)
476 $this->_contactId
= $params['contactId'] = $ids[0];
478 // check if user has already signed this petition - redirects to Thank You if true
479 $this->redirectIfSigned($params);
481 if ($this->petition
['bypass_confirm']) {
482 // send thank you email directly, bypassing confirmation
483 $this->_sendEmailMode
= self
::EMAIL_THANK
;
484 // Set status for signature activity to completed
485 $params['statusId'] = 2;
490 $tag = new CRM_Core_DAO_EntityTag();
491 $tag->entity_id
= $this->_contactId
;
492 $tag->tag_id
= $this->_tagId
;
494 if (!($tag->find())) {
495 // send thank you email
496 $this->_sendEmailMode
= self
::EMAIL_THANK
;
497 // Set status for signature activity to completed
498 $params['statusId'] = 2;
501 // send email verification email
502 $this->_sendEmailMode
= self
::EMAIL_CONFIRM
;
503 // Set status for signature activity to scheduled until email is verified
504 $params['statusId'] = 1;
512 $transaction = new CRM_Core_Transaction();
514 $addToGroupID = isset($this->_addToGroupID
) ?
$this->_addToGroupID
: NULL;
515 $this->_contactId
= CRM_Contact_BAO_Contact
::createProfileContact($params, $this->_contactProfileFields
,
516 $this->_contactId
, $addToGroupID,
517 $this->_contactProfileId
, $this->_ctype
,
521 // get additional custom activity profile field data
522 // to save with new signature activity record
523 $surveyInfo = $this->bao
->getSurveyInfo($this->_surveyId
);
524 $customActivityFields = CRM_Core_BAO_CustomField
::getFields('Activity', FALSE, FALSE,
525 $surveyInfo['activity_type_id']
527 $customActivityFields = CRM_Utils_Array
::crmArrayMerge($customActivityFields,
528 CRM_Core_BAO_CustomField
::getFields('Activity', FALSE, FALSE,
533 $params['custom'] = CRM_Core_BAO_CustomField
::postProcess($params,
534 $customActivityFields,
539 // create the signature activity record
540 $params['contactId'] = $this->_contactId
;
541 $params['activity_campaign_id'] = CRM_Utils_Array
::value('campaign_id', $this->petition
);
542 $result = $this->bao
->createSignature($params);
544 // send thank you or email verification emails
546 // if logged in using Facebook connect and email on form matches Fb email,
547 // no need for email confirmation, send thank you email
548 if ($this->forceEmailConfirmed
['flag'] &&
549 ($this->forceEmailConfirmed
['email'] == $params['email-Primary'])
551 $this->_sendEmailMode
= self
::EMAIL_THANK
;
554 switch ($this->_sendEmailMode
) {
555 case self
::EMAIL_THANK
:
556 // mark the signature activity as completed and set confirmed cookie
557 $this->bao
->confirmSignature($result->id
, $this->_contactId
, $this->_surveyId
);
560 case self
::EMAIL_CONFIRM
:
561 // set 'Unconfirmed' tag for this new contact
564 $tag_params['contact_id'] = $this->_contactId
;
565 $tag_params['tag_id'] = $this->_tagId
;
566 $tag_params['version'] = 3;
567 $tag_value = civicrm_api('entity_tag', 'create', $tag_params);
573 $params['activityId'] = $result->id
;
574 $params['tagId'] = $this->_tagId
;
576 $transaction->commit();
578 $this->bao
->sendEmail($params, $this->_sendEmailMode
);
581 // call the hook before we redirect
582 $this->postProcessHook();
584 // set the template to thank you
586 CRM_Utils_System
::url(
587 'civicrm/petition/thankyou',
588 'pid=' . $this->_surveyId
. '&id=' . $this->_sendEmailMode
. '&reset=1'
590 CRM_Utils_System
::redirect($url);
595 * Function to build the petition profile form
599 * @param bool $viewOnly
604 function buildCustom($id, $name, $viewOnly = FALSE) {
606 // create state country map array to hold selectors
607 $stateCountryMap = array();
610 $session = CRM_Core_Session
::singleton();
611 $this->assign("petition", $this->petition
);
612 //$contactID = $this->_contactId;
614 $this->assign('contact_id', $this->_contactId
);
617 // TODO: contactID is never set (commented above)
619 if (CRM_Core_BAO_UFGroup
::filterUFGroups($id, $contactID)) {
620 $fields = CRM_Core_BAO_UFGroup
::getFields($id, FALSE, CRM_Core_Action
::ADD
);
624 $fields = CRM_Core_BAO_UFGroup
::getFields($id, FALSE, CRM_Core_Action
::ADD
);
629 // unset any email-* fields since we already collect it, CRM-2888
630 foreach ( array_keys( $fields ) as $fieldName ) {
631 if ( substr( $fieldName, 0, 6 ) == 'email-' ) {
632 unset( $fields[$fieldName] );
638 $this->assign($name, $fields);
641 foreach ($fields as $key => $field) {
643 isset($field['data_type']) &&
644 $field['data_type'] == 'File' ||
($viewOnly && $field['name'] == 'image_URL')
646 // ignore file upload fields
650 // if state or country in the profile, create map
651 list($prefixName, $index) = CRM_Utils_System
::explode('-', $key, 2);
652 if ($prefixName == 'state_province' ||
$prefixName == 'country' ||
$prefixName == 'county') {
653 if (!array_key_exists($index, $stateCountryMap)) {
654 $stateCountryMap[$index] = array();
656 $stateCountryMap[$index][$prefixName] = $key;
659 CRM_Core_BAO_UFGroup
::buildProfile($this, $field, CRM_Profile_Form
::MODE_CREATE
, $contactID, TRUE);
660 $this->_fields
[$key] = $field;
661 // CRM-11316 Is ReCAPTCHA enabled for this profile AND is this an anonymous visitor
662 if ($field['add_captcha'] && !$this->_contactId
) {
667 // initialize the state country map
668 CRM_Core_BAO_Address
::addStateCountryMap($stateCountryMap);
670 if ($addCaptcha && !$viewOnly) {
671 $captcha = CRM_Utils_ReCAPTCHA
::singleton();
672 $captcha->add($this);
673 $this->assign("isCaptcha", TRUE);
682 function getTemplateFileName() {
683 if (isset($this->thankyou
)) {
684 return ('CRM/Campaign/Page/Petition/ThankYou.tpl');
687 return parent
::getTemplateFileName();
690 // check if user has already signed this petition
694 function redirectIfSigned($params) {
695 $signature = $this->bao
->checkSignature($this->_surveyId
, $this->_contactId
);
696 //TODO: error case when more than one signature found for this petition and this contact
697 if (!empty($signature) && (count($signature) == 1)) {
698 $signature_id = array_keys($signature);
699 switch ($signature[$signature_id[0]]['status_id']) {
701 //status is scheduled - email is unconfirmed
702 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId
. '&id=4&reset=1'));
706 //status is completed
707 $this->bao
->sendEmail($params, 1);
708 CRM_Utils_System
::redirect(CRM_Utils_System
::url('civicrm/petition/thankyou', 'pid=' . $this->_surveyId
. '&id=5&reset=1'));