MOBILE-3447 lti: Support disable InAppBrowser

main
Dani Palou 2020-06-12 13:54:50 +02:00
parent ecb4071971
commit 55d3af30c7
5 changed files with 157 additions and 37 deletions

View File

@ -16,6 +16,7 @@ import { Component, Optional, Injector } from '@angular/core';
import { Content } from 'ionic-angular';
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
import { AddonModLtiProvider, AddonModLtiLti } from '../../providers/lti';
import { AddonModLtiHelper } from '../../providers/helper';
/**
* Component that displays an LTI entry page.
@ -92,18 +93,6 @@ export class AddonModLtiIndexComponent extends CoreCourseModuleMainActivityCompo
* Launch the LTI.
*/
launch(): void {
this.ltiProvider.getLtiLaunchData(this.lti.id).then((launchData) => {
// "View" LTI.
this.ltiProvider.logView(this.lti.id, this.lti.name).then(() => {
this.checkCompletion();
}).catch((error) => {
// Ignore errors.
});
// Launch LTI.
return this.ltiProvider.launch(launchData.endpoint, launchData.parameters);
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'core.error', true);
});
AddonModLtiHelper.instance.getDataAndLaunch(this.courseId, this.module, this.lti);
}
}

View File

@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
import { AddonModLtiComponentsModule } from './components/components.module';
import { AddonModLtiModuleHandler } from './providers/module-handler';
import { AddonModLtiProvider } from './providers/lti';
import { AddonModLtiHelperProvider } from './providers/helper';
import { AddonModLtiLinkHandler } from './providers/link-handler';
import { AddonModLtiListLinkHandler } from './providers/list-link-handler';
import { AddonModLtiPrefetchHandler } from './providers/prefetch-handler';
@ -25,7 +26,8 @@ import { CoreCourseModulePrefetchDelegate } from '@core/course/providers/module-
// List of providers (without handlers).
export const ADDON_MOD_LTI_PROVIDERS: any[] = [
AddonModLtiProvider
AddonModLtiProvider,
AddonModLtiHelperProvider,
];
@NgModule({
@ -36,10 +38,11 @@ export const ADDON_MOD_LTI_PROVIDERS: any[] = [
],
providers: [
AddonModLtiProvider,
AddonModLtiHelperProvider,
AddonModLtiModuleHandler,
AddonModLtiLinkHandler,
AddonModLtiListLinkHandler,
AddonModLtiPrefetchHandler
AddonModLtiPrefetchHandler,
]
})
export class AddonModLtiModule {

View File

@ -0,0 +1,119 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { CoreEvents, CoreEventsProvider } from '@providers/events';
import { CoreSites } from '@providers/sites';
import { CoreDomUtils } from '@providers/utils/dom';
import { CoreCourse } from '@core/course/providers/course';
import { AddonModLti, AddonModLtiLti } from './lti';
import { makeSingleton } from '@singletons/core.singletons';
/**
* Service that provides some helper functions for LTI.
*/
@Injectable()
export class AddonModLtiHelperProvider {
protected pendingCheckCompletion: {[moduleId: string]: {courseId: number, module: any}} = {};
constructor(platform: Platform) {
platform.resume.subscribe(() => {
// User went back to the app, check pending completions.
for (const moduleId in this.pendingCheckCompletion) {
const data = this.pendingCheckCompletion[moduleId];
CoreCourse.instance.checkModuleCompletion(data.courseId, data.module.completiondata);
}
});
// Clear pending completion on logout.
CoreEvents.instance.on(CoreEventsProvider.LOGOUT, () => {
this.pendingCheckCompletion = {};
});
}
/**
* Get needed data and launch the LTI.
*
* @param courseId Course ID.
* @param module Module.
* @param lti LTI instance. If not provided it will be obtained.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
async getDataAndLaunch(courseId: number, module: any, lti?: AddonModLtiLti, siteId?: string): Promise<void> {
siteId = siteId || CoreSites.instance.getCurrentSiteId();
const modal = CoreDomUtils.instance.showModalLoading();
try {
const openInBrowser = await AddonModLti.instance.isOpenInAppBrowserDisabled(siteId);
if (openInBrowser) {
const site = await CoreSites.instance.getSite(siteId);
// The view event is triggered by the browser, mark the module as pending to check completion.
this.pendingCheckCompletion[module.id] = {
courseId,
module,
};
await site.openInBrowserWithAutoLogin(module.url);
} else {
// Open in app.
if (!lti) {
lti = await AddonModLti.instance.getLti(courseId, module.id);
}
const launchData = await AddonModLti.instance.getLtiLaunchData(lti.id);
// "View" LTI without blocking the UI.
this.logViewAndCheckCompletion(courseId, module, lti.id, lti.name, siteId);
// Launch LTI.
return AddonModLti.instance.launch(launchData.endpoint, launchData.parameters);
}
} catch (error) {
CoreDomUtils.instance.showErrorModalDefault(error, 'addon.mod_lti.errorgetlti', true);
} finally {
modal.dismiss();
}
}
/**
* Report the LTI as being viewed and check completion.
*
* @param courseId Course ID.
* @param module Module.
* @param ltiId LTI id.
* @param name Name of the lti.
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved when done.
*/
async logViewAndCheckCompletion(courseId: number, module: any, ltiId: number, name?: string, siteId?: string): Promise<void> {
try {
await AddonModLti.instance.logView(ltiId, name);
CoreCourse.instance.checkModuleCompletion(courseId, module.completiondata);
} catch (error) {
// Ignore errors.
}
}
}
export class AddonModLtiHelper extends makeSingleton(AddonModLtiHelperProvider) {}

View File

@ -24,6 +24,8 @@ import { CoreCourseLogHelperProvider } from '@core/course/providers/log-helper';
import { CoreSite } from '@classes/site';
import { CoreWSExternalWarning, CoreWSExternalFile } from '@providers/ws';
import { makeSingleton } from '@singletons/core.singletons';
/**
* Service that provides some features for LTI.
*/
@ -193,6 +195,30 @@ export class AddonModLtiProvider {
return this.sitesProvider.getCurrentSite().invalidateWsCacheForKey(this.getLtiLaunchDataCacheKey(id));
}
/**
* Check if open in InAppBrowser is disabled.
*
* @param siteId Site ID. If not defined, current site.
* @return Promise resolved with boolean: whether it's disabled.
*/
async isOpenInAppBrowserDisabled(siteId?: string): Promise<boolean> {
const site = await this.sitesProvider.getSite(siteId);
return this.isOpenInAppBrowserDisabledInSite(site);
}
/**
* Check if open in InAppBrowser is disabled.
*
* @param site Site. If not defined, current site.
* @return Whether it's disabled.
*/
isOpenInAppBrowserDisabledInSite(site?: CoreSite): boolean {
site = site || this.sitesProvider.getCurrentSite();
return site.isFeatureDisabled('CoreCourseModuleDelegate_AddonModLti:openInAppBrowser');
}
/**
* Launch LTI.
*
@ -233,6 +259,8 @@ export class AddonModLtiProvider {
}
}
export class AddonModLti extends makeSingleton(AddonModLtiProvider) {}
/**
* LTI returned by mod_lti_get_ltis_by_courses.
*/

View File

@ -18,11 +18,11 @@ import { DomSanitizer } from '@angular/platform-browser';
import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate';
import { CoreAppProvider } from '@providers/app';
import { CoreCourseProvider } from '@core/course/providers/course';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { CoreFilepoolProvider } from '@providers/filepool';
import { CoreSitesProvider } from '@providers/sites';
import { AddonModLtiIndexComponent } from '../components/index/index';
import { AddonModLtiProvider } from './lti';
import { AddonModLtiHelper } from './helper';
import { CoreConstants } from '@core/constants';
/**
@ -46,7 +46,6 @@ export class AddonModLtiModuleHandler implements CoreCourseModuleHandler {
constructor(private appProvider: CoreAppProvider,
private courseProvider: CoreCourseProvider,
private domUtils: CoreDomUtilsProvider,
private filepoolProvider: CoreFilepoolProvider,
private sitesProvider: CoreSitesProvider,
private ltiProvider: AddonModLtiProvider,
@ -85,26 +84,8 @@ export class AddonModLtiModuleHandler implements CoreCourseModuleHandler {
icon: 'link',
label: 'addon.mod_lti.launchactivity',
action: (event: Event, navCtrl: NavController, module: any, courseId: number): void => {
const modal = this.domUtils.showModalLoading();
// Get LTI and launch data.
this.ltiProvider.getLti(courseId, module.id).then((ltiData) => {
return this.ltiProvider.getLtiLaunchData(ltiData.id).then((launchData) => {
// "View" LTI.
this.ltiProvider.logView(ltiData.id, ltiData.name).then(() => {
this.courseProvider.checkModuleCompletion(courseId, module.completiondata);
}).catch(() => {
// Ignore errors.
});
// Launch LTI.
return this.ltiProvider.launch(launchData.endpoint, launchData.parameters);
});
}).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'addon.mod_lti.errorgetlti', true);
}).finally(() => {
modal.dismiss();
});
// Launch the LTI.
AddonModLtiHelper.instance.getDataAndLaunch(courseId, module);
}
}]
};