QA fixes
[civicrm-core.git] / CRM / Core / BAO / CMSUser.php
CommitLineData
6a488035
TO
1<?php
2/*
3 +--------------------------------------------------------------------+
06b69b18 4 | CiviCRM version 4.5 |
6a488035 5 +--------------------------------------------------------------------+
06b69b18 6 | Copyright CiviCRM LLC (c) 2004-2014 |
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 +--------------------------------------------------------------------+
26*/
27
28/**
29 *
30 * @package CRM
06b69b18 31 * @copyright CiviCRM LLC (c) 2004-2014
6a488035
TO
32 * $Id$
33 *
34 */
35
36/**
37 * this file contains functions for synchronizing cms users with CiviCRM contacts
38 */
39
40require_once 'DB.php';
b5c2afd0
EM
41
42/**
43 * Class CRM_Core_BAO_CMSUser
44 */
6a488035
TO
45class CRM_Core_BAO_CMSUser {
46
47 /**
100fef9d 48 * Synchronizing cms users with CiviCRM contacts
6a488035 49 *
a1f7c05f
TO
50 * @param bool $is_interactive whether to show statuses & perform redirects
51 * This behavior is misplaced in the BAO layer, but we'll preserve it to avoid
52 * contract changes in the middle of the support cycle. In the next major
53 * release, we should remove & document it.
6a488035
TO
54 *
55 * @return void
56 *
57 * @static
58 * @access public
59 */
a1f7c05f 60 static function synchronize($is_interactive = TRUE) {
6a488035
TO
61 //start of schronization code
62 $config = CRM_Core_Config::singleton();
63
64 // Build an array of rows from UF users table.
65 $rows = array();
66 if ($config->userSystem->is_drupal == '1') {
67 $id = 'uid';
68 $mail = 'mail';
69 $name = 'name';
70
71 $result = db_query("SELECT uid, mail, name FROM {users} where mail != ''");
72
73 if ($config->userFramework == 'Drupal') {
74 while ($row = $result->fetchAssoc()) {
75 $rows[] = $row;
76 }
77 }
78 elseif ($config->userFramework == 'Drupal6') {
79 while ($row = db_fetch_array($result)) {
80 $rows[] = $row;
81 }
82 }
83 }
84 elseif ($config->userFramework == 'Joomla') {
85 $id = 'id';
86 $mail = 'email';
87 $name = 'name';
88 // TODO: Insert code here to populate $rows for Joomla;
89 }
90 elseif ($config->userFramework == 'WordPress') {
91 $id = 'ID';
92 $mail = 'user_email';
93 }
94 else {
95 CRM_Core_Error::fatal('CMS user creation not supported for this framework');
96 }
97
98 set_time_limit(300);
99
100 if ($config->userSystem->is_drupal == '1') {
101 $user = new StdClass();
102 $uf = $config->userFramework;
103 $contactCount = 0;
104 $contactCreated = 0;
105 $contactMatching = 0;
106 foreach ($rows as $row) {
107 $user->$id = $row[$id];
108 $user->$mail = $row[$mail];
109 $user->$name = $row[$name];
110 $contactCount++;
111 if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user, $row[$id], $row[$mail], $uf, 1, 'Individual', TRUE)) {
112 $contactCreated++;
113 }
114 else {
115 $contactMatching++;
116 }
117 if (is_object($match)) {
118 $match->free();
119 }
120 }
121 }
122 elseif ($config->userFramework == 'Joomla') {
123
124 $JUserTable = &JTable::getInstance('User', 'JTable');
125
126 $db = $JUserTable->getDbo();
127 $query = $db->getQuery(TRUE);
128 $query->select($id . ', ' . $mail . ', ' . $name);
129 $query->from($JUserTable->getTableName());
130 $query->where($mail != '');
131
132 $db->setQuery($query, 0, $limit);
133 $users = $db->loadObjectList();
134
135 $user = new StdClass();
136 $uf = $config->userFramework;
137 $contactCount = 0;
138 $contactCreated = 0;
139 $contactMatching = 0;
140 for ($i = 0; $i < count($users); $i++) {
141 $user->$id = $users[$i]->$id;
142 $user->$mail = $users[$i]->$mail;
143 $user->$name = $users[$i]->$name;
144 $contactCount++;
145 if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($user,
146 $users[$i]->$id,
147 $users[$i]->$mail,
148 $uf,
149 1,
150 'Individual',
151 TRUE
152 )) {
153 $contactCreated++;
154 }
155 else {
156 $contactMatching++;
157 }
158 if (is_object($match)) {
159 $match->free();
160 }
161 }
162 }
163 elseif ($config->userFramework == 'WordPress') {
164 $uf = $config->userFramework;
165 $contactCount = 0;
166 $contactCreated = 0;
167 $contactMatching = 0;
168
169 global $wpdb;
82d5bb05 170 $wpUserIds = $wpdb->get_col("SELECT $wpdb->users.ID FROM $wpdb->users");
6a488035
TO
171
172 foreach ($wpUserIds as $wpUserId) {
173 $wpUserData = get_userdata($wpUserId);
174 $contactCount++;
175 if ($match = CRM_Core_BAO_UFMatch::synchronizeUFMatch($wpUserData,
176 $wpUserData->$id,
177 $wpUserData->$mail,
178 $uf,
179 1,
180 'Individual',
181 TRUE
182 )) {
183 $contactCreated++;
184 }
185 else {
186 $contactMatching++;
187 }
188 if (is_object($match)) {
189 $match->free();
190 }
191 }
192 }
a1f7c05f
TO
193 //end of synchronization code
194
195 if ($is_interactive) {
196 $status = ts('Synchronize Users to Contacts completed.');
197 $status .= ' ' . ts('Checked one user record.',
6a488035 198 array(
a1f7c05f
TO
199 'count' => $contactCount,
200 'plural' => 'Checked %count user records.'
6a488035
TO
201 )
202 );
a1f7c05f
TO
203 if ($contactMatching) {
204 $status .= ' ' . ts('Found one matching contact record.',
205 array(
206 'count' => $contactMatching,
207 'plural' => 'Found %count matching contact records.'
208 )
209 );
210 }
6a488035 211
a1f7c05f
TO
212 $status .= ' ' . ts('Created one new contact record.',
213 array(
214 'count' => $contactCreated,
215 'plural' => 'Created %count new contact records.'
216 )
217 );
218 CRM_Core_Session::setStatus($status, ts('Saved'), 'success');
219 CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/admin', 'reset=1'));
220 }
6a488035
TO
221 }
222
223 /**
100fef9d 224 * Create CMS user using Profile
6a488035
TO
225 *
226 * @param array $params associated array
227 * @param string $mail email id for cms user
228 *
229 * @return int contact id that has been created
230 * @access public
231 * @static
232 */
233 static function create(&$params, $mail) {
234 $config = CRM_Core_Config::singleton();
235
236 $ufID = $config->userSystem->createUser($params, $mail);
237
238 //if contact doesn't already exist create UF Match
239 if ($ufID !== FALSE &&
240 isset($params['contactID'])
241 ) {
242 // create the UF Match record
243 $ufmatch = new CRM_Core_DAO_UFMatch();
244 $ufmatch->domain_id = CRM_Core_Config::domainID();
245 $ufmatch->uf_id = $ufID;
246 $ufmatch->contact_id = $params['contactID'];
247 $ufmatch->uf_name = $params[$mail];
248
249 if (!$ufmatch->find(TRUE)) {
250 $ufmatch->save();
251 }
252 }
253
254 return $ufID;
255 }
256
257 /**
100fef9d 258 * Create Form for CMS user using Profile
6a488035 259 *
c490a46a 260 * @param CRM_Core_Form $form
6a488035
TO
261 * @param integer $gid id of group of profile
262 * @param bool $emailPresent true if the profile field has email(primary)
da3c7979 263 * @param \const|int $action
fd31fa4c 264 *
6a488035
TO
265 * @return FALSE|void WTF
266 *
267 * @access public
268 * @static
269 */
270 static function buildForm(&$form, $gid, $emailPresent, $action = CRM_Core_Action::NONE) {
271 $config = CRM_Core_Config::singleton();
272 $showCMS = FALSE;
273
274 $isDrupal = $config->userSystem->is_drupal;
275 $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE;
276 $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE;
277
278 //if CMS is configured for not to allow creating new CMS user,
279 //don't build the form,Fixed for CRM-4036
280 if ($isJoomla) {
281 $userParams = JComponentHelper::getParams('com_users');
282 if (!$userParams->get('allowUserRegistration')) {
283 return FALSE;
284 }
285 }
286 elseif ($isDrupal && !variable_get('user_register', TRUE)) {
287 return FALSE;
288 }
289 elseif ($isWordPress && !get_option('users_can_register')) {
290 return FALSE;
291 }
292
293 if ($gid) {
294 $isCMSUser = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_UFGroup', $gid, 'is_cms_user');
295 }
296
297 // $cms is true when there is email(primary location) is set in the profile field.
298 $session = CRM_Core_Session::singleton();
299 $userID = $session->get('userID');
300 $showUserRegistration = FALSE;
301 if ($action) {
302 $showUserRegistration = TRUE;
303 }
304 elseif (!$action && !$userID) {
305 $showUserRegistration = TRUE;
306 }
307
308 if ($isCMSUser && $emailPresent) {
309 if ($showUserRegistration) {
310 if ($isCMSUser != 2) {
311 $extra = array(
312 'onclick' => "return showHideByValue('cms_create_account','','details','block','radio',false );",
313 );
314 $form->addElement('checkbox', 'cms_create_account', ts('Create an account?'), NULL, $extra);
315 $required = FALSE;
316 }
317 else {
318 $form->add('hidden', 'cms_create_account', 1);
319 $required = TRUE;
320 }
321
322 $form->assign('isCMS', $required);
323 if (!$userID || $action & CRM_Core_Action::PREVIEW || $action & CRM_Core_Action::PROFILE) {
324 $form->add('text', 'cms_name', ts('Username'), NULL, $required);
325 if (($isDrupal && !variable_get('user_email_verification', TRUE)) OR ($isJoomla) OR ($isWordPress)) {
326 $form->add('password', 'cms_pass', ts('Password'));
327 $form->add('password', 'cms_confirm_pass', ts('Confirm Password'));
328 }
329
330 $form->addFormRule(array('CRM_Core_BAO_CMSUser', 'formRule'), $form);
331 }
332 $showCMS = TRUE;
333 }
334 }
335
336 $destination = $config->userSystem->getLoginDestination($form);
337 $loginURL = $config->userSystem->getLoginURL($destination);
338 $form->assign('loginURL', $loginURL);
339 $form->assign('showCMS', $showCMS);
340 }
341
c490a46a 342 /**
6a488035 343 * Checks that there is a valid username & email
c490a46a 344 * optionally checks password is present & matches DB & gets the CMS to validate
6a488035 345 *
c490a46a
CW
346 * @param array $fields Posted values of form
347 * @param array $files uploaded files if any
348 * @param CRM_Core_Form $form
b5c2afd0
EM
349 *
350 * @return array|bool
351 */
c490a46a 352 static function formRule($fields, $files, $form) {
a7488080 353 if (empty($fields['cms_create_account'])) {
6a488035
TO
354 return TRUE;
355 }
356
357 $config = CRM_Core_Config::singleton();
358
359 $isDrupal = $config->userSystem->is_drupal;
360 $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE;
361 $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE;
362
363 $errors = array();
364 if ($isDrupal || $isJoomla || $isWordPress) {
365 $emailName = NULL;
c490a46a 366 if (!empty($form->_bltID) && array_key_exists("email-{$form->_bltID}", $fields)) {
6a488035 367 // this is a transaction related page
c490a46a 368 $emailName = 'email-' . $form->_bltID;
6a488035
TO
369 } else {
370 // find the email field in a profile page
371 foreach ($fields as $name => $dontCare) {
372 if (substr($name, 0, 5) == 'email') {
373 $emailName = $name;
374 break;
375 }
376 }
377 }
378
379 if ($emailName == NULL) {
380 $errors['_qf_default'] == ts('Could not find an email address.');
381 return $errors;
382 }
383
384 if (empty($fields['cms_name'])) {
385 $errors['cms_name'] = ts('Please specify a username.');
386 }
387
388 if (empty($fields[$emailName])) {
389 $errors[$emailName] = ts('Please specify a valid email address.');
390 }
391
392 if (($isDrupal && !variable_get('user_email_verification', TRUE)) OR ($isJoomla) OR ($isWordPress)) {
393 if (empty($fields['cms_pass']) ||
394 empty($fields['cms_confirm_pass'])
395 ) {
396 $errors['cms_pass'] = ts('Please enter a password.');
397 }
398 if ($fields['cms_pass'] != $fields['cms_confirm_pass']) {
399 $errors['cms_pass'] = ts('Password and Confirm Password values are not the same.');
400 }
401 }
402
403 if (!empty($errors)) {
404 return $errors;
405 }
406
407 // now check that the cms db does not have the user name and/or email
408 if ($isDrupal OR $isJoomla OR $isWordPress) {
409 $params = array(
410 'name' => $fields['cms_name'],
411 'mail' => $fields[$emailName],
412 );
413 }
414
415 $config->userSystem->checkUserNameEmailExists($params, $errors, $emailName);
416 }
417 return (!empty($errors)) ? $errors : TRUE;
418 }
419
420 /**
100fef9d 421 * Check if a cms user already exists.
6a488035
TO
422 *
423 * @param Array $contact array of contact-details
424 *
425 * @return uid if user exists, false otherwise
426 *
427 * @access public
428 * @static
429 */
430 static function userExists(&$contact) {
431 $config = CRM_Core_Config::singleton();
432
433 $isDrupal = $config->userSystem->is_drupal;
434 $isJoomla = ucfirst($config->userFramework) == 'Joomla' ? TRUE : FALSE;
435 $isWordPress = $config->userFramework == 'WordPress' ? TRUE : FALSE;
436
437 if (!$isDrupal && !$isJoomla && !$isWordPress) {
438 die('Unknown user framework');
439 }
440
441 // Use UF native framework to fetch data from UF user table
442 if ($isDrupal) {
443 $uid = db_query(
444 "SELECT uid FROM {users} where mail = :email",
445 array(':email' => $contact['email'])
446 )->fetchField();
447
448 if ($uid) {
449 $contact['user_exists'] = TRUE;
450 $result = $uid;
451 }
452 }
453 elseif ($isJoomla) {
454 $mail = $contact['email'];
455
456 $JUserTable = &JTable::getInstance('User', 'JTable');
457
458 $db = $JUserTable->getDbo();
459 $query = $db->getQuery(TRUE);
460 $query->select('username, email');
461 $query->from($JUserTable->getTableName());
462 $query->where('(LOWER(email) = LOWER(\'' . $email . '\'))');
463 $db->setQuery($query, 0, $limit);
464 $users = $db->loadAssocList();
465
466 $row = array();;
467 if (count($users)) {
468 $row = $users[0];
469 }
470
471 if (!empty($row)) {
472 $uid = CRM_Utils_Array::value('id', $row);
473 $contact['user_exists'] = TRUE;
474 $result = $uid;
475 }
476 }
477 elseif ($isWordPress) {
478 if (email_exists($params['mail'])) {
479 $contact['user_exists'] = TRUE;
480 $userObj = get_user_by('email', $params['mail']);
481 return $userObj->ID;
482 }
483 }
484
485 return $result;
486 }
487
b5c2afd0
EM
488 /**
489 * @param $config
490 *
491 * @return object
492 */
6a488035 493 static function &dbHandle(&$config) {
6a4257d4 494 $errorScope = CRM_Core_TemporaryErrorScope::ignoreException();
6a488035 495 $db_uf = DB::connect($config->userFrameworkDSN);
6a4257d4 496 unset($errorScope);
6a488035
TO
497 if (!$db_uf ||
498 DB::isError($db_uf)
499 ) {
500 $session = CRM_Core_Session::singleton();
501 $session->pushUserContext(CRM_Utils_System::url('civicrm/admin', 'reset=1'));
502 CRM_Core_Error::statusBounce(ts("Cannot connect to UF db via %1. Please check the CIVICRM_UF_DSN value in your civicrm.settings.php file",
503 array(1 => $db_uf->getMessage())
504 ));
505 }
506 $db_uf->query('/*!40101 SET NAMES utf8 */');
507 return $db_uf;
508 }
509}
510