Passed
Push — master ( fe7dcd...466ab7 )
by Angel Fernando Quiroz
08:26
created

ExternalNotificationConnectPlugin::get_name()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\PluginBundle\ExternalNotificationConnect\Entity\AccessToken;
6
use Doctrine\ORM\Tools\SchemaTool;
7
use Doctrine\ORM\Tools\ToolsException;
8
use Firebase\JWT\JWT;
9
use GuzzleHttp\Client;
10
use GuzzleHttp\Exception\ClientException;
11
use GuzzleHttp\Exception\GuzzleException;
12
use GuzzleHttp\Exception\ServerException;
13
14
class ExternalNotificationConnectPlugin extends Plugin
15
{
16
    public const SETTING_AUTH_URL = 'auth_url';
17
    public const SETTING_AUTH_USERNAME = 'auth_username';
18
    public const SETTING_AUTH_PASSWORD = 'auth_password';
19
    public const SETTING_NOTIFICATION_URL = 'notification_url';
20
    public const SETTING_NOTIFY_PORTFOLIO = 'notify_portfolio';
21
    public const SETTING_NOTIFY_LEARNPATH = 'notify_learnpath';
22
23
    protected function __construct()
24
    {
25
        $author = [
26
            'Angel Fernando Quiroz Campos <[email protected]>',
27
        ];
28
29
        $settings = [
30
            'tool_enable' => 'boolean',
31
            self::SETTING_AUTH_URL => 'text',
32
            self::SETTING_AUTH_USERNAME => 'text',
33
            self::SETTING_AUTH_PASSWORD => 'text',
34
            self::SETTING_NOTIFICATION_URL => 'text',
35
            self::SETTING_NOTIFY_PORTFOLIO => 'boolean',
36
            self::SETTING_NOTIFY_LEARNPATH => 'boolean',
37
        ];
38
39
        parent::__construct(
40
            '1.0',
41
            implode('; ', $author),
42
            $settings
43
        );
44
    }
45
46
    public static function create(): ?ExternalNotificationConnectPlugin
47
    {
48
        static $result = null;
49
50
        return $result ?: $result = new self();
51
    }
52
53
    /**
54
     * @throws \Doctrine\DBAL\Exception
55
     */
56
    public function install()
57
    {
58
        $em = Database::getManager();
59
60
        $schemaManager = $em->getConnection()->createSchemaManager();
61
62
        $tableExists = $schemaManager->tablesExist(['plugin_ext_notif_conn_access_token']);
63
64
        if ($tableExists) {
65
            return;
66
        }
67
68
        $this->installDBTables();
69
    }
70
71
    public function uninstall()
72
    {
73
        $this->uninstallDBTables();
74
    }
75
76
    /**
77
     * @throws \Doctrine\ORM\OptimisticLockException
78
     * @throws \Doctrine\ORM\ORMException
79
     * @throws Exception
80
     */
81
    public function getAccessToken()
82
    {
83
        $em = Database::getManager();
84
        $tokenRepository = $em->getRepository(AccessToken::class);
85
86
        $accessToken = $tokenRepository->findOneBy(['isValid' => true]);
87
88
        if (!$accessToken) {
89
            $newToken = $this->requestAuthToken();
90
91
            $accessToken = (new AccessToken())
92
                ->setToken($newToken)
93
                ->setIsValid(true);
94
95
            $em->persist($accessToken);
96
            $em->flush();
97
        } else {
98
            $tks = explode('.', $accessToken->getToken());
99
100
            $payload = json_decode(JWT::urlsafeB64Decode($tks[1]), true);
101
102
            if (time() >= $payload['exp']) {
103
                $accessToken->setIsValid(false);
104
105
                $newToken = $this->requestAuthToken();
106
107
                $accessToken = (new AccessToken())
108
                    ->setToken($newToken)
109
                    ->setIsValid(true);
110
111
                $em->persist($accessToken);
112
113
                $em->flush();
114
            }
115
        }
116
117
        return $accessToken->getToken();
118
    }
119
120
    private function installDBTables()
121
    {
122
        $em = Database::getManager();
123
124
        try {
125
            (new SchemaTool($em))
126
                ->createSchema([
127
                    $em->getClassMetadata(AccessToken::class),
128
                ]);
129
        } catch (ToolsException $e) {
130
            return;
131
        }
132
    }
133
134
    private function uninstallDBTables()
135
    {
136
        $em = Database::getManager();
137
138
        (new SchemaTool($em))
139
            ->dropSchema([
140
                $em->getClassMetadata(AccessToken::class),
141
            ]);
142
    }
143
144
    /**
145
     * @throws Exception
146
     */
147
    private function requestAuthToken(): string
148
    {
149
        $client = new Client();
150
151
        try {
152
            $response = $client->request(
153
                'POST',
154
                $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_URL),
155
                [
156
                    'json' => [
157
                        'email' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_USERNAME),
158
                        'password' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_PASSWORD),
159
                    ],
160
                ]
161
            );
162
        } catch (ClientException|ServerException $e) {
163
            if (!$e->hasResponse()) {
164
                throw new Exception($e->getMessage());
165
            }
166
167
            $response = $e->getResponse();
168
        } catch (GuzzleException $e) {
169
            throw new Exception($e->getMessage());
170
        }
171
172
        $json = json_decode((string) $response->getBody(), true);
173
174
        if (201 !== $json['status']) {
175
            throw new Exception($json['message']);
176
        }
177
178
        return $json['data']['data']['token'];
179
    }
180
181
    public function get_name()
182
    {
183
        return 'ExternalNotificationConnect';
184
    }
185
}
186