linked => connected ; spaces => tabs

Signed-off-by: Julien Veyssier <eneiluj@posteo.net>
This commit is contained in:
Julien Veyssier 2020-09-14 18:15:51 +02:00
parent 0d50fe4afe
commit a651a19cba
No known key found for this signature in database
GPG key ID: 4141FEE162030638
9 changed files with 337 additions and 337 deletions

View file

@ -28,25 +28,25 @@ use OCA\Moodle\Search\MoodleSearchProvider;
*/
class Application extends App implements IBootstrap {
public const APP_ID = 'integration_moodle';
public const APP_ID = 'integration_moodle';
/**
* Constructor
*
* @param array $urlParams
*/
public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);
/**
* Constructor
*
* @param array $urlParams
*/
public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);
$container = $this->getContainer();
}
$container = $this->getContainer();
}
public function register(IRegistrationContext $context): void {
$context->registerDashboardWidget(MoodleWidget::class);
$context->registerSearchProvider(MoodleSearchProvider::class);
}
public function register(IRegistrationContext $context): void {
$context->registerDashboardWidget(MoodleWidget::class);
$context->registerSearchProvider(MoodleSearchProvider::class);
}
public function boot(IBootContext $context): void {
}
public function boot(IBootContext $context): void {
}
}

View file

@ -36,82 +36,82 @@ use OCA\Moodle\AppInfo\Application;
class ConfigController extends Controller {
private $userId;
private $config;
private $dbconnection;
private $dbtype;
private $userId;
private $config;
private $dbconnection;
private $dbtype;
public function __construct($AppName,
IRequest $request,
IServerContainer $serverContainer,
IConfig $config,
IAppManager $appManager,
IAppData $appData,
IDBConnection $dbconnection,
IURLGenerator $urlGenerator,
IL10N $l,
ILogger $logger,
MoodleAPIService $moodleAPIService,
$userId) {
parent::__construct($AppName, $request);
$this->l = $l;
$this->userId = $userId;
$this->appData = $appData;
$this->serverContainer = $serverContainer;
$this->config = $config;
$this->dbconnection = $dbconnection;
$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
$this->moodleAPIService = $moodleAPIService;
}
public function __construct($AppName,
IRequest $request,
IServerContainer $serverContainer,
IConfig $config,
IAppManager $appManager,
IAppData $appData,
IDBConnection $dbconnection,
IURLGenerator $urlGenerator,
IL10N $l,
ILogger $logger,
MoodleAPIService $moodleAPIService,
$userId) {
parent::__construct($AppName, $request);
$this->l = $l;
$this->userId = $userId;
$this->appData = $appData;
$this->serverContainer = $serverContainer;
$this->config = $config;
$this->dbconnection = $dbconnection;
$this->urlGenerator = $urlGenerator;
$this->logger = $logger;
$this->moodleAPIService = $moodleAPIService;
}
/**
* set config values
* @NoAdminRequired
*/
public function setConfig($values) {
foreach ($values as $key => $value) {
$this->config->setUserValue($this->userId, Application::APP_ID, $key, $value);
}
$response = new DataResponse(1);
return $response;
}
/**
* set config values
* @NoAdminRequired
*/
public function setConfig($values) {
foreach ($values as $key => $value) {
$this->config->setUserValue($this->userId, Application::APP_ID, $key, $value);
}
$response = new DataResponse(1);
return $response;
}
/**
* receive oauth code and get oauth access token
* @NoAdminRequired
* @NoCSRFRequired
*/
public function oauthRedirect($code = '') {
$moodleUrl = $this->config->getUserValue($this->userId, Application::APP_ID, 'url', '');
$clientID = $this->config->getUserValue($this->userId, Application::APP_ID, 'client_id', '');
$clientSecret = $this->config->getUserValue($this->userId, Application::APP_ID, 'client_secret', '');
/**
* receive oauth code and get oauth access token
* @NoAdminRequired
* @NoCSRFRequired
*/
public function oauthRedirect($code = '') {
$moodleUrl = $this->config->getUserValue($this->userId, Application::APP_ID, 'url', '');
$clientID = $this->config->getUserValue($this->userId, Application::APP_ID, 'client_id', '');
$clientSecret = $this->config->getUserValue($this->userId, Application::APP_ID, 'client_secret', '');
if ($moodleUrl !== '' and $clientID !== '' and $clientSecret !== '' and $code !== '') {
$redirect_uri = $this->urlGenerator->linkToRouteAbsolute('integration_moodle.config.oauthRedirect');
$result = $this->moodleAPIService->requestOAuthAccessToken($moodleUrl, [
'client_id' => $clientID,
'client_secret' => $clientSecret,
'code' => $code,
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code',
'scope' => 'read write follow'
], 'POST');
if (is_array($result) and isset($result['access_token'])) {
$accessToken = $result['access_token'];
$this->config->setUserValue($this->userId, Application::APP_ID, 'token', $accessToken);
return new RedirectResponse(
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'linked-accounts']) .
'?moodleToken=success'
);
}
$result = $this->l->t('Error getting OAuth access token') . ' ' . $result;
} else {
$result = $this->l->t('Error during OAuth exchanges');
}
return new RedirectResponse(
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'linked-accounts']) .
'?moodleToken=error&message=' . urlencode($result)
);
}
if ($moodleUrl !== '' and $clientID !== '' and $clientSecret !== '' and $code !== '') {
$redirect_uri = $this->urlGenerator->linkToRouteAbsolute('integration_moodle.config.oauthRedirect');
$result = $this->moodleAPIService->requestOAuthAccessToken($moodleUrl, [
'client_id' => $clientID,
'client_secret' => $clientSecret,
'code' => $code,
'redirect_uri' => $redirect_uri,
'grant_type' => 'authorization_code',
'scope' => 'read write follow'
], 'POST');
if (is_array($result) and isset($result['access_token'])) {
$accessToken = $result['access_token'];
$this->config->setUserValue($this->userId, Application::APP_ID, 'token', $accessToken);
return new RedirectResponse(
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'connected-accounts']) .
'?moodleToken=success'
);
}
$result = $this->l->t('Error getting OAuth access token') . ' ' . $result;
} else {
$result = $this->l->t('Error during OAuth exchanges');
}
return new RedirectResponse(
$this->urlGenerator->linkToRoute('settings.PersonalSettings.index', ['section' => 'connected-accounts']) .
'?moodleToken=error&message=' . urlencode($result)
);
}
}

View file

@ -36,89 +36,89 @@ use OCA\Moodle\AppInfo\Application;
class MoodleAPIController extends Controller {
private $userId;
private $config;
private $dbconnection;
private $dbtype;
private $userId;
private $config;
private $dbconnection;
private $dbtype;
public function __construct($AppName,
IRequest $request,
IServerContainer $serverContainer,
IConfig $config,
IL10N $l10n,
IAppManager $appManager,
IAppData $appData,
ILogger $logger,
MoodleAPIService $moodleAPIService,
$userId) {
parent::__construct($AppName, $request);
$this->userId = $userId;
$this->l10n = $l10n;
$this->appData = $appData;
$this->serverContainer = $serverContainer;
$this->config = $config;
$this->logger = $logger;
$this->moodleAPIService = $moodleAPIService;
$this->accessToken = $this->config->getUserValue($this->userId, Application::APP_ID, 'token', '');
$this->moodleUrl = $this->config->getUserValue($this->userId, Application::APP_ID, 'url', '');
}
public function __construct($AppName,
IRequest $request,
IServerContainer $serverContainer,
IConfig $config,
IL10N $l10n,
IAppManager $appManager,
IAppData $appData,
ILogger $logger,
MoodleAPIService $moodleAPIService,
$userId) {
parent::__construct($AppName, $request);
$this->userId = $userId;
$this->l10n = $l10n;
$this->appData = $appData;
$this->serverContainer = $serverContainer;
$this->config = $config;
$this->logger = $logger;
$this->moodleAPIService = $moodleAPIService;
$this->accessToken = $this->config->getUserValue($this->userId, Application::APP_ID, 'token', '');
$this->moodleUrl = $this->config->getUserValue($this->userId, Application::APP_ID, 'url', '');
}
/**
* get notification list
* @NoAdminRequired
*/
public function getMoodleUrl() {
return new DataResponse($this->moodleUrl);
}
/**
* get notification list
* @NoAdminRequired
*/
public function getMoodleUrl() {
return new DataResponse($this->moodleUrl);
}
/**
* authenticate and get access token
* @NoAdminRequired
*/
public function getToken(string $login, string $password): DataResponse {
$result = $this->moodleAPIService->getToken($this->moodleUrl, $login, $password);
if (!isset($result['error'])) {
// we save the client ID and secret and give the client ID back to the UI
$this->config->setUserValue($this->userId, Application::APP_ID, 'token', $result['token']);
$this->config->setUserValue($this->userId, Application::APP_ID, 'privatetoken', $result['privatetoken']);
$data = [
'token' => $result['token']
];
$response = new DataResponse($data);
} else {
$response = new DataResponse($result, 401);
}
return $response;
}
/**
* authenticate and get access token
* @NoAdminRequired
*/
public function getToken(string $login, string $password): DataResponse {
$result = $this->moodleAPIService->getToken($this->moodleUrl, $login, $password);
if (!isset($result['error'])) {
// we save the client ID and secret and give the client ID back to the UI
$this->config->setUserValue($this->userId, Application::APP_ID, 'token', $result['token']);
$this->config->setUserValue($this->userId, Application::APP_ID, 'privatetoken', $result['privatetoken']);
$data = [
'token' => $result['token']
];
$response = new DataResponse($data);
} else {
$response = new DataResponse($result, 401);
}
return $response;
}
/**
* get moodle user avatar
* @NoAdminRequired
* @NoCSRFRequired
*/
public function getMoodleAvatar($url) {
$content = $this->moodleAPIService->getMoodleAvatar($url);
//return new DataResponse($content);
$response = new DataDisplayResponse($content);
$response->cacheFor(60*60*24);
return $response;
}
/**
* get moodle user avatar
* @NoAdminRequired
* @NoCSRFRequired
*/
public function getMoodleAvatar($url) {
$content = $this->moodleAPIService->getMoodleAvatar($url);
//return new DataResponse($content);
$response = new DataDisplayResponse($content);
$response->cacheFor(60*60*24);
return $response;
}
/**
* get notification list
* @NoAdminRequired
*/
public function getNotifications(?int $recentSince) {
if ($this->accessToken === '') {
return new DataResponse(['error' => 'plop'], 400);
}
$result = $this->moodleAPIService->getNotifications($this->moodleUrl, $this->accessToken, $recentSince);
if (!isset($result['error'])) {
$response = new DataResponse($result);
} else {
$response = new DataResponse($result, 401);
}
return $response;
}
/**
* get notification list
* @NoAdminRequired
*/
public function getNotifications(?int $recentSince) {
if ($this->accessToken === '') {
return new DataResponse(['error' => 'plop'], 400);
}
$result = $this->moodleAPIService->getNotifications($this->moodleUrl, $this->accessToken, $recentSince);
if (!isset($result['error'])) {
$response = new DataResponse($result);
} else {
$response = new DataResponse($result, 401);
}
return $response;
}
}

View file

@ -50,8 +50,8 @@ class MoodleWidget implements IWidget {
* @inheritDoc
*/
public function getTitle(): string {
return $this->l10n->t('Moodle notifications');
}
return $this->l10n->t('Moodle notifications');
}
/**
* @inheritDoc
@ -71,14 +71,14 @@ class MoodleWidget implements IWidget {
* @inheritDoc
*/
public function getUrl(): ?string {
return \OC::$server->getURLGenerator()->linkToRoute('settings.PersonalSettings.index', ['section' => 'linked-accounts']);
return \OC::$server->getURLGenerator()->linkToRoute('settings.PersonalSettings.index', ['section' => 'connected-accounts']);
}
/**
* @inheritDoc
*/
public function load(): void {
\OC_Util::addScript(Application::APP_ID, Application::APP_ID . '-dashboard');
\OC_Util::addStyle(Application::APP_ID, 'dashboard');
}
\OC_Util::addScript(Application::APP_ID, Application::APP_ID . '-dashboard');
\OC_Util::addStyle(Application::APP_ID, 'dashboard');
}
}

View file

@ -111,8 +111,8 @@ class MoodleSearchProvider implements IProvider {
$resultBills = [];
$moodleUrl = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'url', '');
$accessToken = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'token', '');
$moodleUrl = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'url', '');
$accessToken = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'token', '');
$searchEnabled = $this->config->getUserValue($user->getUID(), Application::APP_ID, 'search_enabled', '0') === '1';
if ($accessToken === '' || !$searchEnabled) {
return SearchResult::paginated($this->getName(), [], 0);

View file

@ -19,177 +19,177 @@ use OCA\Moodle\AppInfo\Application;
class MoodleAPIService {
private $l10n;
private $logger;
private $l10n;
private $logger;
/**
* Service to make requests to Moodle v1 API
*/
public function __construct (
string $appName,
ILogger $logger,
IL10N $l10n,
IClientService $clientService
) {
$this->appName = $appName;
$this->l10n = $l10n;
$this->logger = $logger;
$this->clientService = $clientService;
$this->client = $clientService->newClient();
}
/**
* Service to make requests to Moodle v1 API
*/
public function __construct (
string $appName,
ILogger $logger,
IL10N $l10n,
IClientService $clientService
) {
$this->appName = $appName;
$this->l10n = $l10n;
$this->logger = $logger;
$this->clientService = $clientService;
$this->client = $clientService->newClient();
}
public function getNotifications(string $url, string $accessToken, ?int $recentSince): array {
$params = [
'wstoken' => $accessToken,
'wsfunction' => 'block_recentlyaccesseditems_get_recent_items',
'moodlewsrestformat' => 'json',
];
$recentItems = $this->request($url, 'webservice/rest/server.php', $params);
public function getNotifications(string $url, string $accessToken, ?int $recentSince): array {
$params = [
'wstoken' => $accessToken,
'wsfunction' => 'block_recentlyaccesseditems_get_recent_items',
'moodlewsrestformat' => 'json',
];
$recentItems = $this->request($url, 'webservice/rest/server.php', $params);
if (isset($recentItems['error'])) {
return $recentItems;
}
if (isset($recentItems['error'])) {
return $recentItems;
}
// sort recent items by date DESC
$a = usort($recentItems, function($a, $b) {
$ta = $a['timeaccess'];
$tb = $b['timeaccess'];
return ($ta > $tb) ? -1 : 1;
});
// sort recent items by date DESC
$a = usort($recentItems, function($a, $b) {
$ta = $a['timeaccess'];
$tb = $b['timeaccess'];
return ($ta > $tb) ? -1 : 1;
});
// get courses and set 'time'
$courseIds = [];
foreach ($recentItems as $k => $recentItem) {
if (isset($recentItem['courseid']) && !in_array($recentItem['courseid'], $courseIds)) {
array_push($courseIds, $recentItem['courseid']);
}
$recentItems[$k]['time'] = $recentItem['timeaccess'];
$recentItems[$k]['type'] = 'recent';
}
// get courses and set 'time'
$courseIds = [];
foreach ($recentItems as $k => $recentItem) {
if (isset($recentItem['courseid']) && !in_array($recentItem['courseid'], $courseIds)) {
array_push($courseIds, $recentItem['courseid']);
}
$recentItems[$k]['time'] = $recentItem['timeaccess'];
$recentItems[$k]['type'] = 'recent';
}
// get upcoming events
$upcomingEvents = [];
foreach ($courseIds as $courseId) {
$params['wsfunction'] = 'core_calendar_get_calendar_upcoming_view';
$params['courseid'] = $courseId;
$oneRes = $this->request($url, 'webservice/rest/server.php', $params);
if (!isset($oneRes['error']) && isset($oneRes['events'])) {
$upcomingEvents = array_merge($upcomingEvents, $oneRes['events']);
}
}
// sort upcoming events by date ASC
$a = usort($upcomingEvents, function($a, $b) {
$ta = $a['timestart'];
$tb = $b['timestart'];
return ($ta < $tb) ? -1 : 1;
});
// get upcoming events
$upcomingEvents = [];
foreach ($courseIds as $courseId) {
$params['wsfunction'] = 'core_calendar_get_calendar_upcoming_view';
$params['courseid'] = $courseId;
$oneRes = $this->request($url, 'webservice/rest/server.php', $params);
if (!isset($oneRes['error']) && isset($oneRes['events'])) {
$upcomingEvents = array_merge($upcomingEvents, $oneRes['events']);
}
}
// sort upcoming events by date ASC
$a = usort($upcomingEvents, function($a, $b) {
$ta = $a['timestart'];
$tb = $b['timestart'];
return ($ta < $tb) ? -1 : 1;
});
foreach ($upcomingEvents as $k => $upcomingEvent) {
$upcomingEvents[$k]['time'] = $upcomingEvent['timestart'];
$upcomingEvents[$k]['type'] = 'event';
}
foreach ($upcomingEvents as $k => $upcomingEvent) {
$upcomingEvents[$k]['time'] = $upcomingEvent['timestart'];
$upcomingEvents[$k]['type'] = 'event';
}
// filter by date
if (!is_null($recentSince)) {
$recentItems = array_filter($recentItems, function($elem) use ($since) {
$ts = intval($elem['time']);
return $ts > $recentSince;
});
}
// filter by date
if (!is_null($recentSince)) {
$recentItems = array_filter($recentItems, function($elem) use ($since) {
$ts = intval($elem['time']);
return $ts > $recentSince;
});
}
return [
'recents' => array_values($recentItems),
'events' => array_values($upcomingEvents)
];
}
return [
'recents' => array_values($recentItems),
'events' => array_values($upcomingEvents)
];
}
public function search(string $url, string $accessToken, string $query): array {
$params = [
'wstoken' => $accessToken,
'wsfunction' => 'core_course_search_courses',
'moodlewsrestformat' => 'json',
'criterianame' => 'search',
'criteriavalue' => $query,
];
$searchResult = $this->request($url, 'webservice/rest/server.php', $params);
return $searchResult['courses'];
}
public function search(string $url, string $accessToken, string $query): array {
$params = [
'wstoken' => $accessToken,
'wsfunction' => 'core_course_search_courses',
'moodlewsrestformat' => 'json',
'criterianame' => 'search',
'criteriavalue' => $query,
];
$searchResult = $this->request($url, 'webservice/rest/server.php', $params);
return $searchResult['courses'];
}
public function getMoodleAvatar($url) {
$rawResult = $this->client->get($url)->getBody();
$success = preg_match('/<svg.*/', $rawResult, $matches);
//$result = $success === 1 ? $this->getBase64Svg($matches[0]) : $rawResult;
if ($success === 1) {
$result = '<?xml version="1.0"?>' . $matches[0];
//$result = $this->getBase64Svg($result);
} else {
$result = $rawResult;
}
//error_log('RESult['.$success.'] '.$result);
return $result;
}
public function getMoodleAvatar($url) {
$rawResult = $this->client->get($url)->getBody();
$success = preg_match('/<svg.*/', $rawResult, $matches);
//$result = $success === 1 ? $this->getBase64Svg($matches[0]) : $rawResult;
if ($success === 1) {
$result = '<?xml version="1.0"?>' . $matches[0];
//$result = $this->getBase64Svg($result);
} else {
$result = $rawResult;
}
//error_log('RESult['.$success.'] '.$result);
return $result;
}
private function getBase64Svg(string $svgString): string {
return 'data:image/svg+xml;base64,' . base64_encode($svgString);
}
private function getBase64Svg(string $svgString): string {
return 'data:image/svg+xml;base64,' . base64_encode($svgString);
}
public function request(string $url, string $endPoint, array $params = [], string $method = 'GET'): array {
try {
$url = $url . '/' . $endPoint;
$options = [
'headers' => [
'User-Agent' => 'Nextcloud Moodle integration',
]
];
public function request(string $url, string $endPoint, array $params = [], string $method = 'GET'): array {
try {
$url = $url . '/' . $endPoint;
$options = [
'headers' => [
'User-Agent' => 'Nextcloud Moodle integration',
]
];
if (count($params) > 0) {
if ($method === 'GET') {
// manage array parameters
$paramsContent = '';
foreach ($params as $key => $value) {
if (is_array($value)) {
foreach ($value as $oneArrayValue) {
$paramsContent .= $key . '[]=' . urlencode($oneArrayValue) . '&';
}
unset($params[$key]);
}
}
$paramsContent .= http_build_query($params);
$url .= '?' . $paramsContent;
} else {
$options['body'] = $params;
}
}
if (count($params) > 0) {
if ($method === 'GET') {
// manage array parameters
$paramsContent = '';
foreach ($params as $key => $value) {
if (is_array($value)) {
foreach ($value as $oneArrayValue) {
$paramsContent .= $key . '[]=' . urlencode($oneArrayValue) . '&';
}
unset($params[$key]);
}
}
$paramsContent .= http_build_query($params);
$url .= '?' . $paramsContent;
} else {
$options['body'] = $params;
}
}
if ($method === 'GET') {
$response = $this->client->get($url, $options);
} else if ($method === 'POST') {
$response = $this->client->post($url, $options);
} else if ($method === 'PUT') {
$response = $this->client->put($url, $options);
} else if ($method === 'DELETE') {
$response = $this->client->delete($url, $options);
}
$body = $response->getBody();
$respCode = $response->getStatusCode();
if ($method === 'GET') {
$response = $this->client->get($url, $options);
} else if ($method === 'POST') {
$response = $this->client->post($url, $options);
} else if ($method === 'PUT') {
$response = $this->client->put($url, $options);
} else if ($method === 'DELETE') {
$response = $this->client->delete($url, $options);
}
$body = $response->getBody();
$respCode = $response->getStatusCode();
if ($respCode >= 400) {
return ['error' => $this->l10n->t('Bad credentials')];
} else {
return json_decode($body, true);
}
} catch (\Exception $e) {
$this->logger->warning('Moodle API error : '.$e, array('app' => $this->appName));
return ['error' => $e->getMessage()];
}
}
if ($respCode >= 400) {
return ['error' => $this->l10n->t('Bad credentials')];
} else {
return json_decode($body, true);
}
} catch (\Exception $e) {
$this->logger->warning('Moodle API error : '.$e, array('app' => $this->appName));
return ['error' => $e->getMessage()];
}
}
public function getToken(string $moodleUrl, string $login, string $password): array {
$params = [
'username' => $login,
'password' => $password,
'service' => 'moodle_mobile_app',
];
return $this->request($moodleUrl, 'login/token.php', $params, 'POST');
}
public function getToken(string $moodleUrl, string $login, string $password): array {
$params = [
'username' => $login,
'password' => $password,
'service' => 'moodle_mobile_app',
];
return $this->request($moodleUrl, 'login/token.php', $params, 'POST');
}
}

View file

@ -55,7 +55,7 @@ class Personal implements ISettings {
}
public function getSection() {
return 'linked-accounts';
return 'connected-accounts';
}
public function getPriority() {

View file

@ -28,7 +28,7 @@ class PersonalSection implements IIconSection {
* @returns string
*/
public function getID() {
return 'linked-accounts'; //or a generic id if feasible
return 'connected-accounts'; //or a generic id if feasible
}
/**
@ -38,7 +38,7 @@ class PersonalSection implements IIconSection {
* @return string
*/
public function getName() {
return $this->l->t('Linked accounts');
return $this->l->t('Connected accounts');
}
/**

View file

@ -52,7 +52,7 @@ export default {
locale: getLocale(),
loop: null,
state: 'loading',
settingsUrl: generateUrl('/settings/user/linked-accounts'),
settingsUrl: generateUrl('/settings/user/connected-accounts'),
themingColor: OCA.Theming ? OCA.Theming.color.replace('#', '') : '0082C9',
}
},