Passed
Push — master ( 212654...8aa330 )
by Angel Fernando Quiroz
11:04
created

ExternalNotificationConnectPlugin::create()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 2
nc 1
nop 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
    public function install()
54
    {
55
        $em = Database::getManager();
56
57
        $schemaManager = $em->getConnection()->getSchemaManager();
58
59
        $tableExists = $schemaManager->tablesExist(['plugin_ext_notif_conn_access_token']);
60
61
        if ($tableExists) {
62
            return;
63
        }
64
65
        $this->installDBTables();
66
    }
67
68
    public function uninstall()
69
    {
70
        $this->uninstallDBTables();
71
    }
72
73
    /**
74
     * @throws \Doctrine\ORM\OptimisticLockException
75
     * @throws \Doctrine\ORM\ORMException
76
     * @throws Exception
77
     */
78
    public function getAccessToken()
79
    {
80
        $em = Database::getManager();
81
        $tokenRepository = $em->getRepository(AccessToken::class);
82
83
        $accessToken = $tokenRepository->findOneBy(['isValid' => true]);
84
85
        if (!$accessToken) {
86
            $newToken = $this->requestAuthToken();
87
88
            $accessToken = (new AccessToken())
89
                ->setToken($newToken)
90
                ->setIsValid(true);
91
92
            $em->persist($accessToken);
93
            $em->flush();
94
        } else {
95
            $tks = explode('.', $accessToken->getToken());
96
97
            $payload = json_decode(JWT::urlsafeB64Decode($tks[1]), true);
98
99
            if (time() >= $payload['exp']) {
100
                $accessToken->setIsValid(false);
101
102
                $newToken = $this->requestAuthToken();
103
104
                $accessToken = (new AccessToken())
105
                    ->setToken($newToken)
106
                    ->setIsValid(true);
107
108
                $em->persist($accessToken);
109
110
                $em->flush();
111
            }
112
        }
113
114
        return $accessToken->getToken();
115
    }
116
117
    private function installDBTables()
118
    {
119
        $em = Database::getManager();
120
121
        try {
122
            (new SchemaTool($em))
123
                ->createSchema([
124
                    $em->getClassMetadata(AccessToken::class),
125
                ]);
126
        } catch (ToolsException $e) {
127
            return;
128
        }
129
    }
130
131
    private function uninstallDBTables()
132
    {
133
        $em = Database::getManager();
134
135
        (new SchemaTool($em))
136
            ->dropSchema([
137
                $em->getClassMetadata(AccessToken::class),
138
            ]);
139
    }
140
141
    /**
142
     * @throws Exception
143
     */
144
    private function requestAuthToken(): string
145
    {
146
        $client = new Client();
147
148
        try {
149
            $response = $client->request(
150
                'POST',
151
                $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_URL),
152
                [
153
                    'json' => [
154
                        'email' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_USERNAME),
155
                        'password' => $this->get(ExternalNotificationConnectPlugin::SETTING_AUTH_PASSWORD),
156
                    ],
157
                ]
158
            );
159
        } catch (ClientException|ServerException $e) {
160
            if (!$e->hasResponse()) {
161
                throw new Exception($e->getMessage());
162
            }
163
164
            $response = $e->getResponse();
165
        } catch (GuzzleException $e) {
166
            throw new Exception($e->getMessage());
167
        }
168
169
        $json = json_decode((string) $response->getBody(), true);
170
171
        if (201 !== $json['status']) {
172
            throw new Exception($json['message']);
173
        }
174
175
        return $json['data']['data']['token'];
176
    }
177
}
178