| Current Path : /var/www/html/administrator/components/com_jchat/Framework/Helpers/ |
| Current File : /var/www/html/administrator/components/com_jchat/Framework/Helpers/Users.php |
<?php
namespace JExtstore\Component\JChat\Administrator\Framework\Helpers;
/**
* @package JCHAT::components::com_jchat
* @subpackage framework
* @subpackage helpers
* @author Joomla! Extensions Store
* @copyright (C) 2024 - Joomla! Extensions Store
* @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Component\ComponentHelper;
use JExtstore\Component\JChat\Administrator\Framework\Helpers\Users as JChatHelpersUsers;
/**
* Utility class for chat users
*
* @package JCHAT::components::com_jchat
* @subpackage framework
* @subpackage helpers
* @since 1.0
*/
class Users {
/**
* Static variable for the ChatGPT bot session identifier across the app
*
* @access public
* @var string
*/
public static $chatGPTSessionIdentifier = '02jsess544jchat8b99gptc688bot1';
/**
* Cross system filemtime no bugged
* @access public
* @param string $filePath
* @return int
*/
public static function crossFileMTime($filePath) {
$time = filemtime($filePath);
$isDST = (date('I', $time) == 1);
$systemDST = (date('I') == 1);
$adjustment = 0;
if($isDST == false && $systemDST == true)
$adjustment = 3600;
else if($isDST == true && $systemDST == false)
$adjustment = -3600;
else
$adjustment = 0;
return ($time + $adjustment);
}
/**
* Effettua un reverse reduce sul'ID di sessione MD5 per arrivare
* ad una stringa da appendere al prefix del name assegnato ai guest users
*
* @access public
* @static
* @param string $sessionID
* @param Object $cParams
* @return string
*/
public static function generateRandomGuestNameSuffix($sessionID, $cParams) {
static $guestNamesCache = array();
static $db = null;
// First look if already generated guest name available in cache
if(array_key_exists($sessionID, $guestNamesCache)) {
return $guestNamesCache[$sessionID];
}
// If override guest name enabled and is guest this user and not in cache, try to check if t
if($cParams->get('allow_guest_overridename', true)) {
if(!is_object($db)) {
$db = Factory::getContainer()->get('DatabaseDriver');
}
$query = "SELECT ccs.override_name" .
"\n FROM #__jchat_sessionstatus AS ccs" .
"\n INNER JOIN #__session AS sess" .
"\n ON ccs.sessionid = sess.session_id" .
"\n WHERE sess.session_id = " . $db->quote($sessionID) .
"\n AND sess.client_id = 0 AND sess.guest = 1";
$overrideNameFound = $db->setQuery($query)->loadResult();
if($overrideNameFound) {
$guestNamesCache[$sessionID] = $overrideNameFound;
return $overrideNameFound;
}
}
// Fallback on the random generators algos
if($cParams->get('guests_name_algo', 'name_based') == 'name_based') {
$appendHashSuffix = null;
$guestNamesLength = $cParams->get('guests_name_length', '3');
$vowels = array("a", "e", "i", "o", "u", "a", "e", "i", "o", "u");
$consonants = array("b", "c", "d", "v", "g", "t", "f", "m", "r", "s");
// Get numeric hash substr
preg_match_all('/\d/i', $sessionID, $matches);
if(is_array($matches[0]) && count($matches[0])) {
for($i=0; $i<$guestNamesLength; $i++) {
if(isset($matches[0][$i])) {
$appendHashSuffix .= $consonants[$matches[0][$i]];
$appendHashSuffix .= $vowels[$matches[0][$i]];
}
}
}
$appendHashSuffix = ucfirst($appendHashSuffix);
// If odd random names, trim the last character
if($cParams->get('guests_name_odd', 'odd') == 'odd') {
$appendHashSuffix = substr($appendHashSuffix, 0, -1);
}
} else {
// Get numeric hash substr
preg_match_all('/\d/i', $sessionID, $matches);
if(is_array($matches[0]) && count($matches[0])) {
$numericHashArray = (float)(implode('', $matches[0]));
}
$appendHashSuffix = $numericHashArray;
// Limitiamo a 4 cifre il numeric suffix
$appendHashSuffix = $cParams->get('guestprefix', 'Guest') . substr($appendHashSuffix, 0, 4);
}
// First store in cache for next message
$guestNamesCache[$sessionID] = $appendHashSuffix;
return $appendHashSuffix;
}
/**
* Get names for users based on current state, logged or guest
*
* @access public
* @static
* @param string $sessionIDFrom
* @param string $sessionIDTo
* @param Object $componentParams
* @return array
*/
public static function getActualNames($sessionIDFrom, $sessionIDTo, $componentParams) {
// Load user table
$userTable = new \Joomla\CMS\Table\User(Factory::getContainer()->get('DatabaseDriver'));
// Load user session table
$app = Factory::getApplication();
$userSessionTable = $app->bootComponent('com_jchat')->getMVCFactory()->createTable('Session', 'Administrator');
// Current chosen user field name
$userFieldName = $componentParams->get('usefullname', 'username');
// Sender actualfrom
$userSessionTable->load($sessionIDFrom);
$userTable->load($userSessionTable->userid);
$actualFrom = $userTable->{$userFieldName};
if(!$actualFrom) {
$actualFrom = self::generateRandomGuestNameSuffix($sessionIDFrom, $componentParams);
}
// Receiver actualto
$receiverSessionTable = clone($userSessionTable);
$receiverSessionTable->load($sessionIDTo);
$userTable->load($receiverSessionTable->userid);
$actualTo = $userTable->{$userFieldName};
// If the other users has been logged out it's possible to recover the actualTo not using the session id but the popup tologged still valid
if(!$actualTo) {
$explicitToLogged = Factory::getApplication()->getInput()->getInt('tologged');
if($explicitToLogged) {
$userTable->load($explicitToLogged);
$actualTo = $userTable->{$userFieldName};
}
}
if(!$actualTo) {
$actualTo = self::generateRandomGuestNameSuffix($receiverSessionTable->session_id, $componentParams);
}
$result = array();
$result['fromActualName'] = $actualFrom;
$result['toActualName'] = $actualTo;
return $result;
}
/**
* Return current user session table object with singleton
* @access private
* @static
* @return Object
*/
public static function getSessionTable() {
// Lazy loading user session
static $userSessionTable;
if(!is_object($userSessionTable)) {
$app = Factory::getApplication();
$userSessionTable = $app->bootComponent('com_jchat')->getMVCFactory()->createTable('Session', 'Administrator');
$userSessionTable->load(session_id());
}
return $userSessionTable;
}
/**
* Singleton for session object
* @static
*
* @access private
* @return Object
*/
public static function getEmptySessionTable() {
static $sessionTable;
if(!is_object($sessionTable)) {
$app = Factory::getApplication();
$sessionTable = $app->bootComponent('com_jchat')->getMVCFactory()->createTable('Session', 'Administrator');
}
return $sessionTable;
}
/**
* Generate and assign avatars to users
* Caching system for $sessionID->avatar associated for the still same request
*
* @param string $sessionID
* @param int $explicitUserId
* @return string
*/
public static function getAvatar($sessionID, $explicitUserId = null) {
static $avatarCache = array();
$integrationType = null;
// Avoid uneeded queries
if(isset($avatarCache[$sessionID])) {
return $avatarCache[$sessionID];
}
$baseURL = Uri::root();
$cParams = ComponentHelper::getParams('com_jchat');
$avatarFormat = 'png';
$avatarSubPath = '/images/avatars/';
$userGender = null;
// Special case for ChatGPT bot avatar
if($sessionID == JChatHelpersUsers::$chatGPTSessionIdentifier && $cParams->get('chatgpt_ai_bot_avatar')) {
$chatGPTAvatar = $cParams->get('chatgpt_ai_bot_avatar');
$avatarCache[$sessionID] = $chatGPTAvatar;
return Uri::root() . $chatGPTAvatar;
}
// User session object
$userSessionTable = self::getEmptySessionTable();
if(!$explicitUserId) {
$userSessionTable->load($sessionID);
$userId = $userSessionTable->userid;
} else {
$userId = $explicitUserId;
}
$thirdPartyIntegration = $cParams->get('3pdintegration', false);
switch ($thirdPartyIntegration) {
case 'jomsocial':
$integrationType = 'jomsocial/';
$userGender = '_male';
break;
case 'easysocial':
$integrationType = 'easysocial/';
break;
case 'cbuilder':
$integrationType = 'cb/';
break;
}
// PRIORITY 1 - Try for JomSocial avatar if integration active
if($thirdPartyIntegration === 'jomsocial' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__community_users');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
// Check if remote server and specific uploaded avatar by default
if($cParams->get('easysocial_custom_avatar', 0)) {
$baseURL = rtrim($cParams->get('easysocial_custom_avatar_path', ''), '/') . '/';
}
$sql = "SELECT CONCAT('$baseURL', thumb) AS avatar" .
"\n FROM #__community_users AS cu" .
"\n INNER JOIN #__users AS u ON cu.userid = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND cu.thumb != ''";
$DBO->setQuery($sql);
if($userAvatar = $DBO->loadResult()) {
$avatarCache[$sessionID] = $userAvatar;
return $userAvatar;
}
// Select the gender of the user if available
$sql = "SELECT v.value AS gender" .
"\n FROM #__community_fields AS f" .
"\n LEFT JOIN #__community_fields_values AS v ON f.id = v.field_id" .
"\n WHERE f.fieldcode = " . $DBO->quote('FIELD_GENDER') .
"\n AND v.user_id = " . $DBO->quote($userId);
$DBO->setQuery($sql);
if($userAvatarGender = $DBO->loadResult()) {
$userGender = stripos($userAvatarGender, 'female') !== false ? '_female' : '_male';
}
}
}
// PRIORITY 1 - Try for EasySocial avatar if integration active
if($thirdPartyIntegration === 'easysocial' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__social_avatars');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
$easySocialAvatarPath = $cParams->get('easysocial_avatar_path', 'media/com_easysocial');
// Check if remote server and specific uploaded avatar by default
if($cParams->get('easysocial_custom_avatar', 0)) {
$baseURL = rtrim($cParams->get('easysocial_custom_avatar_path', ''), '/') . '/';
}
$sql = "SELECT CONCAT('" . $baseURL . "$easySocialAvatarPath/avatars/users/" . $userId . "/', square) AS avatar" .
"\n FROM #__social_avatars AS cu" .
"\n INNER JOIN #__users AS u ON cu.uid = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND cu.square != ''";
$DBO->setQuery($sql);
if($userUploadedAvatar = $DBO->loadResult()) {
$avatarCache[$sessionID] = $userUploadedAvatar;
}
// Override by profiles image if any chosen
$sql = "SELECT" .
"\n sda.small AS avatarname, sda.uid AS profileid" .
"\n FROM #__social_avatars AS sa" .
"\n INNER JOIN #__social_default_avatars AS sda ON sa.avatar_id = sda.id" .
"\n INNER JOIN #__users AS u ON sa.uid = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND sda.small != ''";
$DBO->setQuery($sql);
if($userAvatar = $DBO->loadObject()) {
$avatarCache[$sessionID] = Uri::root() . $easySocialAvatarPath . '/avatars/defaults/profiles/' . $userAvatar->profileid . '/' . $userAvatar->avatarname;
}
// If found a valid avatar by upload or profile avatar return it
if(isset($avatarCache[$sessionID]) && $avatarCache[$sessionID]) {
return $avatarCache[$sessionID];
}
}
}
// PRIORITY 1 - Try for CB avatar if integration active
if($thirdPartyIntegration === 'cbuilder' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__comprofiler');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
$sql = "SELECT CONCAT('" . $baseURL . "images/comprofiler/', avatar)" .
"\n FROM #__comprofiler AS cu" .
"\n INNER JOIN #__users AS u ON cu.id = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND cu.avatarapproved = 1 AND cu.avatar != ''";
$DBO->setQuery($sql);
if($userAvatar = $DBO->loadResult()) {
$avatarCache[$sessionID] = $userAvatar;
return $userAvatar;
}
}
}
// PRIORITY 1 - Try for Kunena avatar if integration active
if($thirdPartyIntegration === 'kunena' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__kunena_users');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
$kunenaAvatarSize = $cParams->get('kunena_avatars_resize_format', 'size36');
$sql = "SELECT CONCAT('" . $baseURL . "media/kunena/avatars/resized/$kunenaAvatarSize/', avatar) AS avatar" .
"\n FROM #__kunena_users AS cu" .
"\n INNER JOIN #__users AS u ON cu.userid = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND cu.avatar != ''";
$DBO->setQuery($sql);
if($userAvatar = $DBO->loadResult()) {
$avatarCache[$sessionID] = $userAvatar;
return $userAvatar;
}
}
}
// PRIORITY 1 - Try for EasyProfile avatar if integration active
if($thirdPartyIntegration === 'easyprofile' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__jsn_users');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
$sql = "SELECT CONCAT('" . $baseURL . "', REPLACE(avatar, '_', 'mini_')) AS avatar" .
"\n FROM #__jsn_users AS cu" .
"\n INNER JOIN #__users AS u ON cu.id = u.id" .
"\n WHERE u.id = " . $DBO->quote($userId) .
"\n AND cu.avatar != ''";
$DBO->setQuery($sql);
if($userAvatar = $DBO->loadResult()) {
$avatarCache[$sessionID] = $userAvatar;
return $userAvatar;
}
}
}
// PRIORITY 1 - Try for K2 avatar user if integration active
if($thirdPartyIntegration === 'k2user' && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$tableName = $DBO->replacePrefix('#__k2_users');
$query = method_exists ( $DBO, 'createQuery' ) ? $DBO->createQuery () : $DBO->getQuery ( true );
$query->setQuery("SHOW TABLES LIKE " . $DBO->quote($tableName));
$DBO->setQuery($query);
if ($table = $DBO->loadResult()) {
$sql = "SELECT CONCAT('" . $baseURL . "media/k2/users/', image)" .
"\n FROM #__k2_users AS cu" .
"\n WHERE cu.userID = " . $DBO->quote ( $userId ) .
"\n AND cu.image != ''";
$DBO->setQuery ( $sql );
if ($userAvatar = $DBO->loadResult ()) {
$avatarCache [$sessionID] = $userAvatar;
return $userAvatar;
}
}
}
// PRIORITY 1 - Try for Joomla contacts avatar user if the option is active
if($cParams->get('use_joomla_contacts_avatar', 0) && $userId) {
$DBO = Factory::getContainer()->get('DatabaseDriver');
$sql = "SELECT CONCAT('" . $baseURL . "', image)" .
"\n FROM #__contact_details AS cd" .
"\n WHERE cd.user_id = " . $DBO->quote ( $userId ) .
"\n AND cd.image != ''";
$DBO->setQuery ( $sql );
if ($userAvatar = $DBO->loadResult ()) {
$avatarCache [$sessionID] = $userAvatar;
return $userAvatar;
}
}
// Calculate avatar name based on md5 from user id and username
$calculatedHash = $userId ? 'uidavatar_' . $userId : 'gsidavatar_' . $sessionID;
$finalName = $calculatedHash . '.' . $avatarFormat;
$filePath = JPATH_COMPONENT_SITE . $avatarSubPath . $finalName;
// PRIORITY 2 - User uploaded avatar, check if user has uploaded avatar
if(file_exists($filePath)) {
$lastModTimeFile = self::crossFileMTime($filePath);
$userAvatar = Uri::root() . 'components/com_jchat/images/avatars/' . $finalName . '?nocache='.$lastModTimeFile;
$avatarCache[$sessionID] = $userAvatar;
} else {
// PRIORITY 3 - Default avatar image for my and other users
// Current user session table
$userSessionTable->load(session_id());
$am_i = $sessionID == $userSessionTable->session_id ? 'my' : 'other';
$defaultAvatar = 'default_' . $am_i . $userGender . '.png';
$userAvatar = Uri::root() . 'components/com_jchat/images/avatars/' . $integrationType . $defaultAvatar ;
$avatarCache[$sessionID] = $userAvatar;
}
return $userAvatar;
}
/**
* Get children user groups required for ACL permissions check
*
* @static
* @access public
* @param Object $db
* @param int $parentGroupId
* @return array
*/
public static function getChildGroups($db, $parentGroupId) {
// Find all the child groups given a parent group
try {
$query = method_exists ( $db, 'createQuery' ) ? $db->createQuery () : $db->getQuery ( true );
$query->select('DISTINCT(ug2.id)')
->from('#__usergroups as ug1')
->join('INNER', '#__usergroups AS ug2 ON ug2.lft > ug1.lft AND ug2.rgt < ug1.rgt')
->where('ug1.id=' . $db->quote($parentGroupId));
$db->setQuery($query);
$result = $db->loadColumn();
} catch (\Exception $e) {
return array();
}
return $result;
}
/**
* Get the total access levels registered in Joomla
*
* @static
* @access public
* @param Object $db
* @param int $parentGroupId
* @return array
*/
public static function getTotalAccessLevels($db) {
// Find all the access levels registered in Joomla
try {
$query = method_exists ( $db, 'createQuery' ) ? $db->createQuery () : $db->getQuery ( true );
$query->select($db->quoteName('a.id', 'value') . ', ' . $db->quoteName('a.title', 'text'))
->from($db->quoteName('#__viewlevels', 'a'))
->group($db->quoteName(array('a.id', 'a.title', 'a.ordering')))
->order($db->quoteName('a.ordering') . ' ASC')
->order($db->quoteName('title') . ' ASC');
// Get the options.
$db->setQuery($query);
$result = $db->loadObjectList();
} catch (\Exception $e) {
return array();
}
return $result;
}
/**
* Find if the FB user id is already registered in this Joomla system
* and in this case return the Joomla user id assigned
*
* @param string $userIdentifier
* It can be facebook app scoped user id or email address
* @param string $email
* @return int
*/
public static function getJoomlaId($userIdentifier, $authType = 'id') {
$db = Factory::getContainer()->get('DatabaseDriver');
// Mapping for auth types
$mapping = array('id'=>'fb_uid', 'email'=>'email');
$authType = $mapping[$authType];
$query = "SELECT login.j_uid" .
"\n FROM #__jchat_login AS login" .
"\n INNER JOIN #__users AS users" .
"\n ON login.j_uid = users.id" .
"\n WHERE login." . $authType . " = " . $db->quote ( $userIdentifier );
$db->setQuery ( $query );
$userExistsID = $db->loadResult ();
return $userExistsID;
}
}