From c20df40bdc7942bd88e60e5f6e2b7c21e8be8592 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Wed, 23 Aug 2023 16:05:20 +0200 Subject: [PATCH] MOBILE-4323 enrol: Support enrolment action on siteplugins Co-authored: dpalou --- src/core/features/compile/services/compile.ts | 2 + src/core/features/enrol/enrol.module.ts | 4 + .../classes/handlers/enrol-handler.ts | 77 +++++++++++++++++++ .../services/siteplugins-helper.ts | 70 +++++++++++++++++ .../siteplugins/services/siteplugins.ts | 11 ++- 5 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/core/features/siteplugins/classes/handlers/enrol-handler.ts diff --git a/src/core/features/compile/services/compile.ts b/src/core/features/compile/services/compile.ts index 0ba9a739c..30eb5d31b 100644 --- a/src/core/features/compile/services/compile.ts +++ b/src/core/features/compile/services/compile.ts @@ -47,6 +47,7 @@ import { CORE_CONTENTLINKS_SERVICES } from '@features/contentlinks/contentlinks. import { CORE_COURSE_SERVICES } from '@features/course/course.module'; import { CORE_COURSES_SERVICES } from '@features/courses/courses.module'; import { CORE_EDITOR_SERVICES } from '@features/editor/editor.module'; +import { CORE_ENROL_SERVICES } from '@features/enrol/enrol.module'; import { CORE_NATIVE_SERVICES } from '@features/native/native.module'; import { CORE_FILEUPLOADER_SERVICES } from '@features/fileuploader/fileuploader.module'; import { CORE_FILTER_SERVICES } from '@features/filter/filter.module'; @@ -269,6 +270,7 @@ export class CoreCompileProvider { ...CORE_COURSE_SERVICES, ...CORE_COURSES_SERVICES, ...CORE_EDITOR_SERVICES, + ...CORE_ENROL_SERVICES, ...CORE_FILEUPLOADER_SERVICES, ...CORE_FILTER_SERVICES, ...CORE_GRADES_SERVICES, diff --git a/src/core/features/enrol/enrol.module.ts b/src/core/features/enrol/enrol.module.ts index c211f6849..d1f8472b6 100644 --- a/src/core/features/enrol/enrol.module.ts +++ b/src/core/features/enrol/enrol.module.ts @@ -15,8 +15,12 @@ import { NgModule, Type } from '@angular/core'; import { CoreEnrolDelegateService } from './services/enrol-delegate'; +import { CoreEnrolService } from './services/enrol'; +import { CoreEnrolHelperService } from './services/enrol-helper'; export const CORE_ENROL_SERVICES: Type[] = [ + CoreEnrolService, + CoreEnrolHelperService, CoreEnrolDelegateService, ]; diff --git a/src/core/features/siteplugins/classes/handlers/enrol-handler.ts b/src/core/features/siteplugins/classes/handlers/enrol-handler.ts new file mode 100644 index 000000000..f387804bb --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/enrol-handler.ts @@ -0,0 +1,77 @@ +// (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 { CoreLogger } from '@singletons/logger'; +import { CoreSitePluginsBaseHandler } from './base-handler'; +import { CoreEnrolAction, CoreEnrolHandler, CoreEnrolInfoIcon } from '@features/enrol/services/enrol-delegate'; +import { CoreSitePluginsContent, CoreSitePluginsEnrolHandlerData } from '@features/siteplugins/services/siteplugins'; + +/** + * Handler to support a enrol using a site plugin. + */ +export class CoreSitePluginsEnrolHandler extends CoreSitePluginsBaseHandler implements CoreEnrolHandler { + + protected logger: CoreLogger; + + constructor( + name: string, + public type: string, + public enrolmentAction: CoreEnrolAction, + protected handlerSchema: CoreSitePluginsEnrolHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.logger = CoreLogger.getInstance('CoreSitePluginsEnrolHandler'); + } + + /** + * @inheritdoc + */ + async getInfoIcons(): Promise { + return this.handlerSchema.infoIcons ?? []; + } + + /** + * @inheritdoc + */ + async invalidate(): Promise { + // To be overridden. + } + + /** + * @inheritdoc + */ + async enrol(): Promise { + // To be overridden. + return false; + } + + /** + * @inheritdoc + */ + async canAccess(): Promise { + // To be overridden. + return false; + } + + /** + * @inheritdoc + */ + async validateAccess(): Promise { + // To be overridden. + return false; + } + +} diff --git a/src/core/features/siteplugins/services/siteplugins-helper.ts b/src/core/features/siteplugins/services/siteplugins-helper.ts index 9b485bf3a..93e96edda 100644 --- a/src/core/features/siteplugins/services/siteplugins-helper.ts +++ b/src/core/features/siteplugins/services/siteplugins-helper.ts @@ -74,6 +74,7 @@ import { CoreSitePluginsHandlerCommonData, CoreSitePluginsInitHandlerData, CoreSitePluginsMainMenuHomeHandlerData, + CoreSitePluginsEnrolHandlerData, } from './siteplugins'; import { makeSingleton } from '@singletons'; import { CoreMainMenuHomeDelegate } from '@features/mainmenu/services/home-delegate'; @@ -86,6 +87,8 @@ import { CoreContentLinksModuleListHandler } from '@features/contentlinks/classe import { CoreObject } from '@singletons/object'; import { CoreUrlUtils } from '@services/utils/url'; import { CorePath } from '@singletons/path'; +import { CoreEnrolAction, CoreEnrolDelegate } from '@features/enrol/services/enrol-delegate'; +import { CoreSitePluginsEnrolHandler } from '../classes/handlers/enrol-handler'; const HANDLER_DISABLED = 'core_site_plugins_helper_handler_disabled'; @@ -561,6 +564,10 @@ export class CoreSitePluginsHelperProvider { uniqueName = this.registerMainMenuHomeHandler(plugin, handlerName, handlerSchema, initResult); break; + case 'CoreEnrolDelegate': + uniqueName = await this.registerEnrolHandler(plugin, handlerName, handlerSchema, initResult); + break; + default: // Nothing to do. } @@ -800,6 +807,69 @@ export class CoreSitePluginsHelperProvider { return uniqueName; } + /** + * Given a handler in a plugin, register it in the enrol delegate. + * + * @param plugin Data of the plugin. + * @param handlerName Name of the handler in the plugin. + * @param handlerSchema Data about the handler. + * @param initResult Result of init function. + * @returns A string to identify the handler. + */ + protected async registerEnrolHandler( + plugin: CoreSitePluginsPlugin, + handlerName: string, + handlerSchema: CoreSitePluginsEnrolHandlerData, + initResult: CoreSitePluginsContent | null, + ): Promise { + const uniqueName = CoreSitePlugins.getHandlerUniqueName(plugin, handlerName); + const type = (handlerSchema.moodlecomponent || plugin.component).replace('enrol_', ''); + const action = handlerSchema.enrolmentAction ?? CoreEnrolAction.BROWSER; + const handler = new CoreSitePluginsEnrolHandler(uniqueName, type, action, handlerSchema, initResult); + + if (!handlerSchema.method && (action === CoreEnrolAction.SELF || action === CoreEnrolAction.GUEST)) { + this.logger.error('"self" or "guest" enrol plugins must implement a method to override the required JS functions.'); + + return; + } + + if (handlerSchema.method) { + // Execute the main method and its JS to allow implementing the handler functions. + const result = await this.executeMethodAndJS(plugin, handlerSchema.method); + + if (action === CoreEnrolAction.SELF && !result.jsResult?.enrol) { + this.logger.error('"self" enrol plugins must implement an "enrol" function in the JS returned by the method.'); + + return; + } + + if (action === CoreEnrolAction.GUEST && (!result.jsResult?.canAccess || !result.jsResult?.validateAccess)) { + this.logger.error('"guest" enrol plugins must implement "canAccess" and "validateAccess" functions in the JS ' + + 'returned by the method.'); + + return; + } + + if (result.jsResult) { + // Override default handler functions with the result of the method JS. + const jsResult = > result.jsResult; + const handlerProperties = CoreObject.getAllPropertyNames(handler); + + for (const property of handlerProperties) { + if (property !== 'constructor' && typeof handler[property] === 'function' && + typeof jsResult[property] === 'function') { + // eslint-disable-next-line @typescript-eslint/ban-types + handler[property] = ( jsResult[property]).bind(handler); + } + } + } + } + + CoreEnrolDelegate.registerHandler(handler); + + return uniqueName; + } + /** * Given a handler in a plugin, register it in the main menu delegate. * diff --git a/src/core/features/siteplugins/services/siteplugins.ts b/src/core/features/siteplugins/services/siteplugins.ts index 856f8ccfe..76dc1569b 100644 --- a/src/core/features/siteplugins/services/siteplugins.ts +++ b/src/core/features/siteplugins/services/siteplugins.ts @@ -31,6 +31,7 @@ import { CoreLogger } from '@singletons/logger'; import { CoreSitePluginsModuleHandler } from '../classes/handlers/module-handler'; import { CorePromisedValue } from '@classes/promised-value'; import { CorePlatform } from '@services/platform'; +import { CoreEnrolAction, CoreEnrolInfoIcon } from '@features/enrol/services/enrol-delegate'; const ROOT_CACHE_KEY = 'CoreSitePlugins:'; @@ -825,7 +826,7 @@ export type CoreSitePluginsPlugin = CoreSitePluginsWSPlugin & { export type CoreSitePluginsHandlerData = CoreSitePluginsInitHandlerData | CoreSitePluginsCourseOptionHandlerData | CoreSitePluginsMainMenuHandlerData | CoreSitePluginsCourseModuleHandlerData | CoreSitePluginsCourseFormatHandlerData | CoreSitePluginsUserHandlerData | CoreSitePluginsSettingsHandlerData | CoreSitePluginsMessageOutputHandlerData | -CoreSitePluginsBlockHandlerData | CoreSitePluginsMainMenuHomeHandlerData; +CoreSitePluginsBlockHandlerData | CoreSitePluginsMainMenuHomeHandlerData | CoreSitePluginsEnrolHandlerData; /** * Plugin handler data common to all delegates. @@ -960,6 +961,14 @@ export type CoreSitePluginsBlockHandlerData = CoreSitePluginsHandlerCommonData & fallback?: string; }; +/** + * Enrol handler specific data. + */ +export type CoreSitePluginsEnrolHandlerData = CoreSitePluginsHandlerCommonData & { + enrolmentAction?: CoreEnrolAction; + infoIcons?: CoreEnrolInfoIcon[]; +}; + /** * Common handler data with some data from the init method. */