rc-1.0.x-dev/src/Services/RcUser.php
src/Services/RcUser.php
<?php
namespace Drupal\rc\Services;
use ATDev\RocketChat\Chat;
use ATDev\RocketChat\Users\User;
use Drupal\Core\Config\ConfigFactory;
use Drupal\Core\Logger\LoggerChannelFactory;
/**
* Class RcUser.
*/
class RcUser extends RcAuth {
/**
* @var object
*/
protected object $user;
/**
* The module configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $config;
/**
* The logging service.
*
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @param \Drupal\Core\Config\ConfigFactory $config_factory
*
* @param \Drupal\Core\Logger\LoggerChannelFactory $logger_factory
* The logging service. *.
*/
public function __construct(
ConfigFactory $config_factory,
LoggerChannelFactory $logger_factory) {
$this->config = $config_factory->get('rc.settings');
$this->logger = $logger_factory->get('rc');
parent::__construct($config_factory);
}
/**
* Login user with Rocket Chat account credentials.
*
* @param string $userName
* @param string $password
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function login(string $userName = NULL, string $password = NULL) {
if ($userName && $password) {
// Set the Rocket Chat server URL.
Chat::setUrl($this->url());
// Login user.
$result = Chat::login($userName, $password);
if ($result) {
return $result;
}
// Log the error if there is no results.
$error = Chat::getError();
$this->logger->error('Rocket chat error while login: ' . $error);
}
}
/**
* Get the auth token using username.
* This method is handy when the Rocket Chat ID is not saved in the user
* object.
*
* @param $user
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function getAuthTokenByName($user) {
// Validate the username as required by RC account name limitations.
$userName = $this->validateUsername($user->getDisplayName());
// User the hashed user password as the RC account password.
$password = $user->getPassword();
// Set the Rocket Chat server URL.
Chat::setUrl($this->url());
// Get the personal auth token.
$result = RcChat::authToken($userName, $password, TRUE);
if ($result) {
// Retuen the auth token if exist.
return $result;
}
// Log the error.
$error = Chat::getError();
$this->logger->error('Rocket chat error while getting authToken: ' . $error);
}
/**
* Login to Rocket Chat server with admin account saved in configurations.
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function loginRcAdmin() {
return $this->login($this->user(), $this->secret());
}
/**
* Convert username to an acceptable Rocket Chat account name.
*
* @param string $userName
*
* @return array|string|string[]|null
*/
public function validateUsername(string $userName) {
// Replacing spaces and special character with dashes as Rocket Chat does
// not accept them in the username.
return preg_replace("![^a-z0-9]+!i", "-", $userName);
}
/**
* Login to Rocket Chat server using user account.
*
* @param object $user
*
* @return \ATDev\RocketChat\Users\User|bool|null
*/
public function loginUserByName(object $user): User|bool|null {
// Validate the username.
$userName = $this->validateUsername($user->getDisplayName());
// Use user hashed password as the password of RC account.
$password = $user->getPassword();
return $this->login($userName, $password);
}
/**
* Get the saved Rocket chat ID from the field_ricd field in the user object.
*
* @param object $user
*
* @return mixed
*/
public function getRcIdFromField(object $user) {
return $user->field_rcid->value;
}
/**
* Get Rocket Chat account information using username from user object.
*
* @param object $user
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function userInfoByName(object $user = NULL) {
if ($user) {
// Login to Rocket Chat server using Admin account.
if ($this->loginRcAdmin()) {
$rcUser = new User($this->validateUsername($user->getDisplayName()));
// Get account information.
$result = $rcUser->info();
if ($result) {
// Return info if exists.
return $result;
}
// Handling output with messages.
$this->logger->error('Rocket chat error: ' . $rcUser->getError());
}
}
}
/**
* Get account information using RC account ID field from user object.
*
* @param object|null $user
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function userInfoById(object $user = NULL) {
if ($user) {
// Get the Rocket Chat account Id from field.
$rcId = $this->getRcIdFromField($user);
if ($rcId) {
// Login to Rocket Chat server as admin.
if ($this->loginRcAdmin()) {
$rcUser = new User($rcId);
// Get account information if exists.
$result = $rcUser->info();
if ($result) {
return $result;
}
// Log the error.
$this->logger->error('Rocket chat error: ' . $rcUser->getError());
}
}
}
}
/**
* Check if Rocket Chat account exists for the user using the Rocket Chat
* Account ID if exists, and if not it checks by the username.
*
* @param $user
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function checkIfUserExist($user) {
// Get account info using field_rcid field from user object.
$userInfoById = $this->userInfoById($user);
if ($userInfoById) {
return $userInfoById;
}
// If no results, try getting account information by username.
$userInfoByName = $this->userInfoByName($user);
if ($userInfoByName) {
return $userInfoByName;
}
}
/**
* This method creates the chat account, set the Rocket Chat account ID & the
* token and saves it to the user entity.
* The $save variable is used to save the user object, this is helpful when
* using Drupal CRUD hooks as the preprocessors should not be used with
* $entity->save() which leads to infinite loop.
*
* @param object $user
* @param bool|null $save
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function createUser(object $user, bool $save = NULL) {
// Login in with Rocket chat admin to create new user.
if ($this->loginRcAdmin()) {
// Check if Rocket Chat account exists.
$checkIfUserExist = $this->checkIfUserExist($user);
// If Rocket Chat account does not exist.
if (!$checkIfUserExist) {
// Initiate the Rocket Chat account creation.
$rcUser = new User();
// Get the mapped fields. This method is separated to allow maximum
// flexibility that contains the minimum fields requirements of Rocket
// Chat account and allow mapping for custom fields.
$this->fieldMapping($user, $rcUser);
// Create the Rocket Chat account.
$result = $rcUser->create();
if ($result) {
// Set the Rocket Chat ID in the field.
$rcId = $result->getUserId();
$user->field_rcid->value = $rcId;
// Set the personal access token field.
$token = $result->generatePersonalAccessToken("mypersonaltoken", TRUE);
if (!$token) {
$token = $result
->regeneratePersonalAccessToken("mypersonaltoken");
}
$user->field_rc_token->value = $token;
// Invoke custom hook.
\Drupal::moduleHandler()->invokeAll('rc_create_user', [$user]);
// Log the successful creation of the Rocket Chat account.
$this->logger->info('New chat account of user ' . $user->getDisplayName() . ' is created');
// Save Drupal user object.
if ($save) {
$user->save();
}
return $result;
}
// Log error.
$this->logger->error('Rocket Chat error while creating user: ' . $rcUser->getError());
}
// If user exists continue to get the Rocket chat ID and personal access
// token fields.
// Set the Rocket Chat ID in the field.
$user->field_rcid->value = $checkIfUserExist->getUserId();
// Get and save the personal access token.
if ($checkIfUserExist->getPersonalAccessTokens()) {
// Set the personal access token.
$user->field_rc_token->value = $checkIfUserExist
->regeneratePersonalAccessToken("mypersonaltoken", TRUE);
}
else {
$user->field_rc_token->value = $checkIfUserExist
->generatePersonalAccessToken("mypersonaltoken");
}
// Save Drupal user object.
if ($save) {
$user->save();
}
return $checkIfUserExist;
}
}
/**
* This method updates the chat account, the token and saves it to
* the user entity.
* The $save variable is used to save the user object, this is helpful when
* using Drupal CRUD hooks as the preprocessors should not be used with
* $entity->save() which leads to infinite loop.
*
* @param object $user
* @param bool|null $save
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function updateUser(object $user, bool $save = NULL) {
// Check if user exists.
$checkIfUserExist = $this->checkIfUserExist($user->original ? $user->original : $user);
if ($checkIfUserExist) {
// Login as Rocket Chat admin.
if ($this->loginRcAdmin()) {
// Get the RC account ID from RC server.
$rcId = $checkIfUserExist->getUserId();
// Initiate update process.
$rcUser = new User($rcId);
// Get the mapped fields. This method is separated to allow maximum
// flexibility that contains the minimum fields requirements of Rocket
// Chat account and allow mapping for custom fields.
$this->fieldMapping($user, $rcUser);
// Update Rocket Chat account.
$result = $rcUser->update();
// Log error and return if there is an error.
if (!$result) {
$error = $rcUser->getError();
$this->logger->error('Rocket Chat error while updating user: ' . $error);
return;
}
// Set the Rocket Chat ID field if it does not exist.
if (!$user->field_rcid->value) {
$user->field_rcid->value = $rcId;
}
// Set the personal token field if it does not exist.
if (!$user->field_rc_token->value) {
// Generate token.
$token = $result->generatePersonalAccessToken('mypersonaltoken', TRUE);
// If no result, regenerate the token.
if (!$token) {
$token = $result->regeneratePersonalAccessToken("mypersonaltoken");
}
// Set personal access token field.
$user->field_rc_token->value = $token;
}
// Invoke custom hook.
\Drupal::moduleHandler()->invokeAll('rc_update_user', [$result, $user]);
// Log successful account update.
$this->logger->info('Chat account for user ' . $user->getDisplayName() . ' is updated');
// Save user entity.
if ($save) {
$user->save();
}
return $result;
}
}
}
/**
* Delete Rocket chat account.
*
* @param object $user
*
* @return \ATDev\RocketChat\Users\User|bool|void
*/
public function deleteUser(object $user) {
// Check if RC account exits.
$checkIfUserExist = $this->checkIfUserExist($user);
if ($checkIfUserExist) {
// Get the RC account ID.
$rcId = $checkIfUserExist->getUserId();
// Initiate RC account deletion.
$rcUser = new User($rcId);
// Delete RC account.
$result = $rcUser->delete();
// Log erros and return.
if (!$result) {
// Log the error.
$error = $rcUser->getError();
$this->logger->error('Rocket chat error: ' . $error);
return;
}
return $result;
}
}
/**
* Helper method to map Drupal user fields to Rocket Chat account fields.
* The main benefit is that it maps mandatory fields by default and allows to
* map custom fields of Drupal user entity to the Rocket chat account custom
* fields.
*
* @param object $user
* @param object $rcUser
*
* @return object
*/
public function fieldMapping(object $user, object &$rcUser) {
// Preparing the data from the $user object, this is a basic mapping to user
// entity fields.
$displayName = $user->getDisplayName();
$name = $this->validateUsername($displayName);
// Setting the matching data to the rcUser object.
$rcUser->setName($displayName);
$rcUser->setUsername($name);
$rcUser->setPassword($user->getPassword());
$rcUser->setEmail($user->getEmail());
// Map user roles, and set Rocket Chat admin role to Drupal users with
// Administrator role.
if ($this->config->get('user.add_admin_role')) {
if (in_array('administrator', $user->getRoles())) {
$rcUser->setRoles(['admin']);
}
else {
$rcUser->setRoles(['user']);
}
}
// Map the user status to Rocket Chat account status.
if ($user->isActive()) {
$rcUser->setActive(TRUE);
$rcUser->setVerified(TRUE);
}
else {
$rcUser->setActive(FALSE);
$rcUser->setVerified(FALSE);
}
// Invoke hook_field_mapping invoke to update field.
\Drupal::moduleHandler()->invokeAll('field_mapping_rc_alter', [$user, $rcUser]);
return $rcUser;
}
/**
* Get the personal access token from field_rc_token.
*
* @param object $user
*
* @return mixed
*/
public function getPersonalAccessToken(object $user) {
return $user->field_rc_token->value;
}
/**
* Generate personal access token for Rocket Chat account and save it to user
* object.
*
* @param object $user
*
* @return string|void
*/
public function generatePersonalAccessToken(object $user) {
// Login to Rocket Chat server by username.
if ($this->loginUserByName($user)) {
// Initiate personal access token generation.
$rcUser = Chat::me();
// Generate the personal access token.
$token = $rcUser->generatePersonalAccessToken("mypersonaltoken", TRUE);
// Log errors in no results.
if (!$token) {
$this->logger->error('Rocket chat error: ' . $rcUser->getError());
}
else {
// Set the token value to field in user object.
$user->field_rc_token->value = $token;
return $token;
}
}
// If login is not successful, show an error.
else {
\Drupal::messenger()->addError('Couldn\'t generate an access token, Contact your system administrator.');
}
}
/**
* Re-generate personal access token for Rocket Chat account and save it to
* user object.
*
* @param object $user
*
* @return string|void
*/
public function reGeneratePersonalAccessToken(object $user) {
// Login to Rocket Chat server by username.
if ($this->loginUserByName($user)) {
// Initiate the personal access token regeneration.
$rcUser = Chat::me();
// Regenerate the personal access token.
$token = $rcUser->regeneratePersonalAccessToken("mypersonaltoken");
// Log errors in no results.
if (!$token) {
// Try generating the token.
$token = $rcUser->generatePersonalAccessToken("mypersonaltoken", TRUE);
// If still no result, log errors.
if (!$token) {
$this->logger->error('Rocket chat error: ' . $rcUser->getError());
return;
}
}
// Set the token value to field in user object.
$user->field_rc_token->value = $token;
return $token;
}
}
}
