| Current Path : /var/www/html/components/com_jchat/Model/ |
| Current File : /var/www/html/components/com_jchat/Model/WebrtcModel.php |
<?php
namespace JExtstore\Component\JChat\Site\Model;
/**
* @package JCHAT::WEBRTC::components::com_jchat
* @subpackage models
* @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\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use JExtstore\Component\JChat\Administrator\Framework\Model as JChatModel;
use JExtstore\Component\JChat\Administrator\Framework\Helpers\Users as JChatHelpersUsers;
use JExtstore\Component\JChat\Administrator\Framework\Exception as JChatException;
/**
* Group users chat model
*
* @package JCHAT::WEBRTC::components::com_jchat
* @subpackage models
* @since 1.0
*/
class WebrtcModel extends JChatModel {
/**
* This peer1 session ID
* @access private
* @var int
*/
private $peer1;
/**
* Client response
* @access private
* @var array
*/
private $response;
/**
*
* Store call session for WebRTC video chat
*
* @param string $otherPeer
* @param string $sdp
* @param string $iceCandidate
* @param boolean $isCaller
* @param int $videoCam
* @access public
* @return boolean
*/
public function storeEntity($otherPeer = null, $sdp = null, $iceCandidate = null, $videoCam = null, $isCaller = 0) {
// Check if correct informations are feed to this server model
if(!$otherPeer) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_NOPEER_SPECIFIED'));
return $this->response;
}
// Missing informations sent by client, we can't go on
if(!$sdp && !$iceCandidate) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_NODATA_SPECIFIED'));
return $this->response;
}
// Check if callee has permissions to use videochat
$aclParamValue = $this->componentParams->get('allow_videochat', array(0));
// Ensure that the ACL parameter has no 'All groups' option selected
if(is_array($aclParamValue) && !in_array(0, $aclParamValue, false)) {
// Fetch current user id using session id of the remote callee peer
$query = "SELECT " .
$this->dbInstance->quoteName('userid') .
"\n FROM " .
$this->dbInstance->quoteName('#__session') .
"\n WHERE " .
$this->dbInstance->quoteName('session_id') . " = " . $this->dbInstance->quote($otherPeer);
$otherPeerUserID = $this->dbInstance->setQuery($query)->loadResult();
$otherPeerUser = Factory::getContainer()->get(\Joomla\CMS\User\UserFactoryInterface::class)->loadUserById($otherPeerUserID);
// If we are calling a super user skip the ACL permissions check, always allowed
if(!$otherPeerUser->authorise('core.admin')) {
$totalParamGroups = $aclParamValue;
// Cycle on all the group selected and retrieve the child groups
foreach ($aclParamValue as $aclParamGroup) {
$totalParamGroups = array_merge($totalParamGroups, JChatHelpersUsers::getChildGroups($this->dbInstance, $aclParamGroup));
}
// Remove duplicates
$totalParamGroups = array_unique($totalParamGroups);
// Fetch current user groups, but firstly user id using session id of the remote callee peer
$userGroups = $otherPeerUser->getAuthorisedGroups();
// Finally intersect to check ACL permission allowed
if(!array_intersect($totalParamGroups, $userGroups)) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_OTHERPEER_NOTALLOWED'), 'usermessage'=>true);
return $this->response;
}
}
}
// Check if the current caller is not already a callee from other peer, respect concurrency model
$queryNotCallee = "SELECT" .
$this->dbInstance->quoteName('peer1') .
"\n FROM #__jchat_webrtc" .
"\n WHERE " .
$this->dbInstance->quoteName('peer2') . " = " .
$this->dbInstance->quote($this->peer1);
$imIACallee = $this->dbInstance->setQuery($queryNotCallee)->loadResult();
if($isCaller) {
// This peer is already a callee from other peer, don't go on starting a collision call!
if($imIACallee) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_ALREADY_A_CALLEE'));
return $this->response;
}
// Check if the current callee is not already busy in another call, AKA is a callee of another user AKA has already a caller, respect concurrency model
$queryNotCallee = "SELECT" .
$this->dbInstance->quoteName('peer1') .
"\n FROM #__jchat_webrtc" .
"\n WHERE " .
$this->dbInstance->quoteName('peer2') . " = " .
$this->dbInstance->quote($otherPeer);
$hasAlreadyACaller = $this->dbInstance->setQuery($queryNotCallee)->loadResult();
if($hasAlreadyACaller && $hasAlreadyACaller != $this->peer1) {
// The other peer is already a callee from another peer not me, don't go on starting a collision call!
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_HAS_ALREADY_A_CALLER'), 'usermessage'=>true);
return $this->response;
}
// Check if the current callee is not already busy in another call, AKA is a caller of another user AKA has already a callee, respect concurrency model
$queryNotCaller = "SELECT" .
$this->dbInstance->quoteName('peer2') .
"\n FROM #__jchat_webrtc" .
"\n WHERE " .
$this->dbInstance->quoteName('peer1') . " = " .
$this->dbInstance->quote($otherPeer);
$isAlreadyACaller = $this->dbInstance->setQuery($queryNotCaller)->loadResult();
if($isAlreadyACaller) {
// The other peer is already a callee from another peer not me, don't go on starting a collision call!
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_HAS_ALREADY_A_CALLER'), 'usermessage'=>true);
return $this->response;
}
} else {
// This peer is no more a callee from other peer for example the caller hanged up, don't go on starting a collision call!
if(!$imIACallee) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>Text::_('COM_JCHAT_NOMORE_A_CALLEE'));
return $this->response;
}
}
// Exchange field and value
$field = $sdp ? 'sdp' : 'icecandidate';
$message = $sdp ? $sdp : $iceCandidate;
// Now execute insert/update query with feed data, the result will be a call start/accept
$query = "INSERT INTO #__jchat_webrtc" .
"\n (" . $this->dbInstance->quoteName('peer1') . "," .
$this->dbInstance->quoteName('peer2') . "," .
$this->dbInstance->quoteName($field) . "," .
$this->dbInstance->quoteName('videocam') . ")" .
"\n VALUES (" .
$this->dbInstance->quote($this->peer1) . "," .
$this->dbInstance->quote($otherPeer) . "," .
$this->dbInstance->quote($message) . "," .
$this->dbInstance->quote($videoCam) . ")" .
"\n ON DUPLICATE KEY UPDATE" .
$this->dbInstance->quoteName($field) . "=" .
$this->dbInstance->quote($message);
try {
$this->dbInstance->setQuery($query);
$this->dbInstance->execute ();
} catch (JChatException $e) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>$e->getMessage());
return $this->response;
} catch (\Exception $e) {
$jchatException = new JChatException($e->getMessage(), 'error');
$this->response['storing'] = array('status'=>false, 'exception_message'=>$jchatException->getMessage());
return $this->response;
}
// All went well
$this->response['storing'] = array('status'=>true);
return $this->response;
}
/**
* Completely deletes a conversation call, this means that caller or callee
* will delete both records and reset status of both peers
*
* @param int $ids
* @access public
* @return array
*/
public function deleteEntity($ids): array {
// Check if a specific peer remote ID has been specified. At last this is mandatory
$where = null;
if($ids) {
$where = "\n OR " .
$this->dbInstance->quoteName('peer1') . " = " .
$this->dbInstance->quote($ids);
}
// End a peers conversation call
$query = "DELETE FROM #__jchat_webrtc" .
"\n WHERE" .
$this->dbInstance->quoteName('peer1') . " = " .
$this->dbInstance->quote($this->peer1) .
$where;
try {
$this->dbInstance->setQuery($query);
$this->dbInstance->execute ();
} catch (JChatException $e) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>$e->getMessage());
return $this->response;
} catch (\Exception $e) {
$jchatException = new JChatException($e->getMessage(), 'error');
$this->response['storing'] = array('status'=>false, 'exception_message'=>$jchatException->getMessage());
return $this->response;
}
// All went well
$this->response['storing'] = array('status'=>true);
return $this->response;
}
/**
*
* Store contact user ID for current owner
*
* @param int $videoCam
* @access public
* @return boolean
*/
public function updateEntity($videoCam) {
// End a peers conversation call
$query = "UPDATE #__jchat_webrtc" .
"\n SET " .
$this->dbInstance->quoteName('videocam') . " = " . (int)$videoCam .
"\n WHERE" .
$this->dbInstance->quoteName('peer1') . " = " .
$this->dbInstance->quote($this->peer1);
try {
$this->dbInstance->setQuery($query);
$this->dbInstance->execute ();
} catch (JChatException $e) {
$this->response['storing'] = array('status'=>false, 'exception_message'=>$e->getMessage());
return $this->response;
} catch (\Exception $e) {
$jchatException = new JChatException($e->getMessage(), 'error');
$this->response['storing'] = array('status'=>false, 'exception_message'=>$jchatException->getMessage());
return $this->response;
}
// All went well
$this->response['storing'] = array('status'=>true);
return $this->response;
}
/**
* Class constructor
* @access public
* @param Object& $wpdb
* @param Object& $userObject
* @return Object &
*/
public function __construct($config = array(), ?MVCFactoryInterface $factory = null) {
// Store ssessionID peer1 caller
$this->peer1 = $config['sessiontable']->session_id;
// Get component params
$this->getComponentParams();
parent::__construct( $config, $factory );
}
}