Skip to content

Commit

Permalink
Plugin: External notification connect - refs BT#20443
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelFQC committed Jan 5, 2023
1 parent f062a1e commit e25066a
Show file tree
Hide file tree
Showing 14 changed files with 717 additions and 0 deletions.
3 changes: 3 additions & 0 deletions plugin/externalnotificationconnect/README.md
@@ -0,0 +1,3 @@
# External Notification Connect

Activate external notification system
5 changes: 5 additions & 0 deletions plugin/externalnotificationconnect/install.php
@@ -0,0 +1,5 @@
<?php

/* For licensing terms, see /license.txt */

ExternalNotificationConnectPlugin::create()->install();
18 changes: 18 additions & 0 deletions plugin/externalnotificationconnect/lang/english.php
@@ -0,0 +1,18 @@
<?php

/* For licensing terms, see /license.txt */

$strings['plugin_title'] = 'External Notification Connect';
$strings['plugin_comment'] = 'Activate external notification system';

$strings['tool_enable'] = 'Enabled';
$strings['auth_url'] = 'Authentication endpoint';
$strings['auth_url_help'] = 'URL for authentication API';
$strings['auth_username'] = 'Username for authentication';
$strings['auth_password'] = 'Password for authentication';
$strings['notification_url'] = 'Notification endpoint';
$strings['notification_url_help'] = 'URL for notification API';
$strings['notify_portfolio'] = 'Portfolio';
$strings['notify_portfolio_help'] = 'Put it to <i>Yes</i> to activate external notification for Portfolio tool actions';
$strings['notify_learnpath'] = 'Learning path';
$strings['notify_learnpath_help'] = 'Put it to <i>Yes</i> to activate external notification for learning path creation';
18 changes: 18 additions & 0 deletions plugin/externalnotificationconnect/lang/spanish.php
@@ -0,0 +1,18 @@
<?php

/* For licensing terms, see /license.txt */

$strings['plugin_title'] = 'Conexión de notificación externa';
$strings['plugin_comment'] = 'Activar un sistema de notificaciones externo';

$strings['tool_enable'] = 'Activado';
$strings['auth_url'] = 'Punto de conexión de autenticación';
$strings['auth_url_help'] = 'URL para API de autenticación';
$strings['auth_username'] = 'Nombre de usuario para autenticación';
$strings['auth_password'] = 'Contraseña para autenticación';
$strings['notification_url'] = 'Punto de conexión de la notificación';
$strings['notification_url_help'] = 'URL para la API de notificación';
$strings['notify_portfolio'] = 'Portafolio';
$strings['notify_portfolio_help'] = 'Ponerlo a <i>Sí</i> para activar la notificación externa para las acciones de la herramienta Portafolio';
$strings['notify_learnpath'] = 'Lecciones';
$strings['notify_learnpath_help'] = 'Ponerlo a <i>Sí</i> para activar la notificación externa para la creación de lecciones';
5 changes: 5 additions & 0 deletions plugin/externalnotificationconnect/plugin.php
@@ -0,0 +1,5 @@
<?php

/* For licensing terms, see /license.txt */

$plugin_info = ExternalNotificationConnectPlugin::create()->get_info();
71 changes: 71 additions & 0 deletions plugin/externalnotificationconnect/src/Entity/AccessToken.php
@@ -0,0 +1,71 @@
<?php

/* For licensing terms, see /license.txt */

namespace Chamilo\PluginBundle\ExternalNotificationConnect\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Table(name="plugin_ext_notif_conn_access_token")
* @ORM\Entity()
*/
class AccessToken
{
/**
* @var int
*
* @ORM\Id()
* @ORM\GeneratedValue(strategy="IDENTITY")
* @ORM\Column(name="id", type="integer")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="access_token", type="text")
*/
private $token;
/**
* @var bool
*
* @ORM\Column(name="is_valid", type="boolean")
*/
private $isValid;

public function getId(): int
{
return $this->id;
}

public function setId(int $id): AccessToken
{
$this->id = $id;

return $this;
}

public function getToken(): string
{
return $this->token;
}

public function setToken(string $token): AccessToken
{
$this->token = $token;

return $this;
}

public function isValid(): bool
{
return $this->isValid;
}

public function setIsValid(bool $isValid): AccessToken
{
$this->isValid = $isValid;

return $this;
}
}
@@ -0,0 +1,234 @@
<?php

/* For licensing terms, see /license.txt */

use Chamilo\PluginBundle\ExternalNotificationConnect\Entity\AccessToken;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\ORM\Tools\ToolsException;
use Firebase\JWT\JWT;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\ServerException;

class ExternalNotificationConnectPlugin extends Plugin implements HookPluginInterface
{
public const SETTING_AUTH_URL = 'auth_url';
public const SETTING_AUTH_USERNAME = 'auth_username';
public const SETTING_AUTH_PASSWORD = 'auth_password';
public const SETTING_NOTIFICATION_URL = 'notification_url';
public const SETTING_NOTIFY_PORTFOLIO = 'notify_portfolio';
public const SETTING_NOTIFY_LEARNPATH = 'notify_learnpath';

protected function __construct()
{
$author = [
'Angel Fernando Quiroz Campos <angel.quiroz@beeznest.com>',
];

$settings = [
'tool_enable' => 'boolean',
self::SETTING_AUTH_URL => 'text',
self::SETTING_AUTH_USERNAME => 'text',
self::SETTING_AUTH_PASSWORD => 'text',
self::SETTING_NOTIFICATION_URL => 'text',
self::SETTING_NOTIFY_PORTFOLIO => 'boolean',
self::SETTING_NOTIFY_LEARNPATH => 'boolean',
];

parent::__construct(
'1.0',
implode('; ', $author),
$settings
);
}

public static function create(): ?ExternalNotificationConnectPlugin
{
static $result = null;

return $result ?: $result = new self();
}

public function performActionsAfterConfigure(): ExternalNotificationConnectPlugin
{
$portfolioItemAddedEvent = HookPortfolioItemAdded::create();
$portfolioItemEditedEvent = HookPortfolioItemEdited::create();
$portfolioItemDeletedEvent = HookPortfolioItemDeleted::create();

$portfolioItemAddedObserver = ExternalNotificationConnectPortfolioItemAddedHookObserver::create();
$portfolioItemEditedObserver = ExternalNotificationConnectPortfolioItemEditedHookObserver::create();
$portfolioItemDeletedObserver = ExternalNotificationConnectPortfolioItemDeletedHookObserver::create();

if ('true' === $this->get(self::SETTING_NOTIFY_PORTFOLIO)) {
$portfolioItemAddedEvent->attach($portfolioItemAddedObserver);
$portfolioItemEditedEvent->attach($portfolioItemEditedObserver);
$portfolioItemDeletedEvent->attach($portfolioItemDeletedObserver);
} else {
$portfolioItemAddedEvent->detach($portfolioItemAddedObserver);
$portfolioItemEditedEvent->detach($portfolioItemEditedObserver);
$portfolioItemDeletedEvent->detach($portfolioItemDeletedObserver);
}

$lpCreatedEvent = HookLearningPathCreated::create();

$lpCreatedObserver = ExternalNotificationConnectLearningPathCreatedHookObserver::create();

if ('true' === $this->get(self::SETTING_NOTIFY_LEARNPATH)) {
$lpCreatedEvent->attach($lpCreatedObserver);
} else {
$lpCreatedEvent->detach($lpCreatedObserver);
}

return $this;
}

public function installHook()
{
}

public function uninstallHook()
{
$portfolioItemAddedEvent = HookPortfolioItemAdded::create();
$portfolioItemEditedEvent = HookPortfolioItemEdited::create();
$portfolioItemDeletedEvent = HookPortfolioItemDeleted::create();
$lpCreatedEvent = HookLearningPathCreated::create();

$portfolioItemAddedObserver = ExternalNotificationConnectPortfolioItemAddedHookObserver::create();
$portfolioItemEditedObserver = ExternalNotificationConnectPortfolioItemEditedHookObserver::create();
$portfolioItemDeletedObserver = ExternalNotificationConnectPortfolioItemDeletedHookObserver::create();
$lpCreatedObserver = ExternalNotificationConnectLearningPathCreatedHookObserver::create();

$portfolioItemAddedEvent->detach($portfolioItemAddedObserver);
$portfolioItemEditedEvent->detach($portfolioItemEditedObserver);
$portfolioItemDeletedEvent->detach($portfolioItemDeletedObserver);
$lpCreatedEvent->detach($lpCreatedObserver);
}

public function install()
{
$em = Database::getManager();

$schemaManager = $em->getConnection()->getSchemaManager();

$tableExists = $schemaManager->tablesExist(['plugin_ext_notif_conn_access_token']);

if ($tableExists) {
return;
}

$this->installDBTables();
$this->installHook();
}

public function uninstall()
{
$this->uninstallHook();
$this->uninstallDBTables();
}

/**
* @throws \Doctrine\ORM\OptimisticLockException
* @throws \Doctrine\ORM\ORMException
* @throws Exception
*/
public function getAccessToken()
{
$em = Database::getManager();
$tokenRepository = $em->getRepository(AccessToken::class);

$accessToken = $tokenRepository->findOneBy(['isValid' => true]);

if (!$accessToken) {
$newToken = $this->requestAuthToken();

$accessToken = (new AccessToken())
->setToken($newToken)
->setIsValid(true);

$em->persist($accessToken);
$em->flush();
} else {
$tks = explode('.', $accessToken->getToken());

$payload = json_decode(JWT::urlsafeB64Decode($tks[1]), true);

if (time() >= $payload['exp']) {
$accessToken->setIsValid(false);

$newToken = $this->requestAuthToken();

$accessToken = (new AccessToken())
->setToken($newToken)
->setIsValid(true);

$em->persist($accessToken);

$em->flush();
}
}

return $accessToken->getToken();
}

private function installDBTables()
{
$em = Database::getManager();

try {
(new SchemaTool($em))
->createSchema([
$em->getClassMetadata(AccessToken::class),
]);
} catch (ToolsException $e) {
return;
}
}

private function uninstallDBTables()
{
$em = Database::getManager();

(new SchemaTool($em))
->dropSchema([
$em->getClassMetadata(AccessToken::class),
]);
}

/**
* @throws Exception
*/
private function requestAuthToken(): string
{
$client = new Client();

try {
$response = $client->request(
'POST',
$this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_URL),
[
'json' => [
'email' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_USERNAME),
'password' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_PASSWORD),
],
]
);
} catch (ClientException|ServerException $e) {
if (!$e->hasResponse()) {
throw new Exception($e->getMessage());
}

$response = $e->getResponse();
} catch (GuzzleException $e) {
throw new Exception($e->getMessage());
}

$json = json_decode((string) $response->getBody(), true);

if (201 !== $json['status']) {
throw new Exception($json['message']);
}

return $json['data']['data']['token'];
}
}
@@ -0,0 +1,21 @@
<?php

/* For licensing terms, see /license.txt */

abstract class ExternalNotificationConnectHookObserver extends HookObserver
{
/**
* @var ExternalNotificationConnectPlugin
*/
protected $plugin;

protected function __construct()
{
parent::__construct(
'plugin/externalnotificationconnect/src/ExternalNotificationConnectPlugin.php',
'externalnotificationconnect'
);

$this->plugin = ExternalNotificationConnectPlugin::create();
}
}

0 comments on commit e25066a

Please sign in to comment.