This commit is contained in:
Xes
2025-08-14 22:39:38 +02:00
parent 3641e93527
commit 5403f346e3
3370 changed files with 327179 additions and 0 deletions

View File

@@ -0,0 +1,172 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\PluginBundle\UserRemoteService;
use Doctrine\ORM\Mapping as ORM;
use Exception;
/**
* UserRemoteService.
*
* @ORM\Table(name="plugin_user_remote_service")
* @ORM\Entity
*/
class UserRemoteService
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=255, nullable=false)
*/
protected $title;
/**
* @var string
*
* @ORM\Column(name="url", type="string", length=255, nullable=false)
*/
protected $url;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param int $id
*
* @return $this
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
/**
* @param string $title
*
* @return UserRemoteService
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* @return string
*/
public function getURL()
{
return $this->url;
}
/**
* @param string $url
*
* @return UserRemoteService
*/
public function setURL($url)
{
$this->url = $url;
return $this;
}
/**
* @return string
*/
public function getAccessURL($pluginName)
{
$accessUrl = api_get_path(WEB_PLUGIN_PATH).$pluginName."/redirect.php?serviceId=".$this->getId();
return $accessUrl;
}
/**
* Returns a user-specific URL, with two extra query string parameters : 'username' and 'hash'.
* 'hash' is generated using $salt and $userId.
*
* @param string $username the URL query parameter 'username'
* @param string $userId the user identifier, to build the hash
* @param string $salt the salt, to build the hash
*
* @throws Exception on hash generation failure
*
* @return string the custom user URL
*/
public function getCustomUserURL($username, $userId, $salt)
{
$hash = password_hash($salt.$userId, PASSWORD_BCRYPT);
if (false === $hash) {
throw new Exception('hash generation failed');
}
return sprintf(
'%s%s%s',
$this->url,
false === strpos($this->url, '?') ? '?' : '&',
http_build_query(
[
'username' => $username,
'hash' => $hash,
]
)
);
}
/**
* Returns a user-specific URL, with two extra query string parameters : 'uid' and 'hash'.
* 'hash' is generated using $salt and $userId.
*
* @param string $userId the user identifier, to build the hash and to include for the uid parameter
* @param string $salt the salt, to build the hash
*
* @throws Exception on hash generation failure
*
* @return string the custom user redirect URL
*/
public function getCustomUserRedirectURL($userId, $salt)
{
$hash = password_hash($salt.$userId, PASSWORD_BCRYPT);
if (false === $hash) {
throw new Exception('hash generation failed');
}
return sprintf(
'%s%s%s',
$this->url,
false === strpos($this->url, '?') ? '?' : '&',
http_build_query(
[
'uid' => $userId,
'hash' => $hash,
]
)
);
}
}

View File

@@ -0,0 +1,10 @@
User Remote Service Plugin
==========================
Appends site-specific iframe-targeted user-identifying links to the menu bar.
You can also hide the link from the menu and use the redirect link to use it as a link in a course.
After activation, configure a __salt__ then select region __menu_administrator__.
In the __Administration__ menu, in block __Plugins__,
you will find a link __User Remote Services__ to manage the services in the main menu (title and URL) and also get the redirect URL to use in a course.

View File

@@ -0,0 +1,18 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
api_protect_admin_script(true);
$plugin = UserRemoteServicePlugin::create();
Display::display_header($plugin->get_title());
echo $plugin->getCreationForm()->returnForm();
echo $plugin->getDeletionForm()->returnForm();
echo $plugin->getServiceHTMLTable();
Display::display_footer();

View File

@@ -0,0 +1,4 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../../main/inc/global.inc.php';

View File

@@ -0,0 +1,16 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
if (!api_user_is_login()) {
api_not_allowed(true);
}
$plugin = UserRemoteServicePlugin::create();
Display::display_header();
echo $plugin->getIFrame();
Display::display_footer();

View File

@@ -0,0 +1,10 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
if ('true' !== UserRemoteServicePlugin::create()->get_hide_link_from_navigation_menu()) {
foreach (UserRemoteServicePlugin::create()->getNavigationMenu() as $key => $menu) {
$template->params['menu'][$key] = $menu;
}
}

View File

@@ -0,0 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
UserRemoteServicePlugin::create()->install();

View File

@@ -0,0 +1,24 @@
<?php
/* For licensing terms, see /license.txt */
$strings['plugin_title'] = 'User Remote Services';
$strings['plugin_comment'] = 'Appends site-specific iframe-targeted user-identifying links to the menu bar.';
$strings['salt'] = 'Salt';
$strings['salt_help'] =
'Secret character string, used to generate the <em>hash</em> URL parameter. The longest, the best.
<br/>Remote user services can check the generated URL authenticity with the following PHP expression :
<br/><code class="php">password_verify($salt.$userId, $hash)</code>
<br/>Where
<br/><code>$salt</code> is this input value,
<br/><code>$userId</code> is the number of the user referenced by the <em>username</em> URL parameter value and
<br/><code>$hash</code> contains the <em>hash</em> URL parameter value.';
$strings['hide_link_from_navigation_menu'] = 'hide links from the menu';
// Please keep alphabetically sorted
$strings['CreateService'] = 'Add service to menu bar';
$strings['DeleteServices'] = 'Remove services from menu bar';
$strings['ServicesToDelete'] = 'Services to remove from menu bar';
$strings['ServiceTitle'] = 'Service title';
$strings['ServiceURL'] = 'Service web site location (URL)';
$strings['RedirectAccessURL'] = "URL to use in Chamilo to redirect user to the service (URL)";

View File

@@ -0,0 +1,26 @@
<?php
/* For licensing terms, see /license.txt */
$strings['plugin_title'] = "Services distants pour l'utilisateur";
$strings['plugin_comment'] =
"Ajoute à la barre de menu des liens spécifiques qui identifient l'utilisateur et qui s'ouvrent dans une iframe.";
/* Strings for settings */
$strings['salt'] = "Sel";
$strings['salt_help'] =
'Chaine de caractère secrète, utilisée pour générer le paramètre d\'URL <em>hash</em>. Plus il est long et mieux c\'est.
<br/>Les services distants peuvent vérifier la validité de l\'URL générée avec l\'expression PHP suivante :
<br/><code class="php">password_verify($salt.$userId, $hash)</code>
<br/>Où
<br/><code>$salt</code> est la valeur saisie ici,
<br/><code>$userId</code> est le numéro de l\'utilisateur auquel fait référence le paramètre d\'URL <em>username</em> et
<br/><code>$hash</code> représente la valeur du paramètre d\'URL <em>hash</em>.';
$strings['hide_link_from_navigation_menu'] = 'Masquer les liens dans le menu';
// Please keep alphabetically sorted
$strings['CreateService'] = "Ajouter le service au menu";
$strings['DeleteServices'] = "Retirer les services du menu";
$strings['ServicesToDelete'] = "Services à retirer du menu";
$strings['ServiceTitle'] = "Titre du service";
$strings['ServiceURL'] = "Adresse web du service (URL)";
$strings['RedirectAccessURL'] = "Adresse à utiliser pour rediriger l'utilisateur au service (URL)";

View File

@@ -0,0 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
$plugin_info = UserRemoteServicePlugin::create()->get_info();

View File

@@ -0,0 +1,13 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
if (!api_user_is_login()) {
api_not_allowed(true);
}
$plugin = UserRemoteServicePlugin::create();
header('Location: '.$plugin->getActiveServiceSpecificUserUrl());
exit;

View File

@@ -0,0 +1,309 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\PluginBundle\UserRemoteService\UserRemoteService;
use Doctrine\ORM\OptimisticLockException;
class UserRemoteServicePlugin extends Plugin
{
public const TABLE = 'plugin_user_remote_service';
/**
* UserRemoteServicePlugin constructor.
*/
protected function __construct()
{
parent::__construct(
'1.0',
'Sébastien Ducoulombier',
[
'salt' => 'text',
'hide_link_from_navigation_menu' => 'boolean',
]
);
$this->isAdminPlugin = true;
}
/**
* Caches and returns a single instance.
*
* @return UserRemoteServicePlugin
*/
public static function create()
{
static $result = null;
return $result ? $result : $result = new self();
}
/**
* Creates the plugin table.
*/
public function install()
{
Database::query(
sprintf(
'create table if not exists %s (
id int unsigned not null auto_increment primary key,
title varchar(255) not null,
url varchar(255) not null
)',
Database::get_main_table(self::TABLE)
)
);
}
/**
* Drops the plugin table.
*/
public function uninstall()
{
Database::query('drop table if exists '.Database::get_main_table(self::TABLE));
}
/**
* @return string the salt setting
*/
public function salt()
{
return $this->get('salt');
}
/**
* @return bool the value of hide_link_from_navigation_menu setting
*/
public function get_hide_link_from_navigation_menu()
{
return $this->get('hide_link_from_navigation_menu');
}
/**
* Retrieves the list of all services.
*
* @return UserRemoteService[]
*/
public function getServices()
{
return Database::getManager()->getRepository(
'Chamilo\PluginBundle\UserRemoteService\UserRemoteService'
)->findAll();
}
/**
* Adds a new service.
*
* @param string $title
* @param string $url
*
* @throws OptimisticLockException
*/
public function addService($title, $url)
{
$service = new UserRemoteService();
$service->setTitle($title);
$service->setURL($url);
Database::getManager()->persist($service);
Database::getManager()->flush();
}
/**
* Removes a service.
*
* @param UserRemoteService $service
*
* @throws OptimisticLockException
*/
public function removeService($service)
{
Database::getManager()->remove($service);
Database::getManager()->flush();
}
/**
* Updates a service.
*
* @param UserRemoteService $service
*
* @throws OptimisticLockException
*/
public function updateService($service)
{
Database::getManager()->persist($service);
Database::getManager()->flush();
}
/**
* Returns the active service id.
*
* @return int|null
*/
public function getActiveServiceId()
{
return array_key_exists('serviceId', $_REQUEST) ? intval($_REQUEST['serviceId']) : null;
}
/**
* Generates the menu items to be appended to the navigation array.
*
* @see \return_navigation_array
*
* @return array menu items
*/
public function getNavigationMenu()
{
$menu = [];
$activeServiceId = $this->getActiveServiceId();
foreach ($this->getServices() as $service) {
$key = 'service_'.$service->getId();
$current = $service->getId() == $activeServiceId;
$menu[$key] = [
'key' => $key,
'current' => $current ? 'active' : '',
'url' => sprintf(
'%s%s/iframe.php?serviceId=%d',
api_get_path(WEB_PLUGIN_PATH),
$this->get_name(),
$service->getId()
),
'title' => $service->getTitle(),
];
}
return $menu;
}
/**
* Generates and handles submission of the creation form.
*
* @throws OptimisticLockException
*
* @return FormValidator
*/
public function getCreationForm()
{
$form = new FormValidator('creationForm');
$titleText = $form->addText('title', get_lang('ServiceTitle'));
$urlText = $form->addText('url', get_lang('ServiceURL'));
$form->addButtonCreate(get_lang('CreateService'));
if ($form->validate()) {
$this->addService($titleText->getValue(), $urlText->getValue());
}
return $form;
}
/**
* Generates and handles submission of the service deletion form.
*
* @throws OptimisticLockException
*
* @return FormValidator
*/
public function getDeletionForm()
{
$form = new FormValidator('deletionForm');
$services = $this->getServices();
$options = [];
foreach ($services as $service) {
$options[$service->getId()] = $service->getTitle();
}
$serviceIdSelect = $form->addSelect('serviceId', get_lang('ServicesToDelete'), $options);
$serviceIdSelect->setMultiple(true);
$form->addButtonDelete(get_lang('DeleteServices'));
if ($form->validate()) {
foreach ($serviceIdSelect->getValue() as $serviceId) {
foreach ($services as $service) {
if ($service->getId() == $serviceId) {
$this->removeService($service);
}
}
}
}
return $form;
}
/**
* Generates the service HTML table.
*
* @return string
*/
public function getServiceHTMLTable()
{
$html = '';
$services = $this->getServices();
if (!empty($services)) {
$table = new HTML_Table('class="table"');
$table->addRow(
[
get_lang('ServiceTitle'),
get_lang('ServiceURL'),
get_lang('RedirectAccessURL'),
],
null,
'th'
);
foreach ($services as $service) {
$table->addRow([
$service->getTitle(),
$service->getURL(),
$service->getAccessURL($this->get_name()),
]);
}
$html = $table->toHtml();
}
return $html;
}
/**
* Retrieves one service.
*
* @param int $id the service identifier
*
* @return UserRemoteService the service
*/
public function getService($id)
{
return Database::getManager()->getRepository(
'Chamilo\PluginBundle\UserRemoteService\UserRemoteService'
)->find($id);
}
/**
* Generates the iframe HTML element to load a service URL.
*
* @throws Exception on hash generation failure
*
* @return string the iframe HTML element
*/
public function getIFrame()
{
$userInfo = api_get_user_info();
return sprintf(
'<div class="embed-responsive embed-responsive-16by9">
<iframe class="embed-responsive-item" src="%s"></iframe>
</div>',
$this->getService(
$this->getActiveServiceId()
)->getCustomUserURL($userInfo['username'], $userInfo['id'], $this->salt())
);
}
/**
* Generates the redirect user specific URL for redirection.
*
* @throws Exception on hash generation failure
*
* @return string the specific user redirect URL
*/
public function getActiveServiceSpecificUserUrl()
{
$userInfo = api_get_user_info();
return $this->getService(
$this->getActiveServiceId()
)->getCustomUserRedirectURL($userInfo['id'], $this->salt());
}
}

View File

@@ -0,0 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/config.php';
UserRemoteServicePlugin::create()->uninstall();