From d7dd3acd8eb60696f955f24f463dbf9b5a89eea9 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Wed, 9 May 2018 12:33:06 +0200 Subject: [PATCH] MOBILE-2376 siteplugins: Support quiz access rules --- .../component/offlineattempts.ts | 1 + .../password/component/password.ts | 1 + .../timelimit/component/timelimit.ts | 1 + .../preflight-modal/preflight-modal.html | 4 +- .../pages/preflight-modal/preflight-modal.ts | 26 ++--- src/core/compile/providers/compile.ts | 2 + .../classes/{ => handlers}/base-handler.ts | 0 .../{ => handlers}/course-format-handler.ts | 2 +- .../{ => handlers}/course-option-handler.ts | 4 +- .../{ => handlers}/main-menu-handler.ts | 0 .../{ => handlers}/message-output-handler.ts | 0 .../classes/{ => handlers}/module-handler.ts | 2 +- .../{ => handlers}/module-prefetch-handler.ts | 2 +- .../question-behaviour-handler.ts | 2 +- .../{ => handlers}/question-handler.ts | 2 +- .../handlers/quiz-access-rule-handler.ts | 110 ++++++++++++++++++ .../{ => handlers}/settings-handler.ts | 0 .../classes/{ => handlers}/user-handler.ts | 2 +- .../user-profile-field-handler.ts | 2 +- .../components/components.module.ts | 10 +- .../quiz-access-rule/quiz-access-rule.html | 1 + .../quiz-access-rule/quiz-access-rule.ts | 57 +++++++++ src/core/siteplugins/providers/helper.ts | 100 ++++++++++++---- 23 files changed, 281 insertions(+), 50 deletions(-) rename src/core/siteplugins/classes/{ => handlers}/base-handler.ts (100%) rename src/core/siteplugins/classes/{ => handlers}/course-format-handler.ts (96%) rename src/core/siteplugins/classes/{ => handlers}/course-option-handler.ts (95%) rename src/core/siteplugins/classes/{ => handlers}/main-menu-handler.ts (100%) rename src/core/siteplugins/classes/{ => handlers}/message-output-handler.ts (100%) rename src/core/siteplugins/classes/{ => handlers}/module-handler.ts (97%) rename src/core/siteplugins/classes/{ => handlers}/module-prefetch-handler.ts (99%) rename src/core/siteplugins/classes/{ => handlers}/question-behaviour-handler.ts (94%) rename src/core/siteplugins/classes/{ => handlers}/question-handler.ts (94%) create mode 100644 src/core/siteplugins/classes/handlers/quiz-access-rule-handler.ts rename src/core/siteplugins/classes/{ => handlers}/settings-handler.ts (100%) rename src/core/siteplugins/classes/{ => handlers}/user-handler.ts (98%) rename src/core/siteplugins/classes/{ => handlers}/user-profile-field-handler.ts (95%) create mode 100644 src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.html create mode 100644 src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.ts diff --git a/src/addon/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts b/src/addon/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts index d23fd6927..f271fbff5 100644 --- a/src/addon/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts +++ b/src/addon/mod/quiz/accessrules/offlineattempts/component/offlineattempts.ts @@ -24,6 +24,7 @@ import { FormGroup, FormBuilder } from '@angular/forms'; }) export class AddonModQuizAccessOfflineAttemptsComponent implements OnInit { + @Input() rule: string; // The name of the rule. @Input() quiz: any; // The quiz the rule belongs to. @Input() attempt: any; // The attempt being started/continued. @Input() prefetch: boolean; // Whether the user is prefetching the quiz. diff --git a/src/addon/mod/quiz/accessrules/password/component/password.ts b/src/addon/mod/quiz/accessrules/password/component/password.ts index 6205901e4..00816c8f7 100644 --- a/src/addon/mod/quiz/accessrules/password/component/password.ts +++ b/src/addon/mod/quiz/accessrules/password/component/password.ts @@ -24,6 +24,7 @@ import { FormGroup, FormBuilder } from '@angular/forms'; }) export class AddonModQuizAccessPasswordComponent implements OnInit { + @Input() rule: string; // The name of the rule. @Input() quiz: any; // The quiz the rule belongs to. @Input() attempt: any; // The attempt being started/continued. @Input() prefetch: boolean; // Whether the user is prefetching the quiz. diff --git a/src/addon/mod/quiz/accessrules/timelimit/component/timelimit.ts b/src/addon/mod/quiz/accessrules/timelimit/component/timelimit.ts index 27d19d661..de23402d3 100644 --- a/src/addon/mod/quiz/accessrules/timelimit/component/timelimit.ts +++ b/src/addon/mod/quiz/accessrules/timelimit/component/timelimit.ts @@ -24,6 +24,7 @@ import { FormGroup } from '@angular/forms'; }) export class AddonModQuizAccessTimeLimitComponent { + @Input() rule: string; // The name of the rule. @Input() quiz: any; // The quiz the rule belongs to. @Input() attempt: any; // The attempt being started/continued. @Input() prefetch: boolean; // Whether the user is prefetching the quiz. diff --git a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html index db49a795e..716bb568f 100644 --- a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html +++ b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.html @@ -12,8 +12,8 @@
- - + +

Couldn't find the directive to render this access rule.

diff --git a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts index 48e704f54..6a9d3b124 100644 --- a/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts +++ b/src/addon/mod/quiz/pages/preflight-modal/preflight-modal.ts @@ -34,8 +34,7 @@ export class AddonModQuizPreflightModalPage implements OnInit { preflightForm: FormGroup; title: string; - accessRulesComponent: any[] = []; - data: any; + accessRulesData: {component: any, data: any}[] = []; // Components and data for each access rule. loaded: boolean; protected quiz: any; @@ -43,7 +42,6 @@ export class AddonModQuizPreflightModalPage implements OnInit { protected prefetch: boolean; protected siteId: string; protected rules: string[]; - protected renderedRules: string[] = []; constructor(params: NavParams, fb: FormBuilder, translate: TranslateService, sitesProvider: CoreSitesProvider, protected viewCtrl: ViewController, protected accessRuleDelegate: AddonModQuizAccessRuleDelegate, @@ -58,15 +56,6 @@ export class AddonModQuizPreflightModalPage implements OnInit { // Create an empty form group. The controls will be added by the access rules components. this.preflightForm = fb.group({}); - - // Create the data to pass to the access rules components. - this.data = { - quiz: this.quiz, - attempt: this.attempt, - prefetch: this.prefetch, - form: this.preflightForm, - siteId: this.siteId - }; } /** @@ -83,8 +72,17 @@ export class AddonModQuizPreflightModalPage implements OnInit { if (required) { return this.accessRuleDelegate.getPreflightComponent(rule, this.injector).then((component) => { if (component) { - this.renderedRules.push(rule); - this.accessRulesComponent.push(component); + this.accessRulesData.push({ + component: component, + data: { + rule: rule, + quiz: this.quiz, + attempt: this.attempt, + prefetch: this.prefetch, + form: this.preflightForm, + siteId: this.siteId + } + }); } }); } diff --git a/src/core/compile/providers/compile.ts b/src/core/compile/providers/compile.ts index 70b3c7fb1..68c67cc42 100644 --- a/src/core/compile/providers/compile.ts +++ b/src/core/compile/providers/compile.ts @@ -78,6 +78,7 @@ import { CoreSitePluginsCourseFormatComponent } from '@core/siteplugins/componen import { CoreSitePluginsQuestionComponent } from '@core/siteplugins/components/question/question'; import { CoreSitePluginsQuestionBehaviourComponent } from '@core/siteplugins/components/question-behaviour/question-behaviour'; import { CoreSitePluginsUserProfileFieldComponent } from '@core/siteplugins/components/user-profile-field/user-profile-field'; +import { CoreSitePluginsQuizAccessRuleComponent } from '@core/siteplugins/components/quiz-access-rule/quiz-access-rule'; /** * Service to provide functionalities regarding compiling dynamic HTML and Javascript. @@ -209,6 +210,7 @@ export class CoreCompileProvider { instance['CoreSitePluginsQuestionComponent'] = CoreSitePluginsQuestionComponent; instance['CoreSitePluginsQuestionBehaviourComponent'] = CoreSitePluginsQuestionBehaviourComponent; instance['CoreSitePluginsUserProfileFieldComponent'] = CoreSitePluginsUserProfileFieldComponent; + instance['CoreSitePluginsQuizAccessRuleComponent'] = CoreSitePluginsQuizAccessRuleComponent; } /** diff --git a/src/core/siteplugins/classes/base-handler.ts b/src/core/siteplugins/classes/handlers/base-handler.ts similarity index 100% rename from src/core/siteplugins/classes/base-handler.ts rename to src/core/siteplugins/classes/handlers/base-handler.ts diff --git a/src/core/siteplugins/classes/course-format-handler.ts b/src/core/siteplugins/classes/handlers/course-format-handler.ts similarity index 96% rename from src/core/siteplugins/classes/course-format-handler.ts rename to src/core/siteplugins/classes/handlers/course-format-handler.ts index ed31e6db4..b8453ca2a 100644 --- a/src/core/siteplugins/classes/course-format-handler.ts +++ b/src/core/siteplugins/classes/handlers/course-format-handler.ts @@ -15,7 +15,7 @@ import { Injector } from '@angular/core'; import { CoreCourseFormatHandler } from '@core/course/providers/format-delegate'; import { CoreSitePluginsBaseHandler } from './base-handler'; -import { CoreSitePluginsCourseFormatComponent } from '../components/course-format/course-format'; +import { CoreSitePluginsCourseFormatComponent } from '../../components/course-format/course-format'; /** * Handler to support a course format using a site plugin. diff --git a/src/core/siteplugins/classes/course-option-handler.ts b/src/core/siteplugins/classes/handlers/course-option-handler.ts similarity index 95% rename from src/core/siteplugins/classes/course-option-handler.ts rename to src/core/siteplugins/classes/handlers/course-option-handler.ts index 66b2c5c6f..0ecaa7515 100644 --- a/src/core/siteplugins/classes/course-option-handler.ts +++ b/src/core/siteplugins/classes/handlers/course-option-handler.ts @@ -13,10 +13,10 @@ // limitations under the License. import { Injector } from '@angular/core'; -import { CoreSitePluginsProvider } from '../providers/siteplugins'; +import { CoreSitePluginsProvider } from '../../providers/siteplugins'; import { CoreCourseOptionsHandler, CoreCourseOptionsHandlerData } from '@core/course/providers/options-delegate'; import { CoreSitePluginsBaseHandler } from './base-handler'; -import { CoreSitePluginsCourseOptionComponent } from '../components/course-option/course-option'; +import { CoreSitePluginsCourseOptionComponent } from '../../components/course-option/course-option'; /** * Handler to display a site plugin in course options. diff --git a/src/core/siteplugins/classes/main-menu-handler.ts b/src/core/siteplugins/classes/handlers/main-menu-handler.ts similarity index 100% rename from src/core/siteplugins/classes/main-menu-handler.ts rename to src/core/siteplugins/classes/handlers/main-menu-handler.ts diff --git a/src/core/siteplugins/classes/message-output-handler.ts b/src/core/siteplugins/classes/handlers/message-output-handler.ts similarity index 100% rename from src/core/siteplugins/classes/message-output-handler.ts rename to src/core/siteplugins/classes/handlers/message-output-handler.ts diff --git a/src/core/siteplugins/classes/module-handler.ts b/src/core/siteplugins/classes/handlers/module-handler.ts similarity index 97% rename from src/core/siteplugins/classes/module-handler.ts rename to src/core/siteplugins/classes/handlers/module-handler.ts index ee09ead5f..ffaf73af6 100644 --- a/src/core/siteplugins/classes/module-handler.ts +++ b/src/core/siteplugins/classes/handlers/module-handler.ts @@ -16,7 +16,7 @@ import { Injector } from '@angular/core'; import { NavController, NavOptions } from 'ionic-angular'; import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@core/course/providers/module-delegate'; import { CoreSitePluginsBaseHandler } from './base-handler'; -import { CoreSitePluginsModuleIndexComponent } from '../components/module-index/module-index'; +import { CoreSitePluginsModuleIndexComponent } from '../../components/module-index/module-index'; /** * Handler to support a module using a site plugin. diff --git a/src/core/siteplugins/classes/module-prefetch-handler.ts b/src/core/siteplugins/classes/handlers/module-prefetch-handler.ts similarity index 99% rename from src/core/siteplugins/classes/module-prefetch-handler.ts rename to src/core/siteplugins/classes/handlers/module-prefetch-handler.ts index a6d6d836f..df289cc97 100644 --- a/src/core/siteplugins/classes/module-prefetch-handler.ts +++ b/src/core/siteplugins/classes/handlers/module-prefetch-handler.ts @@ -13,7 +13,7 @@ // limitations under the License. import { Injector } from '@angular/core'; -import { CoreSitePluginsProvider } from '../providers/siteplugins'; +import { CoreSitePluginsProvider } from '../../providers/siteplugins'; import { CoreCourseModulePrefetchHandlerBase } from '@core/course/classes/module-prefetch-handler'; /** diff --git a/src/core/siteplugins/classes/question-behaviour-handler.ts b/src/core/siteplugins/classes/handlers/question-behaviour-handler.ts similarity index 94% rename from src/core/siteplugins/classes/question-behaviour-handler.ts rename to src/core/siteplugins/classes/handlers/question-behaviour-handler.ts index bf4adc7be..5352f6a67 100644 --- a/src/core/siteplugins/classes/question-behaviour-handler.ts +++ b/src/core/siteplugins/classes/handlers/question-behaviour-handler.ts @@ -14,7 +14,7 @@ import { Injector } from '@angular/core'; import { CoreQuestionBehaviourDefaultHandler } from '@core/question/providers/default-behaviour-handler'; -import { CoreSitePluginsQuestionBehaviourComponent } from '../components/question-behaviour/question-behaviour'; +import { CoreSitePluginsQuestionBehaviourComponent } from '../../components/question-behaviour/question-behaviour'; import { CoreQuestionProvider } from '@core/question/providers/question'; /** diff --git a/src/core/siteplugins/classes/question-handler.ts b/src/core/siteplugins/classes/handlers/question-handler.ts similarity index 94% rename from src/core/siteplugins/classes/question-handler.ts rename to src/core/siteplugins/classes/handlers/question-handler.ts index 4950468ca..7e9b128c7 100644 --- a/src/core/siteplugins/classes/question-handler.ts +++ b/src/core/siteplugins/classes/handlers/question-handler.ts @@ -14,7 +14,7 @@ import { Injector } from '@angular/core'; import { CoreQuestionDefaultHandler } from '@core/question/providers/default-question-handler'; -import { CoreSitePluginsQuestionComponent } from '../components/question/question'; +import { CoreSitePluginsQuestionComponent } from '../../components/question/question'; /** * Handler to display a question site plugin. diff --git a/src/core/siteplugins/classes/handlers/quiz-access-rule-handler.ts b/src/core/siteplugins/classes/handlers/quiz-access-rule-handler.ts new file mode 100644 index 000000000..e877c9a28 --- /dev/null +++ b/src/core/siteplugins/classes/handlers/quiz-access-rule-handler.ts @@ -0,0 +1,110 @@ +// (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 { Injector } from '@angular/core'; +import { CoreQuestionDefaultHandler } from '@core/question/providers/default-question-handler'; +import { CoreSitePluginsQuizAccessRuleComponent } from '../../components/quiz-access-rule/quiz-access-rule'; + +/** + * Handler to display a quiz access rule site plugin. + */ +export class CoreSitePluginsQuizAccessRuleHandler extends CoreQuestionDefaultHandler { + + constructor(public name: string, public ruleName: string, public hasTemplate: boolean) { + super(); + } + + /** + * Whether the rule requires a preflight check when prefetch/start/continue an attempt. + * + * @param {any} quiz The quiz the rule belongs to. + * @param {any} [attempt] The attempt started/continued. If not supplied, user is starting a new attempt. + * @param {boolean} [prefetch] Whether the user is prefetching the quiz. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {boolean|Promise} Whether the rule requires a preflight check. + */ + isPreflightCheckRequired(quiz: any, attempt?: any, prefetch?: boolean, siteId?: string): boolean | Promise { + return this.hasTemplate; + } + + /** + * Add preflight data that doesn't require user interaction. The data should be added to the preflightData param. + * + * @param {any} quiz The quiz the rule belongs to. + * @param {any} preflightData Object where to add the preflight data. + * @param {any} [attempt] The attempt started/continued. If not supplied, user is starting a new attempt. + * @param {boolean} [prefetch] Whether the user is prefetching the quiz. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {void|Promise} Promise resolved when done if async, void if it's synchronous. + */ + getFixedPreflightData(quiz: any, preflightData: any, attempt?: any, prefetch?: boolean, siteId?: string): void | Promise { + // Nothing to do. + } + + /** + * Return the Component to use to display the access rule preflight. + * Implement this if your access rule requires a preflight check with user interaction. + * It's recommended to return the class of the component, but you can also return an instance of the component. + * + * @param {Injector} injector Injector. + * @return {any|Promise} The component (or promise resolved with component) to use, undefined if not found. + */ + getPreflightComponent(injector: Injector): any | Promise { + if (this.hasTemplate) { + return CoreSitePluginsQuizAccessRuleComponent; + } + } + + /** + * Function called when the preflight check has passed. This is a chance to record that fact in some way. + * + * @param {any} quiz The quiz the rule belongs to. + * @param {any} attempt The attempt started/continued. + * @param {any} preflightData Preflight data gathered. + * @param {boolean} [prefetch] Whether the user is prefetching the quiz. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {void|Promise} Promise resolved when done if async, void if it's synchronous. + */ + notifyPreflightCheckPassed(quiz: any, attempt: any, preflightData: any, prefetch?: boolean, siteId?: string) + : void | Promise { + // Nothing to do. + } + + /** + * Function called when the preflight check fails. This is a chance to record that fact in some way. + * + * @param {any} quiz The quiz the rule belongs to. + * @param {any} attempt The attempt started/continued. + * @param {any} preflightData Preflight data gathered. + * @param {boolean} [prefetch] Whether the user is prefetching the quiz. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {void|Promise} Promise resolved when done if async, void if it's synchronous. + */ + notifyPreflightCheckFailed(quiz: any, attempt: any, preflightData: any, prefetch?: boolean, siteId?: string) + : void | Promise { + // Nothing to do. + } + + /** + * Whether or not the time left of an attempt should be displayed. + * + * @param {any} attempt The attempt. + * @param {number} endTime The attempt end time (in seconds). + * @param {number} timeNow The current time in seconds. + * @return {boolean} Whether it should be displayed. + */ + shouldShowTimeLeft(attempt: any, endTime: number, timeNow: number): boolean { + return false; + } +} diff --git a/src/core/siteplugins/classes/settings-handler.ts b/src/core/siteplugins/classes/handlers/settings-handler.ts similarity index 100% rename from src/core/siteplugins/classes/settings-handler.ts rename to src/core/siteplugins/classes/handlers/settings-handler.ts diff --git a/src/core/siteplugins/classes/user-handler.ts b/src/core/siteplugins/classes/handlers/user-handler.ts similarity index 98% rename from src/core/siteplugins/classes/user-handler.ts rename to src/core/siteplugins/classes/handlers/user-handler.ts index fb4851f61..044fd2317 100644 --- a/src/core/siteplugins/classes/user-handler.ts +++ b/src/core/siteplugins/classes/handlers/user-handler.ts @@ -14,7 +14,7 @@ import { NavController } from 'ionic-angular'; import { CoreUserDelegate, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@core/user/providers/user-delegate'; -import { CoreSitePluginsProvider } from '../providers/siteplugins'; +import { CoreSitePluginsProvider } from '../../providers/siteplugins'; import { CoreSitePluginsBaseHandler } from './base-handler'; /** diff --git a/src/core/siteplugins/classes/user-profile-field-handler.ts b/src/core/siteplugins/classes/handlers/user-profile-field-handler.ts similarity index 95% rename from src/core/siteplugins/classes/user-profile-field-handler.ts rename to src/core/siteplugins/classes/handlers/user-profile-field-handler.ts index 36ae73268..bd7c1250a 100644 --- a/src/core/siteplugins/classes/user-profile-field-handler.ts +++ b/src/core/siteplugins/classes/handlers/user-profile-field-handler.ts @@ -15,7 +15,7 @@ import { Injector } from '@angular/core'; import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@core/user/providers/user-profile-field-delegate'; import { CoreSitePluginsBaseHandler } from './base-handler'; -import { CoreSitePluginsUserProfileFieldComponent } from '../components/user-profile-field/user-profile-field'; +import { CoreSitePluginsUserProfileFieldComponent } from '../../components/user-profile-field/user-profile-field'; /** * Handler to display a site plugin in the user profile. diff --git a/src/core/siteplugins/components/components.module.ts b/src/core/siteplugins/components/components.module.ts index f6fe3250f..c83d80db8 100644 --- a/src/core/siteplugins/components/components.module.ts +++ b/src/core/siteplugins/components/components.module.ts @@ -25,6 +25,7 @@ import { CoreSitePluginsCourseFormatComponent } from './course-format/course-for import { CoreSitePluginsUserProfileFieldComponent } from './user-profile-field/user-profile-field'; import { CoreSitePluginsQuestionComponent } from './question/question'; import { CoreSitePluginsQuestionBehaviourComponent } from './question-behaviour/question-behaviour'; +import { CoreSitePluginsQuizAccessRuleComponent } from './quiz-access-rule/quiz-access-rule'; @NgModule({ declarations: [ @@ -34,7 +35,8 @@ import { CoreSitePluginsQuestionBehaviourComponent } from './question-behaviour/ CoreSitePluginsCourseFormatComponent, CoreSitePluginsUserProfileFieldComponent, CoreSitePluginsQuestionComponent, - CoreSitePluginsQuestionBehaviourComponent + CoreSitePluginsQuestionBehaviourComponent, + CoreSitePluginsQuizAccessRuleComponent ], imports: [ CommonModule, @@ -52,7 +54,8 @@ import { CoreSitePluginsQuestionBehaviourComponent } from './question-behaviour/ CoreSitePluginsCourseFormatComponent, CoreSitePluginsUserProfileFieldComponent, CoreSitePluginsQuestionComponent, - CoreSitePluginsQuestionBehaviourComponent + CoreSitePluginsQuestionBehaviourComponent, + CoreSitePluginsQuizAccessRuleComponent ], entryComponents: [ CoreSitePluginsModuleIndexComponent, @@ -60,7 +63,8 @@ import { CoreSitePluginsQuestionBehaviourComponent } from './question-behaviour/ CoreSitePluginsCourseFormatComponent, CoreSitePluginsUserProfileFieldComponent, CoreSitePluginsQuestionComponent, - CoreSitePluginsQuestionBehaviourComponent + CoreSitePluginsQuestionBehaviourComponent, + CoreSitePluginsQuizAccessRuleComponent ] }) export class CoreSitePluginsComponentsModule {} diff --git a/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.html b/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.html new file mode 100644 index 000000000..f58bcd913 --- /dev/null +++ b/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.html @@ -0,0 +1 @@ + diff --git a/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.ts b/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.ts new file mode 100644 index 000000000..cfd9d1394 --- /dev/null +++ b/src/core/siteplugins/components/quiz-access-rule/quiz-access-rule.ts @@ -0,0 +1,57 @@ +// (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, OnInit, Input } from '@angular/core'; +import { CoreSitePluginsProvider } from '../../providers/siteplugins'; +import { CoreSitePluginsCompileInitComponent } from '../../classes/compile-init-component'; +import { FormGroup } from '@angular/forms'; + +/** + * Component that displays a quiz access rule created using a site plugin. + */ +@Component({ + selector: 'core-site-plugins-quiz-access-rule', + templateUrl: 'quiz-access-rule.html', +}) +export class CoreSitePluginsQuizAccessRuleComponent extends CoreSitePluginsCompileInitComponent implements OnInit { + @Input() rule: string; // The name of the rule. + @Input() quiz: any; // The quiz the rule belongs to. + @Input() attempt: any; // The attempt being started/continued. + @Input() prefetch: boolean; // Whether the user is prefetching the quiz. + @Input() siteId: string; // Site ID. + @Input() form: FormGroup; // Form where to add the form control. + + constructor(sitePluginsProvider: CoreSitePluginsProvider) { + super(sitePluginsProvider); + } + + /** + * Component being initialized. + */ + ngOnInit(): void { + // Pass the input and output data to the component. + this.jsData = { + rule: this.rule, + quiz: this.quiz, + attempt: this.attempt, + prefetch: this.prefetch, + siteId: this.siteId, + form: this.form + }; + + if (this.rule) { + this.getHandlerData(this.rule); + } + } +} diff --git a/src/core/siteplugins/providers/helper.ts b/src/core/siteplugins/providers/helper.ts index 65116a0e9..5a05e7363 100644 --- a/src/core/siteplugins/providers/helper.ts +++ b/src/core/siteplugins/providers/helper.ts @@ -39,19 +39,21 @@ import { CoreSettingsDelegate } from '@core/settings/providers/delegate'; import { CoreQuestionDelegate } from '@core/question/providers/delegate'; import { CoreQuestionBehaviourDelegate } from '@core/question/providers/behaviour-delegate'; import { AddonMessageOutputDelegate } from '@addon/messageoutput/providers/delegate'; +import { AddonModQuizAccessRuleDelegate } from '@addon/mod/quiz/providers/access-rules-delegate'; // Handler classes. -import { CoreSitePluginsCourseFormatHandler } from '../classes/course-format-handler'; -import { CoreSitePluginsCourseOptionHandler } from '../classes/course-option-handler'; -import { CoreSitePluginsModuleHandler } from '../classes/module-handler'; -import { CoreSitePluginsModulePrefetchHandler } from '../classes/module-prefetch-handler'; -import { CoreSitePluginsMainMenuHandler } from '../classes/main-menu-handler'; -import { CoreSitePluginsUserProfileHandler } from '../classes/user-handler'; -import { CoreSitePluginsUserProfileFieldHandler } from '../classes/user-profile-field-handler'; -import { CoreSitePluginsSettingsHandler } from '../classes/settings-handler'; -import { CoreSitePluginsQuestionHandler } from '../classes/question-handler'; -import { CoreSitePluginsQuestionBehaviourHandler } from '../classes/question-behaviour-handler'; -import { CoreSitePluginsMessageOutputHandler } from '../classes/message-output-handler'; +import { CoreSitePluginsCourseFormatHandler } from '../classes/handlers/course-format-handler'; +import { CoreSitePluginsCourseOptionHandler } from '../classes/handlers/course-option-handler'; +import { CoreSitePluginsModuleHandler } from '../classes/handlers/module-handler'; +import { CoreSitePluginsModulePrefetchHandler } from '../classes/handlers/module-prefetch-handler'; +import { CoreSitePluginsMainMenuHandler } from '../classes/handlers/main-menu-handler'; +import { CoreSitePluginsUserProfileHandler } from '../classes/handlers/user-handler'; +import { CoreSitePluginsUserProfileFieldHandler } from '../classes/handlers/user-profile-field-handler'; +import { CoreSitePluginsSettingsHandler } from '../classes/handlers/settings-handler'; +import { CoreSitePluginsQuestionHandler } from '../classes/handlers/question-handler'; +import { CoreSitePluginsQuestionBehaviourHandler } from '../classes/handlers/question-behaviour-handler'; +import { CoreSitePluginsMessageOutputHandler } from '../classes/handlers/message-output-handler'; +import { CoreSitePluginsQuizAccessRuleHandler } from '../classes/handlers/quiz-access-rule-handler'; /** * Helper service to provide functionalities regarding site plugins. It basically has the features to load and register site @@ -76,7 +78,8 @@ export class CoreSitePluginsHelperProvider { private textUtils: CoreTextUtilsProvider, private filepoolProvider: CoreFilepoolProvider, private settingsDelegate: CoreSettingsDelegate, private questionDelegate: CoreQuestionDelegate, private questionBehaviourDelegate: CoreQuestionBehaviourDelegate, private questionProvider: CoreQuestionProvider, - private messageOutputDelegate: AddonMessageOutputDelegate) { + private messageOutputDelegate: AddonMessageOutputDelegate, + private accessRulesDelegate: AddonModQuizAccessRuleDelegate) { this.logger = logger.getInstance('CoreSitePluginsHelperProvider'); @@ -462,6 +465,10 @@ export class CoreSitePluginsHelperProvider { promise = Promise.resolve(this.registerMessageOutputHandler(plugin, handlerName, handlerSchema, result)); break; + case 'AddonModQuizAccessRuleDelegate': + promise = Promise.resolve(this.registerQuizAccessRuleHandler(plugin, handlerName, handlerSchema, result)); + break; + default: // Nothing to do. promise = Promise.resolve(); @@ -504,7 +511,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the course options delegate. + * Given a handler in a plugin, register it in the course options delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -533,7 +540,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the main menu delegate. + * Given a handler in a plugin, register it in the main menu delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -562,7 +569,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the message output delegate. + * Given a handler in a plugin, register it in the message output delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -592,7 +599,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the module delegate. + * Given a handler in a plugin, register it in the module delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -626,7 +633,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the question delegate. + * Given a handler in a plugin, register it in the question delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -675,7 +682,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the question behaviour delegate. + * Given a handler in a plugin, register it in the question behaviour delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -721,12 +728,61 @@ export class CoreSitePluginsHelperProvider { return plugin.component; }).catch((err) => { - this.logger.error('Error executing main method for question', handlerSchema.method, err); + this.logger.error('Error executing main method for question behaviour', handlerSchema.method, err); }); } /** - * Given a handler in an plugin, register it in the settings delegate. + * Given a handler in a plugin, register it in the quiz access rule delegate. + * + * @param {any} plugin Data of the plugin. + * @param {string} handlerName Name of the handler in the plugin. + * @param {any} handlerSchema Data about the handler. + * @param {any} initResult Result of the init WS call. + * @return {string|Promise} A string (or a promise resolved with a string) to identify the handler. + */ + protected registerQuizAccessRuleHandler(plugin: any, handlerName: string, handlerSchema: any, initResult: any) + : string | Promise { + if (!handlerSchema.method) { + // Required data not provided, stop. + this.logger.warn('Ignore site plugin because it doesn\'t provide method', plugin, handlerSchema); + + return; + } + + this.logger.debug('Register site plugin in quiz access rule delegate:', plugin, handlerSchema, initResult); + + // Execute the main method and its JS. The template returned will be used in the access rule component. + return this.executeMethodAndJS(plugin, handlerSchema.method).then((result) => { + // Create and register the handler. + const uniqueName = this.sitePluginsProvider.getHandlerUniqueName(plugin, handlerName), + ruleName = plugin.component, + ruleHandler = new CoreSitePluginsQuizAccessRuleHandler(uniqueName, ruleName, result.templates.length); + + // Store in handlerSchema some data required by the component. + handlerSchema.methodTemplates = result.templates; + handlerSchema.methodJSResult = result.jsResult; + + if (result && result.jsResult) { + // Override default handler functions with the result of the method JS. + for (const property in ruleHandler) { + if (property != 'constructor' && typeof ruleHandler[property] == 'function' && + typeof result.jsResult[property] == 'function') { + ruleHandler[property] = result.jsResult[property].bind(ruleHandler); + } + } + } + + this.accessRulesDelegate.registerHandler(ruleHandler); + + return ruleName; + }).catch((err) => { + this.logger.error('Error executing main method for quiz access rule', handlerSchema.method, err); + }); + } + + /** + * Given a handler in a plugin, register it in the settings delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -755,7 +811,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the user profile delegate. + * Given a handler in a plugin, register it in the user profile delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin. @@ -784,7 +840,7 @@ export class CoreSitePluginsHelperProvider { } /** - * Given a handler in an plugin, register it in the user profile field delegate. + * Given a handler in a plugin, register it in the user profile field delegate. * * @param {any} plugin Data of the plugin. * @param {string} handlerName Name of the handler in the plugin.