diff --git a/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts b/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts index dc01fdf70..373344396 100644 --- a/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts +++ b/src/addons/block/activitymodules/components/activitymodules/activitymodules.ts @@ -101,7 +101,7 @@ export class AddonBlockActivityModulesComponent extends CoreBlockBaseComponent i if (modName === 'resources') { icon = CoreCourse.getModuleIconSrc('page', modIcons['page']); } else { - icon = CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]); + icon = CoreCourseModuleDelegate.getModuleIconSrc(modName, modIcons[modName]) || ''; } this.entries.push({ diff --git a/src/addons/mod/quiz/services/access-rules-delegate.ts b/src/addons/mod/quiz/services/access-rules-delegate.ts index 0bb48b4e5..0ec872b03 100644 --- a/src/addons/mod/quiz/services/access-rules-delegate.ts +++ b/src/addons/mod/quiz/services/access-rules-delegate.ts @@ -70,7 +70,7 @@ export interface AddonModQuizAccessRuleHandler extends CoreDelegateHandler { * * @return The component (or promise resolved with component) to use, undefined if not found. */ - getPreflightComponent?(): Type | Promise>; + getPreflightComponent?(): undefined | Type | Promise>; /** * Function called when the preflight check has passed. This is a chance to record that fact in some way. diff --git a/src/core/features/course/services/module-delegate.ts b/src/core/features/course/services/module-delegate.ts index 638543dc2..5e2718822 100644 --- a/src/core/features/course/services/module-delegate.ts +++ b/src/core/features/course/services/module-delegate.ts @@ -82,7 +82,7 @@ export interface CoreCourseModuleHandler extends CoreDelegateHandler { * * @return The icon src. */ - getIconSrc?(): string; + getIconSrc?(): string | undefined; /** * Check if this type of module supports a certain feature. @@ -336,7 +336,7 @@ export class CoreCourseModuleDelegateService extends CoreDelegate(modname, 'getIconSrc') || CoreCourse.getModuleIconSrc(modname, modicon); } diff --git a/src/core/features/courses/services/courses.ts b/src/core/features/courses/services/courses.ts index f61ba2376..cacb90551 100644 --- a/src/core/features/courses/services/courses.ts +++ b/src/core/features/courses/services/courses.ts @@ -18,7 +18,7 @@ import { CoreSites, CoreSitesReadingStrategy } from '@services/sites'; import { CoreSite, CoreSiteWSPreSets } from '@classes/site'; import { makeSingleton } from '@singletons'; import { CoreStatusWithWarningsWSResponse, CoreWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning } from '@services/ws'; -import { CoreEvents } from '@singletons/events'; +import { CoreEvents, CoreEventSiteData } from '@singletons/events'; import { CoreWSError } from '@classes/errors/wserror'; const ROOT_CACHE_KEY = 'mmCourses:'; @@ -853,7 +853,7 @@ export class CoreCoursesProvider { if (added.length || removed.length) { // At least 1 course was added or removed, trigger the event. - CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_CHANGED, { + CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_CHANGED, { added: added, removed: removed, }, site.getId()); @@ -1169,7 +1169,7 @@ export const CoreCourses = makeSingleton(CoreCoursesProvider); /** * Data sent to the EVENT_MY_COURSES_UPDATED. */ -export type CoreCoursesMyCoursesUpdatedEventData = { +export type CoreCoursesMyCoursesUpdatedEventData = CoreEventSiteData & { action: string; // Action performed. courseId?: number; // Course ID affected (if any). course?: CoreCourseAnyCourseData; // Course affected (if any). @@ -1177,6 +1177,14 @@ export type CoreCoursesMyCoursesUpdatedEventData = { value?: boolean; // The new value for the state changed. }; +/** + * Data sent to the EVENT_MY_COURSES_CHANGED. + */ +export type CoreCoursesMyCoursesChangedEventData = CoreEventSiteData & { + added: number[]; + removed: number[]; +}; + /** * Params of core_enrol_get_users_courses WS. */ diff --git a/src/core/features/siteplugins/classes/compile-init-component.ts b/src/core/features/siteplugins/classes/compile-init-component.ts new file mode 100644 index 000000000..6fe45e777 --- /dev/null +++ b/src/core/features/siteplugins/classes/compile-init-component.ts @@ -0,0 +1,75 @@ +// (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 { CoreUtils } from '@services/utils/utils'; +import { CoreSitePlugins, CoreSitePluginsInitHandlerData } from '../services/siteplugins'; + +/** + * Base class for components that will display a component using core-compile-html and want to call a + * componentInit function returned by the handler JS. + */ +export class CoreSitePluginsCompileInitComponent { + + content = ''; // Content. + jsData: Record = {}; // Data to pass to the component. + protected handlerSchema?: CoreSitePluginsInitHandlerData; // The handler data. + + /** + * Function called when the component is created. + * + * @param instance The component instance. + */ + componentCreated(instance: unknown): void { + // Check if the JS defined an init function. + if (instance && this.handlerSchema?.methodJSResult?.componentInit) { + this.handlerSchema.methodJSResult.componentInit.apply(instance); + } + } + + /** + * Get the handler data. + * + * @param name The name of the handler. + */ + getHandlerData(name: string): void { + // Retrieve the handler data. + const handler = CoreSitePlugins.getSitePluginHandler(name); + + this.handlerSchema = handler?.handlerSchema; + + if (!this.handlerSchema) { + return; + } + + // Load first template. + if (this.handlerSchema.methodTemplates?.length) { + this.content = this.handlerSchema.methodTemplates[0].html; + this.jsData.CONTENT_TEMPLATES = CoreUtils.objectToKeyValueMap( + this.handlerSchema.methodTemplates, + 'id', + 'html', + ); + } + + // Pass data from the method result to the component. + if (this.handlerSchema.methodOtherdata) { + this.jsData.CONTENT_OTHERDATA = this.handlerSchema.methodOtherdata; + } + + if (this.handlerSchema.methodJSResult) { + this.jsData.CONTENT_JS_RESULT = this.handlerSchema.methodJSResult; + } + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/assign-feedback-handler.ts b/src/core/features/siteplugins/classes/handlers/assign-feedback-handler.ts new file mode 100644 index 000000000..f68a21f13 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/assign-feedback-handler.ts @@ -0,0 +1,55 @@ +// (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 { Type } from '@angular/core'; + +import { AddonModAssignDefaultFeedbackHandler } from '@addons/mod/assign/services/handlers/default-feedback'; +import { AddonModAssignPlugin } from '@addons/mod/assign/services/assign'; +import { CoreSitePluginsAssignFeedbackComponent } from '@features/siteplugins/components/assign-feedback/assign-feedback'; +import { Translate } from '@singletons'; + +/** + * Handler to display an assign feedback site plugin. + */ +export class CoreSitePluginsAssignFeedbackHandler extends AddonModAssignDefaultFeedbackHandler { + + constructor(public name: string, public type: string, protected prefix: string) { + super(); + } + + /** + * @inheritdoc + */ + getComponent(): Type | undefined { + return CoreSitePluginsAssignFeedbackComponent; + } + + /** + * @inheritdoc + */ + getPluginName(plugin: AddonModAssignPlugin): string { + // Check if there's a translated string for the plugin. + const translationId = this.prefix + 'pluginname'; + const translation = Translate.instant(translationId); + + if (translationId != translation) { + // Translation found, use it. + return translation; + } + + // Fallback to WS string. + return plugin.name; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/assign-submission-handler.ts b/src/core/features/siteplugins/classes/handlers/assign-submission-handler.ts new file mode 100644 index 000000000..e88ea28f8 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/assign-submission-handler.ts @@ -0,0 +1,55 @@ +// (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 { Type } from '@angular/core'; + +import { AddonModAssignPlugin } from '@addons/mod/assign/services/assign'; +import { AddonModAssignDefaultSubmissionHandler } from '@addons/mod/assign/services/handlers/default-submission'; +import { Translate } from '@singletons'; +import { CoreSitePluginsAssignSubmissionComponent } from '../../components/assign-submission/assign-submission'; + +/** + * Handler to display an assign submission site plugin. + */ +export class CoreSitePluginsAssignSubmissionHandler extends AddonModAssignDefaultSubmissionHandler { + + constructor(public name: string, public type: string, protected prefix: string) { + super(); + } + + /** + * @inheritdoc + */ + getComponent(): Type { + return CoreSitePluginsAssignSubmissionComponent; + } + + /** + * @inheritdoc + */ + getPluginName(plugin: AddonModAssignPlugin): string { + // Check if there's a translated string for the plugin. + const translationId = this.prefix + 'pluginname'; + const translation = Translate.instant(translationId); + + if (translationId != translation) { + // Translation found, use it. + return translation; + } + + // Fallback to WS string. + return plugin.name; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/base-handler.ts b/src/core/features/siteplugins/classes/handlers/base-handler.ts new file mode 100644 index 000000000..6319177f3 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/base-handler.ts @@ -0,0 +1,31 @@ +// (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 { CoreDelegateHandler } from '@classes/delegate'; + +/** + * Super class for handlers for site plugins. + */ +export class CoreSitePluginsBaseHandler implements CoreDelegateHandler { + + constructor(public name: string) { } + + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return true; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/block-handler.ts b/src/core/features/siteplugins/classes/handlers/block-handler.ts new file mode 100644 index 000000000..776a273c2 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/block-handler.ts @@ -0,0 +1,91 @@ +// (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 { Type } from '@angular/core'; +import { CoreError } from '@classes/errors/error'; +import { CoreBlockPreRenderedComponent } from '@features/block/components/pre-rendered-block/pre-rendered-block'; +import { CoreBlockDelegate, CoreBlockHandler, CoreBlockHandlerData } from '@features/block/services/block-delegate'; +import { CoreCourseBlock } from '@features/course/services/course'; +import { CoreSitePluginsBlockComponent } from '@features/siteplugins/components/block/block'; +import { CoreSitePluginsOnlyTitleBlockComponent } from '@features/siteplugins/components/only-title-block/only-title-block'; +import { CoreSitePluginsBlockHandlerData, CoreSitePluginsContent } from '@features/siteplugins/services/siteplugins'; +import { CoreLogger } from '@singletons/logger'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to support a block using a site plugin. + */ +export class CoreSitePluginsBlockHandler extends CoreSitePluginsBaseHandler implements CoreBlockHandler { + + protected logger: CoreLogger; + + constructor( + name: string, + public title: string, + public blockName: string, + protected handlerSchema: CoreSitePluginsBlockHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.logger = CoreLogger.getInstance('CoreSitePluginsBlockHandler'); + } + + /** + * @inheritdoc + */ + async getDisplayData( + block: CoreCourseBlock, + contextLevel: string, + instanceId: number, + ): Promise { + const className = this.handlerSchema.displaydata?.class || 'block_' + block.name; + let component: Type | undefined; + + if (this.handlerSchema.displaydata?.type == 'title') { + component = CoreSitePluginsOnlyTitleBlockComponent; + } else if (this.handlerSchema.displaydata?.type == 'prerendered') { + component = CoreBlockPreRenderedComponent; + } else if (this.handlerSchema.fallback && !this.handlerSchema.method) { + // Try to use the fallback block. + const originalName = block.name; + block.name = this.handlerSchema.fallback; + + try { + const displayData = await CoreBlockDelegate.getBlockDisplayData(block, contextLevel, instanceId); + + if (!displayData) { + throw new CoreError('Cannot get display data for fallback block.'); + } + + this.logger.debug(`Using fallback "${this.handlerSchema.fallback}" for block "${originalName}"`); + component = displayData.component; + } catch (error) { + this.logger.error(`Error using fallback "${this.handlerSchema.fallback}" for block "${originalName}", ` + + 'maybe it doesn\'t exist or isn\'t enabled.', error); + + throw error; + } + } else { + component = CoreSitePluginsBlockComponent; + } + + return { + title: this.title, + class: className, + component, + }; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/course-format-handler.ts b/src/core/features/siteplugins/classes/handlers/course-format-handler.ts new file mode 100644 index 000000000..1878f6186 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/course-format-handler.ts @@ -0,0 +1,61 @@ +// (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 { Type } from '@angular/core'; + +import { CoreCourseFormatHandler } from '@features/course/services/format-delegate'; +import { CoreSitePluginsCourseFormatHandlerData } from '@features/siteplugins/services/siteplugins'; +import { CoreSitePluginsBaseHandler } from './base-handler'; +import { CoreSitePluginsCourseFormatComponent } from '../../components/course-format/course-format'; + +/** + * Handler to support a course format using a site plugin. + */ +export class CoreSitePluginsCourseFormatHandler extends CoreSitePluginsBaseHandler implements CoreCourseFormatHandler { + + constructor(name: string, public format: string, protected handlerSchema: CoreSitePluginsCourseFormatHandlerData) { + super(name); + } + + /** + * @inheritdoc + */ + canViewAllSections(): boolean { + return this.handlerSchema.canviewallsections ?? true; + } + + /** + * @inheritdoc + */ + displayEnableDownload(): boolean { + return this.handlerSchema.displayenabledownload ?? true; + } + + /** + * @inheritdoc + */ + displaySectionSelector(): boolean { + return this.handlerSchema.displaysectionselector ?? true; + } + + /** + * @inheritdoc + */ + async getCourseFormatComponent(): Promise | undefined> { + if (this.handlerSchema.method) { + return CoreSitePluginsCourseFormatComponent; + } + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/course-option-handler.ts b/src/core/features/siteplugins/classes/handlers/course-option-handler.ts new file mode 100644 index 000000000..6e4cbf464 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/course-option-handler.ts @@ -0,0 +1,137 @@ +// (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 { + CoreCourseOptionsHandler, + CoreCourseOptionsHandlerData, + CoreCourseOptionsMenuHandlerData, +} from '@features/course/services/course-options-delegate'; +import { CoreCourseAnyCourseDataWithOptions } from '@features/courses/services/courses'; +import { CoreEnrolledCourseDataWithExtraInfoAndOptions } from '@features/courses/services/courses-helper'; +import { + CoreSitePlugins, + CoreSitePluginsContent, + CoreSitePluginsCourseOptionHandlerData, + CoreSitePluginsPlugin, +} from '@features/siteplugins/services/siteplugins'; +import { CoreUtils, PromiseDefer } from '@services/utils/utils'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in course options. + */ +export class CoreSitePluginsCourseOptionHandler extends CoreSitePluginsBaseHandler implements CoreCourseOptionsHandler { + + priority: number; + isMenuHandler: boolean; + + protected updatingDefer?: PromiseDefer; + + constructor( + name: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsCourseOptionHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.priority = handlerSchema.priority || 0; + this.isMenuHandler = !!handlerSchema.ismenuhandler; + } + + /** + * @inheritdoc + */ + async isEnabledForCourse(courseId: number): Promise { + // Wait for "init" result to be updated. + if (this.updatingDefer) { + await this.updatingDefer.promise; + } + + return CoreSitePlugins.isHandlerEnabledForCourse( + courseId, + this.handlerSchema.restricttoenrolledcourses, + this.initResult?.restrict, + ); + } + + /** + * @inheritdoc + */ + getDisplayData(): CoreCourseOptionsHandlerData { + return { + title: this.title, + class: this.handlerSchema.displaydata?.class, + page: '@todo CoreSitePluginsCourseOptionComponent', + pageParams: { + handlerUniqueName: this.name, + }, + }; + } + + /** + * @inheritdoc + */ + getMenuDisplayData(course: CoreCourseAnyCourseDataWithOptions): CoreCourseOptionsMenuHandlerData { + return { + title: this.title, + class: this.handlerSchema.displaydata?.class, + icon: this.handlerSchema.displaydata?.icon || '', + page: '@todo CoreSitePluginsPluginPage', + pageParams: { + title: this.title, + component: this.plugin.component, + method: this.handlerSchema.method, + args: { + courseid: course.id, + }, + initResult: this.initResult, + ptrEnabled: this.handlerSchema.ptrenabled, + }, + }; + } + + /** + * @inheritdoc + */ + prefetch(course: CoreEnrolledCourseDataWithExtraInfoAndOptions): Promise { + const args = { + courseid: course.id, + }; + const component = this.plugin.component; + + return CoreSitePlugins.prefetchFunctions(component, args, this.handlerSchema, course.id, undefined, true); + } + + /** + * Set init result. + * + * @param result Result to set. + */ + setInitResult(result: CoreSitePluginsContent | null): void { + this.initResult = result; + + this.updatingDefer?.resolve(); + delete this.updatingDefer; + } + + /** + * Mark init being updated. + */ + updatingInit(): void { + this.updatingDefer = CoreUtils.promiseDefer(); + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts b/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts new file mode 100644 index 000000000..becc84c29 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/main-menu-handler.ts @@ -0,0 +1,62 @@ +// (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 { CoreMainMenuHandler, CoreMainMenuHandlerData } from '@features/mainmenu/services/mainmenu-delegate'; +import { + CoreSitePluginsContent, + CoreSitePluginsMainMenuHandlerData, + CoreSitePluginsPlugin, +} from '@features/siteplugins/services/siteplugins'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in the main menu. + */ +export class CoreSitePluginsMainMenuHandler extends CoreSitePluginsBaseHandler implements CoreMainMenuHandler { + + priority: number; + + constructor( + name: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsMainMenuHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.priority = handlerSchema.priority || 0; + } + + /** + * @inheritdoc + */ + getDisplayData(): CoreMainMenuHandlerData { + return { + title: this.title, + icon: this.handlerSchema.displaydata?.icon || 'fas-question', + class: this.handlerSchema.displaydata?.class, + page: '@todo CoreSitePluginsPluginPage', + pageParams: { + title: this.title, + component: this.plugin.component, + method: this.handlerSchema.method, + initResult: this.initResult, + ptrEnabled: this.handlerSchema.ptrenabled, + }, + onlyInMore: true, + }; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/message-output-handler.ts b/src/core/features/siteplugins/classes/handlers/message-output-handler.ts new file mode 100644 index 000000000..194797fab --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/message-output-handler.ts @@ -0,0 +1,58 @@ +// (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 { AddonMessageOutputHandler, AddonMessageOutputHandlerData } from '@addons/messageoutput/services/messageoutput-delegate'; +import { + CoreSitePluginsContent, + CoreSitePluginsMessageOutputHandlerData, + CoreSitePluginsPlugin, +} from '@features/siteplugins/services/siteplugins'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a message output settings option. + */ +export class CoreSitePluginsMessageOutputHandler extends CoreSitePluginsBaseHandler implements AddonMessageOutputHandler { + + constructor( + name: string, + public processorName: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsMessageOutputHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + } + + /** + * @inheritdoc + */ + getDisplayData(): AddonMessageOutputHandlerData { + return { + priority: this.handlerSchema.priority || 0, + label: this.title, + icon: this.handlerSchema.displaydata?.icon || 'fas-question', + page: '@todo CoreSitePluginsPluginPage', + pageParams: { + title: this.title, + component: this.plugin.component, + method: this.handlerSchema.method, + initResult: this.initResult, + ptrEnabled: this.handlerSchema.ptrenabled, + }, + }; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/module-handler.ts b/src/core/features/siteplugins/classes/handlers/module-handler.ts new file mode 100644 index 000000000..37de850a2 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/module-handler.ts @@ -0,0 +1,166 @@ +// (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 { Type } from '@angular/core'; + +import { CoreCourseAnyModuleData, CoreCourseWSModule } from '@features/course/services/course'; +import { CoreCourseModule } from '@features/course/services/course-helper'; +import { CoreCourseModuleHandler, CoreCourseModuleHandlerData } from '@features/course/services/module-delegate'; +import { CoreSitePluginsModuleIndexComponent } from '@features/siteplugins/components/module-index/module-index'; +import { + CoreSitePlugins, + CoreSitePluginsContent, + CoreSitePluginsCourseModuleHandlerData, + CoreSitePluginsPlugin, +} from '@features/siteplugins/services/siteplugins'; +import { CoreNavigationOptions } from '@services/navigator'; +import { CoreLogger } from '@singletons/logger'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to support a module using a site plugin. + */ +export class CoreSitePluginsModuleHandler extends CoreSitePluginsBaseHandler implements CoreCourseModuleHandler { + + supportedFeatures?: Record; + supportsFeature?: (feature: string) => unknown; + + protected logger: CoreLogger; + + constructor( + name: string, + public modName: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsCourseModuleHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.logger = CoreLogger.getInstance('CoreSitePluginsModuleHandler'); + this.supportedFeatures = handlerSchema.supportedfeatures; + + if (initResult?.jsResult && initResult.jsResult.supportsFeature) { + // The init result defines a function to check if a feature is supported, use it. + this.supportsFeature = initResult.jsResult.supportsFeature.bind(initResult.jsResult); + } + } + + /** + * @inheritdoc + */ + getData( + module: CoreCourseAnyModuleData, + courseId: number, + sectionId?: number, + forCoursePage?: boolean, + ): CoreCourseModuleHandlerData { + const callMethod = forCoursePage && this.handlerSchema.coursepagemethod; + + if ('noviewlink' in module && module.noviewlink && !callMethod) { + // The module doesn't link to a new page (similar to label). Only display the description. + const title = module.description; + module.description = ''; + + return { + icon: this.getIconSrc(), + title: title || '', + a11yTitle: '', + class: this.handlerSchema.displaydata?.class, + }; + } + + const hasOffline = !!(this.handlerSchema.offlinefunctions && Object.keys(this.handlerSchema.offlinefunctions).length); + const showDowloadButton = this.handlerSchema.downloadbutton; + const handlerData: CoreCourseModuleHandlerData = { + title: module.name, + icon: this.getIconSrc(), + class: this.handlerSchema.displaydata?.class, + showDownloadButton: typeof showDowloadButton != 'undefined' ? showDowloadButton : hasOffline, + }; + + if (this.handlerSchema.method) { + // There is a method, add an action. + handlerData.action = (event: Event, module: CoreCourseModule, courseId: number, options?: CoreNavigationOptions) => { + event.preventDefault(); + event.stopPropagation(); + + // @todo navCtrl.push('CoreSitePluginsModuleIndexPage', { + // title: module.name, + // module: module, + // courseId: courseId + // }, options); + }; + } + + if (callMethod && module.visibleoncoursepage !== 0) { + // Call the method to get the course page template. + this.loadCoursePageTemplate(module, courseId, handlerData); + } + + return handlerData; + } + + /** + * Load and use template for course page. + * + * @param module Module. + * @param courseId Course ID. + * @param handlerData Handler data. + * @return Promise resolved when done. + */ + protected async loadCoursePageTemplate( + module: CoreCourseAnyModuleData, + courseId: number, + handlerData: CoreCourseModuleHandlerData, + ): Promise { + // Call the method to get the course page template. + handlerData.loading = true; + + const args = { + courseid: courseId, + cmid: module.id, + }; + + try { + const result = await CoreSitePlugins.getContent( + this.plugin.component, + this.handlerSchema.coursepagemethod!, + args, + ); + + // Use the html returned. + handlerData.title = result.templates[0]?.html ?? ''; + ( module).description = ''; + } catch (error) { + this.logger.error('Error calling course page method:', error); + } finally { + handlerData.loading = false; + } + } + + /** + * @inheritdoc + */ + getIconSrc(): string | undefined { + return this.handlerSchema.displaydata?.icon; + } + + /** + * @inheritdoc + */ + async getMainComponent(): Promise> { + return CoreSitePluginsModuleIndexComponent; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/module-prefetch-handler.ts b/src/core/features/siteplugins/classes/handlers/module-prefetch-handler.ts new file mode 100644 index 000000000..5353cb0b3 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/module-prefetch-handler.ts @@ -0,0 +1,236 @@ +// (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 { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler'; +import { CoreCourse, CoreCourseAnyModuleData } from '@features/course/services/course'; +import { CoreSitePlugins, CoreSitePluginsCourseModuleHandlerData } from '@features/siteplugins/services/siteplugins'; +import { CoreFilepool } from '@services/filepool'; +import { CoreFileSizeSum } from '@services/plugin-file-delegate'; +import { CoreSites } from '@services/sites'; +import { CoreUtils } from '@services/utils/utils'; + +/** + * Handler to prefetch a module site plugin. + */ +export class CoreSitePluginsModulePrefetchHandler extends CoreCourseActivityPrefetchHandlerBase { + + protected isResource: boolean; + + constructor( + component: string, + name: string, + modName: string, + protected handlerSchema: CoreSitePluginsCourseModuleHandlerData, + ) { + super(); + + this.component = component; + this.name = name; + this.modName = modName; + this.isResource = !!handlerSchema.isresource; + + if (handlerSchema.updatesnames) { + try { + this.updatesNames = new RegExp(handlerSchema.updatesnames); + } catch (ex) { + // Ignore errors. + } + } + } + + /** + * @inheritdoc + */ + download(module: CoreCourseAnyModuleData, courseId: number, dirPath?: string): Promise { + const siteId = CoreSites.getCurrentSiteId(); + + return this.prefetchPackage( + module, + courseId, + this.downloadPrefetchPlugin.bind(this, module, courseId, false, dirPath, siteId), + siteId, + ); + } + + /** + * Download or prefetch the plugin, downloading the files and calling the needed WS. + * + * @param module The module object returned by WS. + * @param courseId Course ID. + * @param prefetch True to prefetch, false to download right away. + * @param dirPath Path of the directory where to store all the content files. + * @param siteId Site ID. If not defined, current site. + * @return Promise resolved when done. + */ + protected async downloadPrefetchPlugin( + module: CoreCourseAnyModuleData, + courseId: number, + prefetch: boolean, + dirPath?: string, + siteId?: string, + ): Promise { + const site = await CoreSites.getSite(siteId); + + const args = { + courseid: courseId, + cmid: module.id, + userid: site.getUserId(), + }; + + await Promise.all([ + // Download the files (if any). + this.downloadOrPrefetchFiles(site.getId(), module, courseId, prefetch, dirPath), + + // Call all the offline functions. + CoreSitePlugins.prefetchFunctions( + this.component, + args, + this.handlerSchema, + courseId, + module, + prefetch, + dirPath, + site, + ), + ]); + } + + /** + * Download or prefetch the plugin files. + * + * @param siteId Site ID. + * @param module The module object returned by WS. + * @param courseId Course ID. + * @param prefetch True to prefetch, false to download right away. + * @param dirPath Path of the directory where to store all the content files. + * @return Promise resolved when done. + */ + protected async downloadOrPrefetchFiles( + siteId: string, + module: CoreCourseAnyModuleData, + courseId: number, + prefetch: boolean, + dirPath?: string, + ): Promise { + // Load module contents (ignore cache so we always have the latest data). + await this.loadContents(module, courseId, true); + + // Get the intro files. + const introFiles = await this.getIntroFiles(module, courseId); + + const contentFiles = this.getContentDownloadableFiles(module); + + if (dirPath) { + await Promise.all([ + // Download intro files in filepool root folder. + CoreFilepool.downloadOrPrefetchFiles(siteId, introFiles, prefetch, false, this.component, module.id), + + // Download content files inside dirPath. + CoreFilepool.downloadOrPrefetchFiles( + siteId, + contentFiles, + prefetch, + false, + this.component, + module.id, + dirPath, + ), + ]); + } else { + // No dirPath, download everything in filepool root folder. + await CoreFilepool.downloadOrPrefetchFiles( + siteId, + introFiles.concat(contentFiles), + prefetch, + false, + this.component, + module.id, + ); + } + } + + /** + * @inheritdoc + */ + async getDownloadSize(): Promise { + // In most cases, to calculate the size we'll have to do all the WS calls. Just return unknown size. + return { size: -1, total: false }; + } + + /** + * @inheritdoc + */ + async invalidateContent(moduleId: number, courseId: number): Promise { + const currentSite = CoreSites.getCurrentSite(); + if (!currentSite) { + return; + } + + const promises: Promise[] = []; + const siteId = currentSite.getId(); + const args = { + courseid: courseId, + cmid: moduleId, + userid: currentSite.getUserId(), + }; + + // Invalidate files and the module. + promises.push(CoreFilepool.invalidateFilesByComponent(siteId, this.component, moduleId)); + promises.push(CoreCourse.invalidateModule(moduleId, siteId)); + + // Also invalidate all the WS calls. + for (const method in this.handlerSchema.offlinefunctions) { + if (currentSite.wsAvailable(method)) { + // The method is a WS. + promises.push(currentSite.invalidateWsCacheForKey(CoreSitePlugins.getCallWSCacheKey(method, args))); + } else { + // It's a method to get content. + promises.push(CoreSitePlugins.invalidateContent(this.component, method, args, siteId)); + } + } + + return CoreUtils.allPromises(promises); + } + + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return true; + } + + /** + * @inheritdoc + */ + async loadContents(module: CoreCourseAnyModuleData, courseId: number, ignoreCache?: boolean): Promise { + if (this.isResource) { + return CoreCourse.loadModuleContents(module, courseId, undefined, false, ignoreCache); + } + } + + /** + * @inheritdoc + */ + prefetch(module: CoreCourseAnyModuleData, courseId?: number, single?: boolean, dirPath?: string): Promise { + const siteId = CoreSites.getCurrentSiteId(); + + return this.prefetchPackage( + module, + courseId, + this.downloadPrefetchPlugin.bind(this, module, courseId, true, dirPath, siteId), + siteId, + ); + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/question-behaviour-handler.ts b/src/core/features/siteplugins/classes/handlers/question-behaviour-handler.ts new file mode 100644 index 000000000..9e3a1a991 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/question-behaviour-handler.ts @@ -0,0 +1,38 @@ +// (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 { Type } from '@angular/core'; + +import { CoreQuestionBehaviourBaseHandler } from '@features/question/classes/base-behaviour-handler'; +import { CoreSitePluginsQuestionBehaviourComponent } from '@features/siteplugins/components/question-behaviour/question-behaviour'; + +/** + * Handler to display a question behaviour site plugin. + */ +export class CoreSitePluginsQuestionBehaviourHandler extends CoreQuestionBehaviourBaseHandler { + + constructor(public name: string, public type: string, public hasTemplate: boolean) { + super(); + } + + /** + * @inheritdoc + */ + handleQuestion(): undefined | Type[] { + if (this.hasTemplate) { + return [CoreSitePluginsQuestionBehaviourComponent]; + } + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/question-handler.ts b/src/core/features/siteplugins/classes/handlers/question-handler.ts new file mode 100644 index 000000000..79c8d9dc4 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/question-handler.ts @@ -0,0 +1,36 @@ +// (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 { Type } from '@angular/core'; + +import { CoreQuestionBaseHandler } from '@features/question/classes/base-question-handler'; +import { CoreSitePluginsQuestionComponent } from '@features/siteplugins/components/question/question'; + +/** + * Handler to display a question site plugin. + */ +export class CoreSitePluginsQuestionHandler extends CoreQuestionBaseHandler { + + constructor(public name: string, public type: string) { + super(); + } + + /** + * @inheritdoc + */ + getComponent(): Type { + return CoreSitePluginsQuestionComponent; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/quiz-access-rule-handler.ts b/src/core/features/siteplugins/classes/handlers/quiz-access-rule-handler.ts new file mode 100644 index 000000000..46af909b4 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/quiz-access-rule-handler.ts @@ -0,0 +1,78 @@ +// (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 { Type } from '@angular/core'; + +import { AddonModQuizAccessRuleHandler } from '@addons/mod/quiz/services/access-rules-delegate'; +import { CoreSitePluginsQuizAccessRuleComponent } from '../../components/quiz-access-rule/quiz-access-rule'; + +/** + * Handler to display a quiz access rule site plugin. + */ +export class CoreSitePluginsQuizAccessRuleHandler implements AddonModQuizAccessRuleHandler { + + constructor(public name: string, public ruleName: string, public hasTemplate: boolean) { } + + /** + * @inheritdoc + */ + async isEnabled(): Promise { + return true; + } + + /** + * @inheritdoc + */ + isPreflightCheckRequired(): boolean { + return this.hasTemplate; + } + + /** + * @inheritdoc + */ + getFixedPreflightData(): void { + // Nothing to do. + } + + /** + * @inheritdoc + */ + getPreflightComponent(): undefined | Type { + if (this.hasTemplate) { + return CoreSitePluginsQuizAccessRuleComponent; + } + } + + /** + * @inheritdoc + */ + notifyPreflightCheckPassed(): void { + // Nothing to do. + } + + /** + * @inheritdoc + */ + notifyPreflightCheckFailed(): void { + // Nothing to do. + } + + /** + * @inheritdoc + */ + shouldShowTimeLeft(): boolean { + return false; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/settings-handler.ts b/src/core/features/siteplugins/classes/handlers/settings-handler.ts new file mode 100644 index 000000000..f1b9844e1 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/settings-handler.ts @@ -0,0 +1,63 @@ +// (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 { CoreSettingsHandler, CoreSettingsHandlerData } from '@features/settings/services/settings-delegate'; +import { + CoreSitePluginsContent, + CoreSitePluginsPlugin, + CoreSitePluginsSettingsHandlerData, +} from '@features/siteplugins/services/siteplugins'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in the settings. + */ +export class CoreSitePluginsSettingsHandler extends CoreSitePluginsBaseHandler implements CoreSettingsHandler { + + priority: number; + + constructor( + name: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsSettingsHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.priority = handlerSchema.priority || 0; + } + + /** + * Returns the data needed to render the handler. + * + * @return Data. + */ + getDisplayData(): CoreSettingsHandlerData { + return { + title: this.title, + icon: this.handlerSchema.displaydata?.icon, + class: this.handlerSchema.displaydata?.class, + page: '@todo CoreSitePluginsPluginPage', + params: { + title: this.title, + component: this.plugin.component, + method: this.handlerSchema.method, + initResult: this.initResult, + ptrEnabled: this.handlerSchema.ptrenabled, + }, + }; + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/user-handler.ts b/src/core/features/siteplugins/classes/handlers/user-handler.ts new file mode 100644 index 000000000..b19e8193f --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/user-handler.ts @@ -0,0 +1,127 @@ +// (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 { + CoreSitePlugins, + CoreSitePluginsContent, + CoreSitePluginsPlugin, + CoreSitePluginsUserHandlerData, +} from '@features/siteplugins/services/siteplugins'; +import { CoreUserProfile } from '@features/user/services/user'; +import { CoreUserDelegateService, CoreUserProfileHandler, CoreUserProfileHandlerData } from '@features/user/services/user-delegate'; +import { CoreSites } from '@services/sites'; +import { CoreUtils, PromiseDefer } from '@services/utils/utils'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in the user profile. + */ +export class CoreSitePluginsUserProfileHandler extends CoreSitePluginsBaseHandler implements CoreUserProfileHandler { + + priority: number; + type: string; + + protected updatingDefer?: PromiseDefer; + + constructor( + name: string, + protected title: string, + protected plugin: CoreSitePluginsPlugin, + protected handlerSchema: CoreSitePluginsUserHandlerData, + protected initResult: CoreSitePluginsContent | null, + ) { + super(name); + + this.priority = handlerSchema.priority || 0; + + // Only support TYPE_COMMUNICATION and TYPE_NEW_PAGE. + this.type = handlerSchema.type != CoreUserDelegateService.TYPE_COMMUNICATION ? + CoreUserDelegateService.TYPE_NEW_PAGE : CoreUserDelegateService.TYPE_COMMUNICATION; + } + + /** + * @inheritdoc + */ + async isEnabledForUser( + user: CoreUserProfile, + courseId?: number, + ): Promise { + // First check if it's enabled for the user. + const enabledForUser = CoreSitePlugins.isHandlerEnabledForUser( + user.id, + this.handlerSchema.restricttocurrentuser, + this.initResult?.restrict, + ); + + if (!enabledForUser) { + return false; + } + + courseId = courseId || CoreSites.getCurrentSiteHomeId(); + + // Enabled for user, check if it's enabled for the course. + return CoreSitePlugins.isHandlerEnabledForCourse( + courseId, + this.handlerSchema.restricttoenrolledcourses, + this.initResult?.restrict, + ); + } + + /** + * @inheritdoc + */ + getDisplayData(): CoreUserProfileHandlerData { + return { + title: this.title, + icon: this.handlerSchema.displaydata?.icon, + class: this.handlerSchema.displaydata?.class, + action: (event: Event, user: CoreUserProfile, courseId?: number): void => { + event.preventDefault(); + event.stopPropagation(); + + // @todo navCtrl.push('CoreSitePluginsPluginPage', { + // title: this.title, + // component: this.plugin.component, + // method: this.handlerSchema.method, + // args: { + // courseid: courseId, + // userid: user.id + // }, + // initResult: this.initResult, + // ptrEnabled: this.handlerSchema.ptrenabled, + // }); + }, + }; + } + + /** + * Set init result. + * + * @param result Result to set. + */ + setInitResult(result: CoreSitePluginsContent | null): void { + this.initResult = result; + + this.updatingDefer?.resolve(); + delete this.updatingDefer; + } + + /** + * Mark init being updated. + */ + updatingInit(): void { + this.updatingDefer = CoreUtils.promiseDefer(); + } + +} diff --git a/src/core/features/siteplugins/classes/handlers/user-profile-field-handler.ts b/src/core/features/siteplugins/classes/handlers/user-profile-field-handler.ts new file mode 100644 index 000000000..d051e0f49 --- /dev/null +++ b/src/core/features/siteplugins/classes/handlers/user-profile-field-handler.ts @@ -0,0 +1,58 @@ +// (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 { Type } from '@angular/core'; + +import { AuthEmailSignupProfileField } from '@features/login/services/login-helper'; +import { CoreSitePluginsUserProfileFieldComponent } from '@features/siteplugins/components/user-profile-field/user-profile-field'; +import { CoreUserProfileField } from '@features/user/services/user'; +import { CoreUserProfileFieldHandler, CoreUserProfileFieldHandlerData } from '@features/user/services/user-profile-field-delegate'; +import { CoreSitePluginsBaseHandler } from './base-handler'; + +/** + * Handler to display a site plugin in the user profile. + */ +export class CoreSitePluginsUserProfileFieldHandler extends CoreSitePluginsBaseHandler implements CoreUserProfileFieldHandler { + + constructor(name: string, public type: string) { + super(name); + } + + /** + * @inheritdoc + */ + getComponent(): Type { + return CoreSitePluginsUserProfileFieldComponent; + } + + /** + * @inheritdoc + */ + async getData( + field: AuthEmailSignupProfileField | CoreUserProfileField, + signup: boolean, + registerAuth: string, + formValues: Record, + ): Promise { + // No getData function implemented, use a default behaviour. + const name = 'profile_field_' + field.shortname; + + return { + type: 'type' in field ? field.type : field.datatype!, + name: name, + value: formValues[name], + }; + } + +}