/** * Creates a new users table record. * * This is an internal function that creates a new user. External calls to create either a new * registration record or a new users record are made to Users_Api_Registration#registerNewUser(), which * dispatches either this function or createRegistration(). Users_Api_Registration#registerNewUser() should be the * primary and exclusive function used to create either a user record or a registraion, as it knows how to * decide which gets created based on the system configuration and the data provided. * * ATTENTION: This is the proper place to fire an item-created hook for the user account * record, even though the physical database record may have been saved previously as a pending * registration. See the note in createRegistration(). * * @param array $reginfo Contains the data gathered about the user for the registration record. * @param bool $userNotification Whether the user should be notified of the new registration or not; * however if the user's password was created for him, then he will * receive at least that notification without regard to this setting. * @param bool $adminNotification Whether the configured administrator notification e-mail address should * be sent notification of the new registration. * @param string $passwordCreatedForUser The password that was created for the user either automatically or by * an administrator (but not by the user himself). * * @return array|bool The user info, as saved in the users table; false on error. * * @see Users_Api_Registration#registerNewUser() */ protected function createUser(array $reginfo, $userNotification = true, $adminNotification = true, $passwordCreatedForUser = '') { $currentUserIsAdminOrSubadmin = $this->currentUserIsAdminOrSubAdmin(); if (!isset($reginfo) || empty($reginfo)) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // It is only considered 'created by admin' if the reginfo has no id. If it has an id, then the // registration record was created by an admin, but this is being created after a verification $createdByAdminOrSubAdmin = $currentUserIsAdminOrSubadmin && !isset($reginfo['uid']); // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['email']) || empty($reginfo['email'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // Check to see if we are getting a record directly from the registration request process, or one // from a later step in the registration process (e.g., approval or verification) if (!isset($reginfo['uid']) || empty($reginfo['uid'])) { // This is a record directly from the registration request process (never been saved before) // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['isapproved']) || empty($reginfo['isapproved'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } // Ensure that no user gets created without a password, and that the password is reasonable (no spaces, salted) // If the user is being registered with an authentication method other than one from the Users module, then the // password will be the unsalted, unhashed string stored in UsersConstant::PWD_NO_USERS_AUTHENTICATION. $hasPassword = isset($reginfo['pass']) && is_string($reginfo['pass']) && !empty($reginfo['pass']); if ($reginfo['pass'] === UsersConstant::PWD_NO_USERS_AUTHENTICATION) { $hasSaltedPassword = false; $hasNoUsersAuthenticationPassword = true; } else { $hasSaltedPassword = $hasPassword && strpos($reginfo['pass'], UsersConstant::SALT_DELIM) != strrpos($reginfo['pass'], UsersConstant::SALT_DELIM); $hasNoUsersAuthenticationPassword = false; } if (!$hasPassword || !$hasSaltedPassword && !$hasNoUsersAuthenticationPassword) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } $reginfo['uname'] = mb_strtolower($reginfo['uname']); $reginfo['email'] = mb_strtolower($reginfo['email']); $nowUTC = new \DateTime(null, new \DateTimeZone('UTC')); $nowUTCStr = $nowUTC->format(UsersConstant::DATETIME_FORMAT); // Finally, save it, but first get rid of some pseudo-properties $userObj = $reginfo; // Remove some pseudo-properties if (isset($userObj['isapproved'])) { unset($userObj['isapproved']); } if (isset($userObj['isverified'])) { unset($userObj['isverified']); } if (isset($userObj['verificationsent'])) { unset($userObj['verificationsent']); } $userObj = $this->cleanFieldsToAttributes($userObj); if (isset($userObj['__ATTRIBUTES__']['_Users_isVerified'])) { unset($userObj['__ATTRIBUTES__']['_Users_isVerified']); } $userObj['user_regdate'] = $nowUTCStr; if ($createdByAdminOrSubAdmin) { // Current user is admin, so admin is creating this registration. // See below if moderation is off and user is self-approved $userObj['approved_by'] = UserUtil::getVar('uid'); } // Approved date is set no matter what approved_by will become. $userObj['approved_date'] = $nowUTCStr; // Set activated state as pending registration for now to prevent firing of update hooks after the insert until the // activated state is set properly further below. $userObj['activated'] = UsersConstant::ACTIVATED_PENDING_REG; // store user's attributes to a variable. // we will persist them to the database after the user record is created $attributes = $userObj['__ATTRIBUTES__']; unset($userObj['__ATTRIBUTES__']); $user = new \UsersModule\Entity\User(); $user->merge($userObj); $this->entityManager->persist($user); $this->entityManager->flush(); // store attributes also foreach ($attributes as $attr_key => $attr_value) { $user->setAttribute($attr_key, $attr_value); } // NOTE: See below for the firing of the item-create hook. $userObj = $user->toArray(); if ($userObj) { if (!$createdByAdminOrSubAdmin) { // Current user is not admin, so moderation is off and user "self-approved" through the registration process // We couldn't do this above because we didn't know the uid. $user['approved_by'] = $userObj['uid']; $this->entityManager->flush(); } $reginfo['uid'] = $userObj['uid']; } } else { // This is a record from intermediate step in the registration process (e.g. verification or approval) // Protected method (not callable from the api), so assume that the data has been validated in registerNewUser(). // Just check some basic things we need directly in this function. if (!isset($reginfo['approved_by']) || empty($reginfo['approved_by'])) { $this->registerError(LogUtil::getErrorMsgArgs()); return false; } $userObj = $reginfo; $reginfo['isapproved'] = true; // delete attribute from user without using UserUtil::delVar // so that we don't get an update event. (Create hasn't happened yet.); $user = $this->entityManager->find('UsersModule\\Entity\\User', $reginfo['uid']); $user->delAttribute('_Users_isVerified'); // NOTE: See below for the firing of the item-create hook. } if ($userObj) { // Set appropriate activated status. Again, use Doctrine so we don't get an update event. (Create hasn't happened yet.) // Need to do this here so that it happens for both the case where $reginfo is coming in new, and the case where // $reginfo was already in the database. $user = $this->entityManager->find('UsersModule\\Entity\\User', $userObj['uid']); $user['activated'] = UsersConstant::ACTIVATED_ACTIVE; $userObj['activated'] = UsersConstant::ACTIVATED_ACTIVE; // Add user to default group $defaultGroup = ModUtil::getVar('Groups', 'defaultgroup', false); if (!$defaultGroup) { $this->registerError($this->__('Warning! The user account was created, but there was a problem adding the account to the default group.')); } $groupAdded = ModUtil::apiFunc('GroupsModule', 'user', 'adduser', array('gid' => $defaultGroup, 'uid' => $userObj['uid'])); if (!$groupAdded) { $this->registerError($this->__('Warning! The user account was created, but there was a problem adding the account to the default group.')); } // Force the reload of the user in the cache. $userObj = UserUtil::getVars($userObj['uid'], true); // ATTENTION: This is the proper place for the item-create hook, not when a pending // registration is created. It is not a "real" record until now, so it wasn't really // "created" until now. It is way down here so that the activated state can be properly // saved before the hook is fired. $createEvent = new GenericEvent($userObj); $this->dispatcher->dispatch('user.account.create', $createEvent); $regErrors = array(); if ($adminNotification || $userNotification || !empty($passwordCreatedForUser)) { $sitename = System::getVar('sitename'); $siteurl = System::getBaseUrl(); $approvalOrder = $this->getVar('moderation_order', UsersConstant::APPROVAL_BEFORE); $rendererArgs = array(); $rendererArgs['sitename'] = $sitename; $rendererArgs['siteurl'] = substr($siteurl, 0, strlen($siteurl) - 1); $rendererArgs['reginfo'] = $reginfo; $rendererArgs['createdpassword'] = $passwordCreatedForUser; $rendererArgs['admincreated'] = $createdByAdminOrSubAdmin; $rendererArgs['approvalorder'] = $approvalOrder; if ($userNotification || !empty($passwordCreatedForUser)) { $notificationSent = ModUtil::apiFunc($this->name, 'user', 'sendNotification', array('toAddress' => $userObj['email'], 'notificationType' => 'welcome', 'templateArgs' => $rendererArgs)); if (!$notificationSent) { $loggedErrorMessages = $this->request->getSession()->getFlashBag()->get(Zikula_Session::MESSAGE_ERROR); $this->request->getSession()->getFlashBag()->get(Zikula_Session::MESSAGE_ERROR); foreach ($loggedErrorMessages as $lem) { if (!in_array($lem, $regErrors)) { $regErrors[] = $lem; } $regErrors[] = $this->__('Warning! The welcoming email for the newly created user could not be sent.'); } } } if ($adminNotification) { // mail notify email to inform admin about registration $notificationEmail = $this->getVar('reg_notifyemail', ''); if (!empty($notificationEmail)) { $subject = $this->__f('New registration: %s', $userObj['uname']); $notificationSent = ModUtil::apiFunc($this->name, 'user', 'sendNotification', array('toAddress' => $notificationEmail, 'notificationType' => 'regadminnotify', 'templateArgs' => $rendererArgs, 'subject' => $subject)); if (!$notificationSent) { $loggedErrorMessages = $this->request->getSession()->getFlashBag()->get(Zikula_Session::MESSAGE_ERROR); $this->request->getSession()->getFlashBag()->get(Zikula_Session::MESSAGE_ERROR); foreach ($loggedErrorMessages as $lem) { if (!in_array($lem, $regErrors)) { $regErrors[] = $lem; } $regErrors[] = $this->__('Warning! The notification email for the newly created user could not be sent.'); } } } } } $userObj['regErrors'] = $regErrors; return $userObj; } else { $this->registerError($this->__('Unable to store the new user registration record.')); return false; } }
/** * Add new user accounts from the import process. * * Parameters passed in the $args array: * ------------------------------------- * array $args['importvalues'] An array of information used to create new user records. Each element of the * array should represent the minimum information to create a user record, including * 'uname', 'email', 'pass', etc. * * @param array $args All parameters passed to this function. * * @return bool True on success; false otherwise. */ public function createImport($args) { // Need add access to call this function if (!SecurityUtil::checkPermission("{$this->name}::", '::', ACCESS_ADD)) { return false; } $importValues = $args['importvalues']; if (empty($importValues)) { return false; } // Prepare arrays. $usersArray = array(); foreach ($importValues as $key => $value) { $usersArray[] = $value['uname']; if (!$value['activated']) { $importValues[$key]['activated'] = UsersConstant::ACTIVATED_PENDING_REG; } } $importValuesDB = $importValues; foreach ($importValuesDB as $key => $value) { $importValuesDB[$key]['pass'] = UserUtil::getHashedPassword($importValuesDB[$key]['pass']); } // create users foreach ($importValuesDB as $importValueDB) { $user = new UsersModule\Entity\User(); $user->merge($importValueDB); $this->entityManager->persist($user); } $this->entityManager->flush(); // get users. We need the users identities set them into their groups $usersInDB = ModUtil::apiFunc($this->name, 'admin', 'checkMultipleExistence', array('valuesarray' => $usersArray, 'key' => 'uname')); if (!$usersInDB) { $this->registerError($this->__('Error! The users have been created but something has failed trying to get them from the database. ' . 'Now all these users do not have group.')); return false; } // add user to groups $error_membership = false; foreach ($importValues as $value) { $groupsArray = explode('|', $value['groups']); foreach ($groupsArray as $group) { $adduser = ModUtil::apiFunc('GroupsModule', 'user', 'adduser', array('gid' => $group, 'uid' => $usersInDB[$value['uname']]['uid'], 'verbose' => false)); if (!$adduser) { $error_membership = true; } } } if ($error_membership) { $this->registerError($this->__('Error! The users have been created but something has failed while trying to add the users to their groups. These users are not assigned to a group.')); return false; } // check if module Mailer is active $modinfo = ModUtil::getInfoFromName('Mailer'); if ($modinfo['state'] == ModUtil::TYPE_SYSTEM) { $sitename = System::getVar('sitename'); $siteurl = System::getBaseUrl(); $view = Zikula_View::getInstance($this->name, false); $view->assign('sitename', $sitename); $view->assign('siteurl', $siteurl); foreach ($importValues as $value) { if ($value['activated'] != UsersConstant::ACTIVATED_PENDING_REG) { $createEvent = new GenericEvent($value); $this->dispatcher->dispatch('user.account.create', $createEvent); } else { $createEvent = new GenericEvent($value); $this->dispatcher->dispatch('user.registration.create', $createEvent); } if ($value['activated'] && $value['sendmail']) { $view->assign('email', $value['email']); $view->assign('uname', $value['uname']); $view->assign('pass', $value['pass']); $message = $view->fetch('users_email_importnotify_html.tpl'); $subject = $this->__f('Password for %1$s from %2$s', array($value['uname'], $sitename)); $sendMessageArgs = array('toaddress' => $value['email'], 'subject' => $subject, 'body' => $message, 'html' => true); if (!ModUtil::apiFunc('MailerModule', 'user', 'sendMessage', $sendMessageArgs)) { $this->registerError($this->__f('Error! A problem has occurred while sending e-mail messages. The error happened trying to send a message to the user %s. After this error, no more messages were sent.', $value['uname'])); break; } } } } return true; }
/** * Create the default data for the users module. * * This function is only ever called once during the lifetime of a particular * module instance. * * @return void */ private function defaultdata() { $nowUTC = new \DateTime(null, new \DateTimeZone('UTC')); $nowUTCStr = $nowUTC->format(Constant::DATETIME_FORMAT); // Anonymous $record = array('uid' => 1, 'uname' => 'guest', 'email' => '', 'pass' => '', 'passreminder' => '', 'activated' => Constant::ACTIVATED_ACTIVE, 'approved_date' => '1970-01-01 00:00:00', 'approved_by' => 0, 'user_regdate' => '1970-01-01 00:00:00', 'lastlogin' => '1970-01-01 00:00:00', 'theme' => '', 'ublockon' => 0, 'ublock' => ''); $user = new \UsersModule\Entity\User(); $user->merge($record); $this->entityManager->persist($user); // Admin $record = array('uid' => 2, 'uname' => 'admin', 'email' => '', 'pass' => '1$$dc647eb65e6711e155375218212b3964', 'passreminder' => '', 'activated' => Constant::ACTIVATED_ACTIVE, 'approved_date' => $nowUTCStr, 'approved_by' => 2, 'user_regdate' => $nowUTCStr, 'lastlogin' => '1970-01-01 00:00:00', 'theme' => '', 'ublockon' => 0, 'ublock' => ''); $user = new \UsersModule\Entity\User(); $user->merge($record); $this->entityManager->persist($user); $this->entityManager->flush(); }