Skip to content

Commit 915fa57

Browse files
committed
Plugin: Restoring Whispeakauth - refs BT#14921
1 parent 5d93178 commit 915fa57

File tree

15 files changed

+844
-0
lines changed

15 files changed

+844
-0
lines changed

plugin/whispeakauth/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Speech authentication with Whispeak
2+
3+
Instructions:
4+
1. Install plugin in Chamilo.
5+
2. Set the plugin configuration with the token and API url. And enable the plugin.
6+
3. Set the `login_bottom` region to the plugin.
7+
4. Add `$_configuration['whispeak_auth_enabled'] = true;` to `configuration.php` file.
Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
<?php
2+
/* For licensing terms, see /license.txt */
3+
4+
use Chamilo\CoreBundle\Entity\ExtraField;
5+
use Chamilo\CoreBundle\Entity\ExtraFieldValues;
6+
use Chamilo\UserBundle\Entity\User;
7+
8+
/**
9+
* Class WhispeakAuthPlugin.
10+
*/
11+
class WhispeakAuthPlugin extends Plugin
12+
{
13+
const SETTING_ENABLE = 'enable';
14+
const SETTING_API_URL = 'api_url';
15+
const SETTING_TOKEN = 'token';
16+
const SETTING_INSTRUCTION = 'instruction';
17+
18+
const EXTRAFIELD_AUTH_UID = 'whispeak_auth_uid';
19+
20+
/**
21+
* StudentFollowUpPlugin constructor.
22+
*/
23+
protected function __construct()
24+
{
25+
parent::__construct(
26+
'0.1',
27+
'Angel Fernando Quiroz',
28+
[
29+
self::SETTING_ENABLE => 'boolean',
30+
self::SETTING_API_URL => 'text',
31+
self::SETTING_TOKEN => 'text',
32+
self::SETTING_INSTRUCTION => 'html',
33+
]
34+
);
35+
}
36+
37+
/**
38+
* @return WhispeakAuthPlugin
39+
*/
40+
public static function create()
41+
{
42+
static $result = null;
43+
44+
return $result ? $result : $result = new self();
45+
}
46+
47+
public function install()
48+
{
49+
UserManager::create_extra_field(
50+
self::EXTRAFIELD_AUTH_UID,
51+
\ExtraField::FIELD_TYPE_TEXT,
52+
$this->get_lang('Whispeak uid'),
53+
''
54+
);
55+
}
56+
57+
public function uninstall()
58+
{
59+
$extraField = self::getAuthUidExtraField();
60+
61+
if (empty($extraField)) {
62+
return;
63+
}
64+
65+
$em = Database::getManager();
66+
67+
$em->createQuery('DELETE FROM ChamiloCoreBundle:ExtraFieldValues efv WHERE efv.field = :field')
68+
->execute(['field' => $extraField]);
69+
70+
$em->remove($extraField);
71+
$em->flush();
72+
}
73+
74+
/**
75+
* @return ExtraField
76+
*/
77+
public static function getAuthUidExtraField()
78+
{
79+
$em = Database::getManager();
80+
$efRepo = $em->getRepository('ChamiloCoreBundle:ExtraField');
81+
82+
/** @var ExtraField $extraField */
83+
$extraField = $efRepo->findOneBy(
84+
[
85+
'variable' => self::EXTRAFIELD_AUTH_UID,
86+
'extraFieldType' => ExtraField::USER_FIELD_TYPE,
87+
]
88+
);
89+
90+
return $extraField;
91+
}
92+
93+
/**
94+
* @param int $userId
95+
*
96+
* @return ExtraFieldValues
97+
*/
98+
public static function getAuthUidValue($userId)
99+
{
100+
$extraField = self::getAuthUidExtraField();
101+
$em = Database::getManager();
102+
$efvRepo = $em->getRepository('ChamiloCoreBundle:ExtraFieldValues');
103+
104+
/** @var ExtraFieldValues $value */
105+
$value = $efvRepo->findOneBy(['field' => $extraField, 'itemId' => $userId]);
106+
107+
return $value;
108+
}
109+
110+
/**
111+
* @param int $userId
112+
*
113+
* @return bool
114+
*/
115+
public static function checkUserIsEnrolled($userId)
116+
{
117+
$value = self::getAuthUidValue($userId);
118+
119+
if (empty($value)) {
120+
return false;
121+
}
122+
123+
return !empty($value->getValue());
124+
}
125+
126+
/**
127+
* @return string
128+
*/
129+
public static function getEnrollmentUrl()
130+
{
131+
return api_get_path(WEB_PLUGIN_PATH).'whispeakauth/enrollment.php';
132+
}
133+
134+
/**
135+
* @param User $user
136+
* @param string $filePath
137+
*
138+
* @return array
139+
*/
140+
public function requestEnrollment(User $user, $filePath)
141+
{
142+
$metadata = [
143+
'motherTongue' => $user->getLanguage(),
144+
'spokenTongue' => $user->getLanguage(),
145+
'audioType' => 'pcm',
146+
];
147+
148+
return $this->sendRequest(
149+
'enrollment',
150+
$metadata,
151+
$user,
152+
$filePath
153+
);
154+
}
155+
156+
/**
157+
* @param User $user
158+
* @param string $uid
159+
*
160+
* @throws \Doctrine\ORM\OptimisticLockException
161+
*/
162+
public function saveEnrollment(User $user, $uid)
163+
{
164+
$em = Database::getManager();
165+
$value = self::getAuthUidValue($user->getId());
166+
167+
if (empty($value)) {
168+
$ef = self::getAuthUidExtraField();
169+
$now = new DateTime('now', new DateTimeZone('UTC'));
170+
171+
$value = new ExtraFieldValues();
172+
$value
173+
->setField($ef)
174+
->setItemId($user->getId())
175+
->setUpdatedAt($now);
176+
}
177+
178+
$value->setValue($uid);
179+
180+
$em->persist($value);
181+
$em->flush();
182+
}
183+
184+
public function requestAuthentify(User $user, $filePath)
185+
{
186+
$value = self::getAuthUidValue($user->getId());
187+
188+
if (empty($value)) {
189+
return null;
190+
}
191+
192+
$metadata = [
193+
'uid' => $value->getValue(),
194+
'audioType' => 'pcm',
195+
];
196+
197+
return $this->sendRequest(
198+
'authentify',
199+
$metadata,
200+
$user,
201+
$filePath
202+
);
203+
}
204+
205+
/**
206+
* @return string
207+
*/
208+
public function getAuthentifySampleText()
209+
{
210+
$phrases = [];
211+
212+
for ($i = 1; $i <= 6; $i++) {
213+
$phrases[] = $this->get_lang("AuthentifySampleText$i");
214+
}
215+
216+
$rand = array_rand($phrases, 1);
217+
218+
return $phrases[$rand];
219+
}
220+
221+
/**
222+
* @return bool
223+
*/
224+
public function toolIsEnabled()
225+
{
226+
return 'true' === $this->get(self::SETTING_ENABLE);
227+
}
228+
229+
/**
230+
* Access not allowed when tool is not enabled.
231+
*
232+
* @param bool $printHeaders Optional. Print headers.
233+
*/
234+
public function protectTool($printHeaders = true)
235+
{
236+
if ($this->toolIsEnabled()) {
237+
return;
238+
}
239+
240+
api_not_allowed($printHeaders);
241+
}
242+
243+
/**
244+
* @return string
245+
*/
246+
private function getApiUrl()
247+
{
248+
$url = $this->get(self::SETTING_API_URL);
249+
250+
return trim($url, " \t\n\r \v/");
251+
}
252+
253+
/**
254+
* @param string $endPoint
255+
* @param array $metadata
256+
* @param User $user
257+
* @param string $filePath
258+
*
259+
* @return array
260+
*/
261+
private function sendRequest($endPoint, array $metadata, User $user, $filePath)
262+
{
263+
$moderator = $user->getCreatorId() ?: $user->getId();
264+
$apiUrl = $this->getApiUrl()."/$endPoint";
265+
$headers = [
266+
//"Content-Type: application/x-www-form-urlencoded",
267+
"Authorization: Bearer ".$this->get(self::SETTING_TOKEN),
268+
];
269+
$post = [
270+
'metadata' => json_encode($metadata),
271+
'moderator' => "moderator_$moderator",
272+
'client' => base64_encode($user->getUserId()),
273+
'voice' => new CURLFile($filePath),
274+
];
275+
276+
$ch = curl_init();
277+
curl_setopt($ch, CURLOPT_URL, $apiUrl);
278+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
279+
curl_setopt($ch, CURLOPT_POST, true);
280+
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
281+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
282+
$result = curl_exec($ch);
283+
curl_close($ch);
284+
285+
$result = json_decode($result, true);
286+
287+
if (!empty($result['error'])) {
288+
return null;
289+
}
290+
291+
return json_decode($result, true);
292+
}
293+
}

0 commit comments

Comments
 (0)