forked from EVOgeek/Vmeda.Online
		
	MOBILE-2346 lti: Migrate LTI (external tool)
This commit is contained in:
		
							parent
							
								
									4c222b79af
								
							
						
					
					
						commit
						519256b0bb
					
				
							
								
								
									
										45
									
								
								src/addon/mod/lti/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/addon/mod/lti/components/components.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { NgModule } from '@angular/core';
 | 
			
		||||
import { CommonModule } from '@angular/common';
 | 
			
		||||
import { IonicModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreComponentsModule } from '@components/components.module';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { CoreCourseComponentsModule } from '@core/course/components/components.module';
 | 
			
		||||
import { AddonModLtiIndexComponent } from './index/index';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModLtiIndexComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CommonModule,
 | 
			
		||||
        IonicModule,
 | 
			
		||||
        TranslateModule.forChild(),
 | 
			
		||||
        CoreComponentsModule,
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        CoreCourseComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
    ],
 | 
			
		||||
    exports: [
 | 
			
		||||
        AddonModLtiIndexComponent,
 | 
			
		||||
    ],
 | 
			
		||||
    entryComponents: [
 | 
			
		||||
        AddonModLtiIndexComponent,
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModLtiComponentsModule {}
 | 
			
		||||
							
								
								
									
										23
									
								
								src/addon/mod/lti/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/addon/mod/lti/components/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
<!-- Buttons to add to the header. -->
 | 
			
		||||
<core-navbar-buttons end>
 | 
			
		||||
    <core-context-menu>
 | 
			
		||||
        <core-context-menu-item *ngIf="externalUrl" [priority]="900" [content]="'core.openinbrowser' | translate" [href]="externalUrl" [iconAction]="'open'"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="description" [priority]="800" [content]="'core.moduleintro' | translate" (action)="expandDescription()" [iconAction]="'arrow-forward'"></core-context-menu-item>
 | 
			
		||||
        <core-context-menu-item *ngIf="loaded && !hasOffline && isOnline" [priority]="700" [content]="'core.refresh' | translate" (action)="doRefresh(null, $event)" [iconAction]="refreshIcon" [closeOnClick]="false"></core-context-menu-item>
 | 
			
		||||
    </core-context-menu>
 | 
			
		||||
</core-navbar-buttons>
 | 
			
		||||
 | 
			
		||||
<!-- Content. -->
 | 
			
		||||
<core-loading [hideUntil]="loaded" class="core-loading-center">
 | 
			
		||||
 | 
			
		||||
    <core-course-module-description [description]="description" [component]="component" [componentId]="componentId"></core-course-module-description>
 | 
			
		||||
 | 
			
		||||
    <div padding-horizontal *ngIf="isValidUrl">
 | 
			
		||||
        <button ion-button block icon-left (click)="launch()">
 | 
			
		||||
            <ion-icon name="link"></ion-icon>
 | 
			
		||||
            {{ 'addon.mod_lti.launchactivity' | translate }}
 | 
			
		||||
        </button>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <ion-card class="core-info-card" *ngIf="!isValidUrl">{{ 'addon.mod_lti.errorinvalidlaunchurl' | translate }}</ion-card>
 | 
			
		||||
</core-loading>
 | 
			
		||||
							
								
								
									
										118
									
								
								src/addon/mod/lti/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/addon/mod/lti/components/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,118 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { Component, Optional, Injector } from '@angular/core';
 | 
			
		||||
import { Content } from 'ionic-angular';
 | 
			
		||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
 | 
			
		||||
import { CoreCourseModuleMainActivityComponent } from '@core/course/classes/main-activity-component';
 | 
			
		||||
import { AddonModLtiProvider } from '../../providers/lti';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Component that displays an LTI entry page.
 | 
			
		||||
 */
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'addon-mod-lti-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModLtiIndexComponent extends CoreCourseModuleMainActivityComponent {
 | 
			
		||||
    component = AddonModLtiProvider.COMPONENT;
 | 
			
		||||
    moduleName = 'lti';
 | 
			
		||||
 | 
			
		||||
    lti: any; // The LTI object.
 | 
			
		||||
    isValidUrl: boolean;
 | 
			
		||||
 | 
			
		||||
    protected fetchContentDefaultError = 'addon.mod_lti.errorgetlti';
 | 
			
		||||
 | 
			
		||||
    constructor(injector: Injector,
 | 
			
		||||
            @Optional() protected content: Content,
 | 
			
		||||
            private ltiProvider: AddonModLtiProvider,
 | 
			
		||||
            private urlUtils: CoreUrlUtilsProvider) {
 | 
			
		||||
        super(injector, content);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Component being initialized.
 | 
			
		||||
     */
 | 
			
		||||
    ngOnInit(): void {
 | 
			
		||||
        super.ngOnInit();
 | 
			
		||||
 | 
			
		||||
        this.loadContent(false, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check the completion.
 | 
			
		||||
     */
 | 
			
		||||
    protected checkCompletion(): void {
 | 
			
		||||
        this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the LTI data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {boolean} [refresh=false] If it's refreshing content.
 | 
			
		||||
     * @param {boolean} [sync=false] If the refresh is needs syncing.
 | 
			
		||||
     * @param {boolean} [showErrors=false] If show errors to the user of hide them.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected fetchContent(refresh: boolean = false, sync: boolean = false, showErrors: boolean = false): Promise<any> {
 | 
			
		||||
        return this.ltiProvider.getLti(this.courseId, this.module.id).then((ltiData) => {
 | 
			
		||||
            this.lti = ltiData;
 | 
			
		||||
 | 
			
		||||
            return this.ltiProvider.getLtiLaunchData(ltiData.id).then((launchData) => {
 | 
			
		||||
                this.lti.launchdata = launchData;
 | 
			
		||||
                this.description = this.lti.intro || this.description;
 | 
			
		||||
                this.isValidUrl = this.urlUtils.isHttpURL(launchData.endpoint);
 | 
			
		||||
                this.dataRetrieved.emit(this.lti);
 | 
			
		||||
            });
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            // All data obtained, now fill the context menu.
 | 
			
		||||
            this.fillContextMenu(refresh);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Perform the invalidate content function.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Resolved when done.
 | 
			
		||||
     */
 | 
			
		||||
    protected invalidateContent(): Promise<any> {
 | 
			
		||||
        const promises = [];
 | 
			
		||||
 | 
			
		||||
        promises.push(this.ltiProvider.invalidateLti(this.courseId));
 | 
			
		||||
        if (this.lti) {
 | 
			
		||||
            promises.push(this.ltiProvider.invalidateLtiLaunchData(this.lti.id));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Promise.all(promises);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Launch the LTI.
 | 
			
		||||
     */
 | 
			
		||||
    launch(): void {
 | 
			
		||||
        // "View" LTI.
 | 
			
		||||
        this.ltiProvider.logView(this.lti.id).then(() => {
 | 
			
		||||
            this.checkCompletion();
 | 
			
		||||
        }).catch((error) => {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Launch LTI.
 | 
			
		||||
        this.ltiProvider.launch(this.lti.launchdata.endpoint, this.lti.launchdata.parameters).catch((message) => {
 | 
			
		||||
            if (message) {
 | 
			
		||||
                this.domUtils.showErrorModal(message);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								src/addon/mod/lti/lang/en.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/addon/mod/lti/lang/en.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
    "errorgetlti": "Error getting module data.",
 | 
			
		||||
    "errorinvalidlaunchurl": "The launch URL is not valid.",
 | 
			
		||||
    "launchactivity": "Launch the activity"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								src/addon/mod/lti/lti.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/addon/mod/lti/lti.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { NgModule } from '@angular/core';
 | 
			
		||||
import { AddonModLtiComponentsModule } from './components/components.module';
 | 
			
		||||
import { AddonModLtiModuleHandler } from './providers/module-handler';
 | 
			
		||||
import { AddonModLtiProvider } from './providers/lti';
 | 
			
		||||
import { AddonModLtiLinkHandler } from './providers/link-handler';
 | 
			
		||||
import { CoreContentLinksDelegate } from '@core/contentlinks/providers/delegate';
 | 
			
		||||
import { CoreCourseModuleDelegate } from '@core/course/providers/module-delegate';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        AddonModLtiComponentsModule
 | 
			
		||||
    ],
 | 
			
		||||
    providers: [
 | 
			
		||||
        AddonModLtiProvider,
 | 
			
		||||
        AddonModLtiModuleHandler,
 | 
			
		||||
        AddonModLtiLinkHandler,
 | 
			
		||||
    ]
 | 
			
		||||
})
 | 
			
		||||
export class AddonModLtiModule {
 | 
			
		||||
    constructor(moduleDelegate: CoreCourseModuleDelegate, moduleHandler: AddonModLtiModuleHandler,
 | 
			
		||||
            contentLinksDelegate: CoreContentLinksDelegate, linkHandler: AddonModLtiLinkHandler) {
 | 
			
		||||
        moduleDelegate.registerHandler(moduleHandler);
 | 
			
		||||
        contentLinksDelegate.registerHandler(linkHandler);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								src/addon/mod/lti/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/addon/mod/lti/pages/index/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
<ion-header>
 | 
			
		||||
    <ion-navbar>
 | 
			
		||||
        <ion-title><core-format-text [text]="title"></core-format-text></ion-title>
 | 
			
		||||
 | 
			
		||||
        <ion-buttons end>
 | 
			
		||||
            <!-- The buttons defined by the component will be added in here. -->
 | 
			
		||||
        </ion-buttons>
 | 
			
		||||
    </ion-navbar>
 | 
			
		||||
</ion-header>
 | 
			
		||||
<ion-content>
 | 
			
		||||
    <addon-mod-lti-index [module]="module" [courseId]="courseId" (dataRetrieved)="updateData($event)"></addon-mod-lti-index>
 | 
			
		||||
</ion-content>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/addon/mod/lti/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/addon/mod/lti/pages/index/index.module.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { NgModule } from '@angular/core';
 | 
			
		||||
import { IonicPageModule } from 'ionic-angular';
 | 
			
		||||
import { TranslateModule } from '@ngx-translate/core';
 | 
			
		||||
import { CoreDirectivesModule } from '@directives/directives.module';
 | 
			
		||||
import { AddonModLtiComponentsModule } from '../../components/components.module';
 | 
			
		||||
import { AddonModLtiIndexPage } from './index';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
    declarations: [
 | 
			
		||||
        AddonModLtiIndexPage,
 | 
			
		||||
    ],
 | 
			
		||||
    imports: [
 | 
			
		||||
        CoreDirectivesModule,
 | 
			
		||||
        AddonModLtiComponentsModule,
 | 
			
		||||
        IonicPageModule.forChild(AddonModLtiIndexPage),
 | 
			
		||||
        TranslateModule.forChild()
 | 
			
		||||
    ],
 | 
			
		||||
})
 | 
			
		||||
export class AddonModLtiIndexPageModule {}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/addon/mod/lti/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								src/addon/mod/lti/pages/index/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { Component, ViewChild } from '@angular/core';
 | 
			
		||||
import { IonicPage, NavParams } from 'ionic-angular';
 | 
			
		||||
import { AddonModLtiIndexComponent } from '../../components/index/index';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Page that displays an LTI.
 | 
			
		||||
 */
 | 
			
		||||
@IonicPage({ segment: 'addon-mod-lti-index' })
 | 
			
		||||
@Component({
 | 
			
		||||
    selector: 'page-addon-mod-lti-index',
 | 
			
		||||
    templateUrl: 'index.html',
 | 
			
		||||
})
 | 
			
		||||
export class AddonModLtiIndexPage {
 | 
			
		||||
    @ViewChild(AddonModLtiIndexComponent) ltiComponent: AddonModLtiIndexComponent;
 | 
			
		||||
 | 
			
		||||
    title: string;
 | 
			
		||||
    module: any;
 | 
			
		||||
    courseId: number;
 | 
			
		||||
 | 
			
		||||
    constructor(navParams: NavParams) {
 | 
			
		||||
        this.module = navParams.get('module') || {};
 | 
			
		||||
        this.courseId = navParams.get('courseId');
 | 
			
		||||
        this.title = this.module.name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update some data based on the LTI instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} lti LTI instance.
 | 
			
		||||
     */
 | 
			
		||||
    updateData(lti: any): void {
 | 
			
		||||
        this.title = lti.name || this.title;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								src/addon/mod/lti/providers/link-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/addon/mod/lti/providers/link-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { CoreContentLinksModuleIndexHandler } from '@core/contentlinks/classes/module-index-handler';
 | 
			
		||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to treat links to LTI.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModLtiLinkHandler extends CoreContentLinksModuleIndexHandler {
 | 
			
		||||
    name = 'AddonModLtiLinkHandler';
 | 
			
		||||
 | 
			
		||||
    constructor(courseHelper: CoreCourseHelperProvider) {
 | 
			
		||||
        super(courseHelper, 'AddonModLti', 'lti');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										216
									
								
								src/addon/mod/lti/providers/lti.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								src/addon/mod/lti/providers/lti.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,216 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { TranslateService } from '@ngx-translate/core';
 | 
			
		||||
import { CoreFileProvider } from '@providers/file';
 | 
			
		||||
import { CoreSitesProvider } from '@providers/sites';
 | 
			
		||||
import { CoreTextUtilsProvider } from '@providers/utils/text';
 | 
			
		||||
import { CoreUtilsProvider } from '@providers/utils/utils';
 | 
			
		||||
import { CoreUrlUtilsProvider } from '@providers/utils/url';
 | 
			
		||||
 | 
			
		||||
export interface AddonModLtiParam {
 | 
			
		||||
    name: string;
 | 
			
		||||
    value: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Service that provides some features for LTI.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModLtiProvider {
 | 
			
		||||
    static COMPONENT = 'mmaModLti';
 | 
			
		||||
 | 
			
		||||
    protected ROOT_CACHE_KEY = 'mmaModLti:';
 | 
			
		||||
    protected LAUNCHER_FILE_NAME = 'lti_launcher.html';
 | 
			
		||||
 | 
			
		||||
    constructor(private fileProvider: CoreFileProvider,
 | 
			
		||||
            private sitesProvider: CoreSitesProvider,
 | 
			
		||||
            private textUtils: CoreTextUtilsProvider,
 | 
			
		||||
            private urlUtils: CoreUrlUtilsProvider,
 | 
			
		||||
            private utils: CoreUtilsProvider,
 | 
			
		||||
            private translate: TranslateService) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Delete launcher.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the launcher file is deleted.
 | 
			
		||||
     */
 | 
			
		||||
    deleteLauncher(): Promise<any> {
 | 
			
		||||
        return this.fileProvider.removeFile(this.LAUNCHER_FILE_NAME);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Generates a launcher file.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} url Launch URL.
 | 
			
		||||
     * @param {AddonModLtiParam[]} params Launch params.
 | 
			
		||||
     * @return {Promise<string>} Promise resolved with the file URL.
 | 
			
		||||
     */
 | 
			
		||||
    generateLauncher(url: string, params: AddonModLtiParam[]): Promise<string> {
 | 
			
		||||
        if (!this.fileProvider.isAvailable()) {
 | 
			
		||||
            return Promise.resolve(url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate a form with the params.
 | 
			
		||||
        let text = '<form action="' + url + '" name="ltiLaunchForm" ' +
 | 
			
		||||
                    'method="post" encType="application/x-www-form-urlencoded">\n';
 | 
			
		||||
        params.forEach((p) => {
 | 
			
		||||
            if (p.name == 'ext_submit') {
 | 
			
		||||
                text += '    <input type="submit"';
 | 
			
		||||
            } else {
 | 
			
		||||
                text += '    <input type="hidden" name="' + this.textUtils.escapeHTML(p.name) + '"';
 | 
			
		||||
            }
 | 
			
		||||
            text += ' value="' + this.textUtils.escapeHTML(p.value) + '"/>\n';
 | 
			
		||||
        });
 | 
			
		||||
        text += '</form>\n';
 | 
			
		||||
 | 
			
		||||
        // Add an in-line script to automatically submit the form.
 | 
			
		||||
        text += '<script type="text/javascript"> \n' +
 | 
			
		||||
            '    window.onload = function() { \n' +
 | 
			
		||||
            '        document.ltiLaunchForm.submit(); \n' +
 | 
			
		||||
            '    }; \n' +
 | 
			
		||||
            '</script> \n';
 | 
			
		||||
 | 
			
		||||
        return this.fileProvider.writeFile(this.LAUNCHER_FILE_NAME, text).then((entry) => {
 | 
			
		||||
            return entry.toURL();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a LTI.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} courseId Course ID.
 | 
			
		||||
     * @param {number} cmId Course module ID.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the LTI is retrieved.
 | 
			
		||||
     */
 | 
			
		||||
    getLti(courseId: number, cmId: number): Promise<any> {
 | 
			
		||||
        const params: any = {
 | 
			
		||||
            courseids: [courseId]
 | 
			
		||||
        };
 | 
			
		||||
        const preSets: any = {
 | 
			
		||||
            cacheKey: this.getLtiCacheKey(courseId)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.sitesProvider.getCurrentSite().read('mod_lti_get_ltis_by_courses', params, preSets).then((response) => {
 | 
			
		||||
            if (response.ltis) {
 | 
			
		||||
                const currentLti = response.ltis.find((lti) => lti.coursemodule == cmId);
 | 
			
		||||
                if (currentLti) {
 | 
			
		||||
                    return currentLti;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Promise.reject(null);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for LTI data WS calls.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} courseId Course ID.
 | 
			
		||||
     * @return {string} Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getLtiCacheKey(courseId: number): string {
 | 
			
		||||
        return this.ROOT_CACHE_KEY + 'lti:' + courseId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get a LTI launch data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} id LTI id.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the launch data is retrieved.
 | 
			
		||||
     */
 | 
			
		||||
    getLtiLaunchData(id: number): Promise<any> {
 | 
			
		||||
        const params: any = {
 | 
			
		||||
            toolid: id
 | 
			
		||||
        };
 | 
			
		||||
        const preSets = {
 | 
			
		||||
            cacheKey: this.getLtiLaunchDataCacheKey(id)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return this.sitesProvider.getCurrentSite().read('mod_lti_get_tool_launch_data', params, preSets).then((response) => {
 | 
			
		||||
            if (response.endpoint) {
 | 
			
		||||
                return response;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return Promise.reject(null);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get cache key for LTI launch data WS calls.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} id LTI id.
 | 
			
		||||
     * @return {string} Cache key.
 | 
			
		||||
     */
 | 
			
		||||
    protected getLtiLaunchDataCacheKey(id: number): string {
 | 
			
		||||
        return this.ROOT_CACHE_KEY + 'launch:' + id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidates LTI data.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} courseId Course ID.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateLti(courseId: number): Promise<any> {
 | 
			
		||||
        return this.sitesProvider.getCurrentSite().invalidateWsCacheForKey(this.getLtiCacheKey(courseId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Invalidates options.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {number} id LTI id.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the data is invalidated.
 | 
			
		||||
     */
 | 
			
		||||
    invalidateLtiLaunchData(id: number): Promise<any> {
 | 
			
		||||
        return this.sitesProvider.getCurrentSite().invalidateWsCacheForKey(this.getLtiLaunchDataCacheKey(id));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Launch LTI.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} url Launch URL.
 | 
			
		||||
     * @param {AddonModLtiParam[]} params Launch params.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the WS call is successful.
 | 
			
		||||
     */
 | 
			
		||||
    launch(url: string, params: AddonModLtiParam[]): Promise<any> {
 | 
			
		||||
        if (!this.urlUtils.isHttpURL(url)) {
 | 
			
		||||
            return Promise.reject(this.translate.instant('addon.mod_lti.errorinvalidlaunchurl'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Generate launcher and open it.
 | 
			
		||||
        return this.generateLauncher(url, params).then((url) => {
 | 
			
		||||
            this.utils.openInApp(url).show();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Report the LTI as being viewed.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {string} id LTI id.
 | 
			
		||||
     * @return {Promise<any>} Promise resolved when the WS call is successful.
 | 
			
		||||
     */
 | 
			
		||||
    logView(id: string): Promise<any> {
 | 
			
		||||
        if (id) {
 | 
			
		||||
            const params: any = {
 | 
			
		||||
                ltiid: id
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            return this.sitesProvider.getCurrentSite().write('mod_lti_view_lti', params);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return Promise.reject(null);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								src/addon/mod/lti/providers/module-handler.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								src/addon/mod/lti/providers/module-handler.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,126 @@
 | 
			
		||||
// (C) Copyright 2015 Martin Dougiamas
 | 
			
		||||
//
 | 
			
		||||
// 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 { NavController, NavOptions } from 'ionic-angular';
 | 
			
		||||
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';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handler to support LTI modules.
 | 
			
		||||
 */
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class AddonModLtiModuleHandler implements CoreCourseModuleHandler {
 | 
			
		||||
    name = 'AddonModLti';
 | 
			
		||||
    modName = 'lti';
 | 
			
		||||
 | 
			
		||||
    constructor(private appProvider: CoreAppProvider,
 | 
			
		||||
            private courseProvider: CoreCourseProvider,
 | 
			
		||||
            private domUtils: CoreDomUtilsProvider,
 | 
			
		||||
            private filepoolProvider: CoreFilepoolProvider,
 | 
			
		||||
            private sitesProvider: CoreSitesProvider,
 | 
			
		||||
            private ltiProvider: AddonModLtiProvider) {}
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if the handler is enabled on a site level.
 | 
			
		||||
     *
 | 
			
		||||
     * @return {boolean|Promise<boolean>} Whether or not the handler is enabled on a site level.
 | 
			
		||||
     */
 | 
			
		||||
    isEnabled(): boolean | Promise<boolean> {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the data required to display the module in the course contents view.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} module The module object.
 | 
			
		||||
     * @param {number} courseId The course ID.
 | 
			
		||||
     * @param {number} sectionId The section ID.
 | 
			
		||||
     * @return {CoreCourseModuleHandlerData} Data to render the module.
 | 
			
		||||
     */
 | 
			
		||||
    getData(module: any, courseId: number, sectionId: number): CoreCourseModuleHandlerData {
 | 
			
		||||
        const data: CoreCourseModuleHandlerData = {
 | 
			
		||||
            icon: this.courseProvider.getModuleIconSrc('lti'),
 | 
			
		||||
            title: module.name,
 | 
			
		||||
            class: 'addon-mod_lti-handler',
 | 
			
		||||
            action(event: Event, navCtrl: NavController, module: any, courseId: number, options: NavOptions): void {
 | 
			
		||||
                navCtrl.push('AddonModLtiIndexPage', {module: module, courseId: courseId}, options);
 | 
			
		||||
            },
 | 
			
		||||
            buttons: [{
 | 
			
		||||
                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).then(() => {
 | 
			
		||||
                                this.courseProvider.checkModuleCompletion(courseId, module.completionstatus);
 | 
			
		||||
                            }).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();
 | 
			
		||||
                    });
 | 
			
		||||
                }
 | 
			
		||||
            }]
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Handle custom icons.
 | 
			
		||||
        this.ltiProvider.getLti(courseId, module.id).then((ltiData) => {
 | 
			
		||||
            const icon = ltiData.secureicon || ltiData.icon;
 | 
			
		||||
            if (icon) {
 | 
			
		||||
                const siteId = this.sitesProvider.getCurrentSiteId();
 | 
			
		||||
                this.filepoolProvider.downloadUrl(siteId,  icon, false, AddonModLtiProvider.COMPONENT, module.id).then((url) => {
 | 
			
		||||
                    data.icon = url;
 | 
			
		||||
                }).catch(() => {
 | 
			
		||||
                    // Error downloading. If we're online we'll set the online url.
 | 
			
		||||
                    if (this.appProvider.isOnline()) {
 | 
			
		||||
                        data.icon = icon;
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
            // Ignore errors.
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        return data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the component to render the module. This is needed to support singleactivity course format.
 | 
			
		||||
     * The component returned must implement CoreCourseModuleMainComponent.
 | 
			
		||||
     *
 | 
			
		||||
     * @param {any} course The course object.
 | 
			
		||||
     * @param {any} module The module object.
 | 
			
		||||
     * @return {any} The component to use, undefined if not found.
 | 
			
		||||
     */
 | 
			
		||||
    getMainComponent(course: any, module: any): any {
 | 
			
		||||
        return AddonModLtiIndexComponent;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -82,6 +82,7 @@ import { AddonModBookModule } from '@addon/mod/book/book.module';
 | 
			
		||||
import { AddonModChatModule } from '@addon/mod/chat/chat.module';
 | 
			
		||||
import { AddonModChoiceModule } from '@addon/mod/choice/choice.module';
 | 
			
		||||
import { AddonModLabelModule } from '@addon/mod/label/label.module';
 | 
			
		||||
import { AddonModLtiModule } from '@addon/mod/lti/lti.module';
 | 
			
		||||
import { AddonModResourceModule } from '@addon/mod/resource/resource.module';
 | 
			
		||||
import { AddonModFeedbackModule } from '@addon/mod/feedback/feedback.module';
 | 
			
		||||
import { AddonModFolderModule } from '@addon/mod/folder/folder.module';
 | 
			
		||||
@ -187,6 +188,7 @@ export const CORE_PROVIDERS: any[] = [
 | 
			
		||||
        AddonModFeedbackModule,
 | 
			
		||||
        AddonModFolderModule,
 | 
			
		||||
        AddonModForumModule,
 | 
			
		||||
        AddonModLtiModule,
 | 
			
		||||
        AddonModPageModule,
 | 
			
		||||
        AddonModQuizModule,
 | 
			
		||||
        AddonModScormModule,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user