Merge pull request #3960 from NoelDeMartin/MOBILE-4529

MOBILE-4529: Decouple Survey
main
Dani Palou 2024-03-07 17:37:47 +01:00 committed by GitHub
commit 93a6680146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 335 additions and 158 deletions

View File

@ -23,7 +23,7 @@ import { CoreDomUtils } from '@services/utils/dom';
import { CoreTextUtils } from '@services/utils/text';
import { Translate } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { AddonModSurveyPrefetchHandler } from '../../services/handlers/prefetch';
import { getPrefetchHandlerInstance } from '../../services/handlers/prefetch';
import {
AddonModSurveyProvider,
AddonModSurveySurvey,
@ -215,7 +215,7 @@ export class AddonModSurveyIndexComponent extends CoreCourseModuleMainActivityCo
// The survey is downloaded, update the data.
try {
const prefetched = await AddonModSurveySync.prefetchAfterUpdate(
AddonModSurveyPrefetchHandler.instance,
getPrefetchHandlerInstance(),
this.module,
this.courseId,
);

View File

@ -0,0 +1,26 @@
// (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.
export const ADDON_MOD_SURVEY_COMPONENT = 'mmaModSurvey';
// Routing.
export const ADDON_MOD_SURVEY_PAGE_NAME = 'mod_survey';
// Handlers.
export const ADDON_MOD_SURVEY_PREFETCH_NAME = 'AddonModSurvey';
export const ADDON_MOD_SURVEY_PREFETCH_MODNAME = 'survey';
export const ADDON_MOD_SURVEY_PREFETCH_COMPONENT = ADDON_MOD_SURVEY_COMPONENT;
export const ADDON_MOD_SURVEY_PREFETCH_UPDATE_NAMES = /^configuration$|^.*files$|^answers$/;
export const ADDON_MOD_SURVEY_SYNC_CRON_NAME = 'AddonModSurveySyncCronHandler';

View File

@ -13,11 +13,11 @@
// limitations under the License.
import { CoreConstants, ModPurpose } from '@/core/constants';
import { ADDON_MOD_SURVEY_PAGE_NAME } from '@addons/mod/survey/constants';
import { Injectable, Type } from '@angular/core';
import { CoreModuleHandlerBase } from '@features/course/classes/module-base-handler';
import { CoreCourseModuleHandler } from '@features/course/services/module-delegate';
import { makeSingleton } from '@singletons';
import { AddonModSurveyIndexComponent } from '../../components/index';
/**
* Handler to support survey modules.
@ -25,11 +25,9 @@ import { AddonModSurveyIndexComponent } from '../../components/index';
@Injectable( { providedIn: 'root' })
export class AddonModSurveyModuleHandlerService extends CoreModuleHandlerBase implements CoreCourseModuleHandler {
static readonly PAGE_NAME = 'mod_survey';
name = 'AddonModSurvey';
modName = 'survey';
protected pageName = AddonModSurveyModuleHandlerService.PAGE_NAME;
protected pageName = ADDON_MOD_SURVEY_PAGE_NAME;
supportedFeatures = {
[CoreConstants.FEATURE_GROUPS]: true,
@ -48,6 +46,8 @@ export class AddonModSurveyModuleHandlerService extends CoreModuleHandlerBase im
* @inheritdoc
*/
async getMainComponent(): Promise<Type<unknown>> {
const { AddonModSurveyIndexComponent } = await import('@addons/mod/survey/components/index');
return AddonModSurveyIndexComponent;
}

View File

@ -0,0 +1,109 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreCourseAnyModuleData } from '@features/course/services/course';
import { CoreFilepool } from '@services/filepool';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModSurvey, AddonModSurveyProvider } from '../survey';
import { AddonModSurveySync, AddonModSurveySyncResult } from '../survey-sync';
import { AddonModSurveyPrefetchHandlerService } from '@addons/mod/survey/services/handlers/prefetch';
/**
* Handler to prefetch surveys.
*/
@Injectable( { providedIn: 'root' })
export class AddonModSurveyPrefetchHandlerLazyService extends AddonModSurveyPrefetchHandlerService {
/**
* @inheritdoc
*/
async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreWSFile[]> {
const survey = await CoreUtils.ignoreErrors(AddonModSurvey.getSurvey(courseId, module.id));
return this.getIntroFilesFromInstance(module, survey);
}
/**
* @inheritdoc
*/
async invalidateContent(moduleId: number, courseId: number): Promise<void> {
return AddonModSurvey.invalidateContent(moduleId, courseId);
}
/**
* @inheritdoc
*/
async invalidateModule(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
await AddonModSurvey.invalidateSurveyData(courseId);
}
/**
* @inheritdoc
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* @inheritdoc
*/
prefetch(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
return this.prefetchPackage(module, courseId, (siteId) => this.prefetchSurvey(module, courseId, siteId));
}
/**
* Prefetch a survey.
*
* @param module Module.
* @param courseId Course ID the module belongs to.
* @param siteId SiteId or current site.
* @returns Promise resolved when done.
*/
protected async prefetchSurvey(module: CoreCourseAnyModuleData, courseId: number, siteId: string): Promise<void> {
const survey = await AddonModSurvey.getSurvey(courseId, module.id, {
readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK,
siteId,
});
const promises: Promise<unknown>[] = [];
const files = this.getIntroFilesFromInstance(module, survey);
// Prefetch files.
promises.push(CoreFilepool.addFilesToQueue(siteId, files, AddonModSurveyProvider.COMPONENT, module.id));
// If survey isn't answered, prefetch the questions.
if (!survey.surveydone) {
promises.push(AddonModSurvey.getQuestions(survey.id, {
cmId: module.id,
readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK,
siteId,
}));
}
await Promise.all(promises);
}
/**
* @inheritdoc
*/
sync(module: CoreCourseAnyModuleData, courseId: number, siteId?: string): Promise<AddonModSurveySyncResult> {
return AddonModSurveySync.syncSurvey(module.instance, undefined, siteId);
}
}
export const AddonModSurveyPrefetchHandler = makeSingleton(AddonModSurveyPrefetchHandlerLazyService);

View File

@ -12,103 +12,54 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { AsyncInstance, asyncInstance } from '@/core/utils/async-instance';
import {
ADDON_MOD_SURVEY_PREFETCH_COMPONENT,
ADDON_MOD_SURVEY_PREFETCH_MODNAME,
ADDON_MOD_SURVEY_PREFETCH_NAME,
ADDON_MOD_SURVEY_PREFETCH_UPDATE_NAMES,
} from '@addons/mod/survey/constants';
import { CoreCourseActivityPrefetchHandlerBase } from '@features/course/classes/activity-prefetch-handler';
import { CoreCourseAnyModuleData } from '@features/course/services/course';
import { CoreFilepool } from '@services/filepool';
import { CoreSitesReadingStrategy } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons';
import { AddonModSurvey, AddonModSurveyProvider } from '../survey';
import { AddonModSurveySync, AddonModSurveySyncResult } from '../survey-sync';
import { CoreCourseModulePrefetchHandler } from '@features/course/services/module-prefetch-delegate';
import type { AddonModSurveyPrefetchHandlerLazyService } from './prefetch-lazy';
let prefetchHandlerInstance: AsyncInstance<
AddonModSurveyPrefetchHandlerLazyService,
AddonModSurveyPrefetchHandlerService
> | null = null;
/**
* Handler to prefetch surveys.
*/
@Injectable( { providedIn: 'root' })
export class AddonModSurveyPrefetchHandlerService extends CoreCourseActivityPrefetchHandlerBase {
name = 'AddonModSurvey';
modName = 'survey';
component = AddonModSurveyProvider.COMPONENT;
updatesNames = /^configuration$|^.*files$|^answers$/;
name = ADDON_MOD_SURVEY_PREFETCH_NAME;
modName = ADDON_MOD_SURVEY_PREFETCH_MODNAME;
component = ADDON_MOD_SURVEY_PREFETCH_COMPONENT;
updatesNames = ADDON_MOD_SURVEY_PREFETCH_UPDATE_NAMES;
/**
* @inheritdoc
*/
async getIntroFiles(module: CoreCourseAnyModuleData, courseId: number): Promise<CoreWSFile[]> {
const survey = await CoreUtils.ignoreErrors(AddonModSurvey.getSurvey(courseId, module.id));
return this.getIntroFilesFromInstance(module, survey);
}
/**
* @inheritdoc
*/
async invalidateContent(moduleId: number, courseId: number): Promise<void> {
return AddonModSurvey.invalidateContent(moduleId, courseId);
}
/**
* @inheritdoc
*/
async invalidateModule(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
await AddonModSurvey.invalidateSurveyData(courseId);
}
/**
* @inheritdoc
*/
async isEnabled(): Promise<boolean> {
return true;
}
/**
* @inheritdoc
*/
prefetch(module: CoreCourseAnyModuleData, courseId: number): Promise<void> {
return this.prefetchPackage(module, courseId, (siteId) => this.prefetchSurvey(module, courseId, siteId));
}
/**
* Prefetch a survey.
* Get prefetch handler instance.
*
* @param module Module.
* @param courseId Course ID the module belongs to.
* @param siteId SiteId or current site.
* @returns Promise resolved when done.
* @returns Prefetch handler.
*/
protected async prefetchSurvey(module: CoreCourseAnyModuleData, courseId: number, siteId: string): Promise<void> {
const survey = await AddonModSurvey.getSurvey(courseId, module.id, {
readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK,
siteId,
export function getPrefetchHandlerInstance(): CoreCourseModulePrefetchHandler {
if (!prefetchHandlerInstance) {
prefetchHandlerInstance = asyncInstance(async () => {
const { AddonModSurveyPrefetchHandler } = await import('./prefetch-lazy');
return AddonModSurveyPrefetchHandler.instance;
});
const promises: Promise<unknown>[] = [];
const files = this.getIntroFilesFromInstance(module, survey);
// Prefetch files.
promises.push(CoreFilepool.addFilesToQueue(siteId, files, AddonModSurveyProvider.COMPONENT, module.id));
// If survey isn't answered, prefetch the questions.
if (!survey.surveydone) {
promises.push(AddonModSurvey.getQuestions(survey.id, {
cmId: module.id,
readingStrategy: CoreSitesReadingStrategy.ONLY_NETWORK,
siteId,
}));
prefetchHandlerInstance.setEagerInstance(new AddonModSurveyPrefetchHandlerService());
prefetchHandlerInstance.setLazyMethods(['sync']);
prefetchHandlerInstance.setLazyOverrides([
'prefetch',
'isEnabled',
'invalidateModule',
'invalidateContent',
'getIntroFiles',
]);
}
await Promise.all(promises);
return prefetchHandlerInstance;
}
/**
* @inheritdoc
*/
sync(module: CoreCourseAnyModuleData, courseId: number, siteId?: string): Promise<AddonModSurveySyncResult> {
return AddonModSurveySync.syncSurvey(module.instance, undefined, siteId);
}
}
export const AddonModSurveyPrefetchHandler = makeSingleton(AddonModSurveyPrefetchHandlerService);

View File

@ -0,0 +1,44 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { CoreCronHandler } from '@services/cron';
import { makeSingleton } from '@singletons';
import { AddonModSurveySync } from '../survey-sync';
import { AddonModSurveySyncCronHandlerService } from '@addons/mod/survey/services/handlers/sync-cron';
/**
* Synchronization cron handler.
*/
@Injectable( { providedIn: 'root' })
export class AddonModSurveySyncCronHandlerLazyService
extends AddonModSurveySyncCronHandlerService
implements CoreCronHandler {
/**
* @inheritdoc
*/
async execute(siteId?: string, force?: boolean): Promise<void> {
await AddonModSurveySync.syncAllSurveys(siteId, force);
}
/**
* @inheritdoc
*/
getInterval(): number {
return AddonModSurveySync.syncInterval;
}
}
export const AddonModSurveySyncCronHandler = makeSingleton(AddonModSurveySyncCronHandlerLazyService);

View File

@ -12,32 +12,34 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Injectable } from '@angular/core';
import { asyncInstance } from '@/core/utils/async-instance';
import { ADDON_MOD_SURVEY_SYNC_CRON_NAME } from '@addons/mod/survey/constants';
import { CoreCronHandler } from '@services/cron';
import { makeSingleton } from '@singletons';
import { AddonModSurveySync } from '../survey-sync';
import type { AddonModSurveySyncCronHandlerLazyService } from './sync-cron-lazy';
/**
* Synchronization cron handler.
*/
@Injectable( { providedIn: 'root' })
export class AddonModSurveySyncCronHandlerService implements CoreCronHandler {
export class AddonModSurveySyncCronHandlerService {
name = 'AddonModSurveySyncCronHandler';
name = ADDON_MOD_SURVEY_SYNC_CRON_NAME;
/**
* @inheritdoc
*/
async execute(siteId?: string, force?: boolean): Promise<void> {
await AddonModSurveySync.syncAllSurveys(siteId, force);
}
/**
* @inheritdoc
* Get cron handler instance.
*
* @returns Cron handler.
*/
getInterval(): number {
return AddonModSurveySync.syncInterval;
}
export function getCronHandlerInstance(): CoreCronHandler {
const lazyHandler = asyncInstance<
AddonModSurveySyncCronHandlerLazyService,
AddonModSurveySyncCronHandlerService
>(async () => {
const { AddonModSurveySyncCronHandler } = await import('./sync-cron-lazy');
return AddonModSurveySyncCronHandler.instance;
});
lazyHandler.setEagerInstance(new AddonModSurveySyncCronHandlerService());
lazyHandler.setLazyMethods(['execute', 'getInterval']);
return lazyHandler;
}
export const AddonModSurveySyncCronHandler = makeSingleton(AddonModSurveySyncCronHandlerService);

View File

@ -23,7 +23,7 @@ import { CoreSites } from '@services/sites';
import { CoreUtils } from '@services/utils/utils';
import { makeSingleton } from '@singletons';
import { CoreEvents } from '@singletons/events';
import { AddonModSurveyPrefetchHandler } from './handlers/prefetch';
import { getPrefetchHandlerInstance } from './handlers/prefetch';
import { AddonModSurvey, AddonModSurveyProvider } from './survey';
import { AddonModSurveyAnswersDBRecordFormatted, AddonModSurveyOffline } from './survey-offline';
@ -206,7 +206,7 @@ export class AddonModSurveySyncProvider extends CoreCourseActivitySyncBaseProvid
const module = await CoreCourse.getModuleBasicInfoByInstance(surveyId, 'survey', { siteId });
CoreUtils.ignoreErrors(
this.prefetchAfterUpdate(AddonModSurveyPrefetchHandler.instance, module, result.courseId, undefined, siteId),
this.prefetchAfterUpdate(getPrefetchHandlerInstance(), module, result.courseId, undefined, siteId),
);
}
}

View File

@ -25,6 +25,7 @@ import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWar
import { makeSingleton, Translate } from '@singletons';
import { AddonModSurveyOffline } from './survey-offline';
import { CoreSiteWSPreSets } from '@classes/sites/authenticated-site';
import { ADDON_MOD_SURVEY_COMPONENT } from '@addons/mod/survey/constants';
const ROOT_CACHE_KEY = 'mmaModSurvey:';
@ -34,7 +35,7 @@ const ROOT_CACHE_KEY = 'mmaModSurvey:';
@Injectable( { providedIn: 'root' })
export class AddonModSurveyProvider {
static readonly COMPONENT = 'mmaModSurvey';
static readonly COMPONENT = ADDON_MOD_SURVEY_COMPONENT;
/**
* Get a survey's questions.

View File

@ -20,13 +20,13 @@ import { CoreCourseModulePrefetchDelegate } from '@features/course/services/modu
import { CoreMainMenuTabRoutingModule } from '@features/mainmenu/mainmenu-tab-routing.module';
import { CoreCronDelegate } from '@services/cron';
import { CORE_SITE_SCHEMAS } from '@services/sites';
import { AddonModSurveyComponentsModule } from './components/components.module';
import { ADDON_MOD_SURVEY_OFFLINE_SITE_SCHEMA } from './services/database/survey';
import { AddonModSurveyIndexLinkHandler } from './services/handlers/index-link';
import { AddonModSurveyListLinkHandler } from './services/handlers/list-link';
import { AddonModSurveyModuleHandler, AddonModSurveyModuleHandlerService } from './services/handlers/module';
import { AddonModSurveyPrefetchHandler } from './services/handlers/prefetch';
import { AddonModSurveySyncCronHandler } from './services/handlers/sync-cron';
import { AddonModSurveyModuleHandler } from './services/handlers/module';
import { getPrefetchHandlerInstance } from './services/handlers/prefetch';
import { getCronHandlerInstance } from './services/handlers/sync-cron';
import { ADDON_MOD_SURVEY_PAGE_NAME } from '@addons/mod/survey/constants';
/**
* Get mod Survey services.
@ -47,9 +47,20 @@ export async function getModSurveyServices(): Promise<Type<unknown>[]> {
];
}
/**
* Get survey component modules.
*
* @returns Survey component modules.
*/
export async function getModSurveyComponentModules(): Promise<unknown[]> {
const { AddonModSurveyComponentsModule } = await import('@addons/mod/survey/components/components.module');
return [AddonModSurveyComponentsModule];
}
const routes: Routes = [
{
path: AddonModSurveyModuleHandlerService.PAGE_NAME,
path: ADDON_MOD_SURVEY_PAGE_NAME,
loadChildren: () => import('./survey-lazy.module').then(m => m.AddonModSurveyLazyModule),
},
];
@ -57,7 +68,6 @@ const routes: Routes = [
@NgModule({
imports: [
CoreMainMenuTabRoutingModule.forChild(routes),
AddonModSurveyComponentsModule,
],
providers: [
{
@ -69,9 +79,10 @@ const routes: Routes = [
provide: APP_INITIALIZER,
multi: true,
useValue: () => {
CoreCourseModulePrefetchDelegate.registerHandler(getPrefetchHandlerInstance());
CoreCronDelegate.register(getCronHandlerInstance());
CoreCourseModuleDelegate.registerHandler(AddonModSurveyModuleHandler.instance);
CoreCourseModulePrefetchDelegate.registerHandler(AddonModSurveyPrefetchHandler.instance);
CoreCronDelegate.register(AddonModSurveySyncCronHandler.instance);
CoreContentLinksDelegate.registerHandler(AddonModSurveyIndexLinkHandler.instance);
CoreContentLinksDelegate.registerHandler(AddonModSurveyListLinkHandler.instance);
},

View File

@ -51,7 +51,7 @@ export function getAssessmentStrategyHandlerInstance(): AddonWorkshopAssessmentS
});
lazyHandler.setEagerInstance(new AddonModWorkshopAssessmentStrategyAccumulativeHandlerService());
lazyHandler.setLazyInstanceMethods([
lazyHandler.setLazyMethods([
'getComponent',
'getOriginalValues',
'hasDataChanged',

View File

@ -51,7 +51,7 @@ export function getAssessmentStrategyHandlerInstance(): AddonWorkshopAssessmentS
});
lazyHandler.setEagerInstance(new AddonModWorkshopAssessmentStrategyCommentsHandlerService());
lazyHandler.setLazyInstanceMethods([
lazyHandler.setLazyMethods([
'getComponent',
'getOriginalValues',
'hasDataChanged',

View File

@ -51,7 +51,7 @@ export function getAssessmentStrategyHandlerInstance(): AddonWorkshopAssessmentS
});
lazyHandler.setEagerInstance(new AddonModWorkshopAssessmentStrategyNumErrorsHandlerService());
lazyHandler.setLazyInstanceMethods([
lazyHandler.setLazyMethods([
'getComponent',
'getOriginalValues',
'hasDataChanged',

View File

@ -51,7 +51,7 @@ export function getAssessmentStrategyHandlerInstance(): AddonWorkshopAssessmentS
});
lazyHandler.setEagerInstance(new AddonModWorkshopAssessmentStrategyRubricHandlerService());
lazyHandler.setLazyInstanceMethods([
lazyHandler.setLazyMethods([
'getComponent',
'getOriginalValues',
'hasDataChanged',

View File

@ -48,7 +48,13 @@ export function getPrefetchHandlerInstance(): CoreCourseModulePrefetchHandler {
});
lazyHandler.setEagerInstance(new AddonModWorkshopPrefetchHandlerService());
lazyHandler.setLazyInstanceMethods(['sync']);
lazyHandler.setLazyMethods(['sync']);
lazyHandler.setLazyOverrides([
'getFiles',
'invalidateContent',
'isDownloadable',
'prefetch',
]);
return lazyHandler;
}

View File

@ -39,7 +39,7 @@ export function getCronHandlerInstance(): CoreCronHandler {
});
lazyHandler.setEagerInstance(new AddonModWorkshopSyncCronHandlerService());
lazyHandler.setLazyInstanceMethods(['execute', 'getInterval']);
lazyHandler.setLazyMethods(['execute', 'getInterval']);
return lazyHandler;
}

View File

@ -145,7 +145,7 @@ import { getModPageServices } from '@addons/mod/page/page.module';
import { getModQuizServices } from '@addons/mod/quiz/quiz.module';
import { getModResourceServices } from '@addons/mod/resource/resource.module';
import { getModScormServices } from '@addons/mod/scorm/scorm.module';
import { getModSurveyServices } from '@addons/mod/survey/survey.module';
import { getModSurveyComponentModules, getModSurveyServices } from '@addons/mod/survey/survey.module';
import { getModUrlServices } from '@addons/mod/url/url.module';
import { getModWikiServices } from '@addons/mod/wiki/wiki.module';
import { getModWorkshopComponentModules, getModWorkshopServices } from '@addons/mod/workshop/workshop.module';
@ -184,6 +184,7 @@ export class CoreCompileProvider {
protected readonly LAZY_IMPORTS = [
getModWorkshopComponentModules,
getModSurveyComponentModules,
];
constructor(protected injector: Injector) {
@ -383,7 +384,6 @@ export class CoreCompileProvider {
getTagServices(),
getUsersServices(),
getXAPIServices(),
getBadgesServices(),
getCalendarServices(),
getCompetencyServices(),

View File

@ -14,8 +14,7 @@
import { CoreSyncBaseProvider } from '@classes/base-sync';
import { CoreCourse, CoreCourseAnyModuleData } from '../services/course';
import { CoreCourseModulePrefetchDelegate } from '../services/module-prefetch-delegate';
import { CoreCourseModulePrefetchHandlerBase } from './module-prefetch-handler';
import { CoreCourseModulePrefetchDelegate, CoreCourseModulePrefetchHandler } from '../services/module-prefetch-delegate';
/**
* Base class to create activity sync providers. It provides some common functions.
@ -35,7 +34,7 @@ export class CoreCourseActivitySyncBaseProvider<T = void> extends CoreSyncBasePr
* @returns Promise resolved with boolean: true if prefetched, false if no need to prefetch.
*/
async prefetchAfterUpdate(
prefetchHandler: CoreCourseModulePrefetchHandlerBase,
prefetchHandler: CoreCourseModulePrefetchHandler,
module: CoreCourseAnyModuleData,
courseId: number,
preventDownloadRegex?: RegExp,

View File

@ -28,15 +28,19 @@ function createAsyncInstanceWrapper<
lazyConstructor?: () => TLazyInstance | Promise<TLazyInstance>,
): AsyncInstanceWrapper<TLazyInstance, TEagerInstance> {
let promisedInstance: CorePromisedValue<TLazyInstance> | null = null;
let lazyInstanceMethods: Array<string | symbol>;
let lazyMethods: Array<string | number | symbol> | null = null;
let lazyOverrides: Array<keyof TEagerInstance> | null = null;
let eagerInstance: TEagerInstance;
return {
get instance() {
return promisedInstance?.value ?? undefined;
},
get lazyInstanceMethods() {
return lazyInstanceMethods;
get lazyMethods() {
return lazyMethods;
},
get lazyOverrides() {
return lazyOverrides;
},
get eagerInstance() {
return eagerInstance;
@ -68,8 +72,11 @@ function createAsyncInstanceWrapper<
promisedInstance.resolve(instance);
},
setLazyInstanceMethods(methods) {
lazyInstanceMethods = methods;
setLazyMethods(methods) {
lazyMethods = methods;
},
setLazyOverrides(overrides) {
lazyOverrides = overrides;
},
setEagerInstance(instance) {
eagerInstance = instance;
@ -116,14 +123,16 @@ export interface AsyncInstanceWrapper<
TEagerInstance extends AsyncObject = Partial<TLazyInstance>
> {
instance?: TLazyInstance;
lazyInstanceMethods?: Array<string | symbol>;
lazyMethods?: Array<string | number | symbol> | null;
lazyOverrides?: Array<keyof TEagerInstance> | null;
eagerInstance?: TEagerInstance;
getInstance(): Promise<TLazyInstance>;
getProperty<P extends keyof TLazyInstance>(property: P): Promise<TLazyInstance[P]>;
setInstance(instance: TLazyInstance): void;
setLazyInstanceMethods<const T extends Array<string | symbol>>(
setLazyMethods<const T extends Array<string | number | symbol>>(
methods: LazyMethodsGuard<T, TLazyInstance, TEagerInstance>,
): void;
setLazyOverrides(methods: Array<keyof TEagerInstance>): void;
setEagerInstance(eagerInstance: TEagerInstance): void;
setLazyConstructor(lazyConstructor: () => TLazyInstance | Promise<TLazyInstance>): void;
resetInstance(): void;
@ -156,7 +165,7 @@ export type AsyncInstance<TLazyInstance extends TEagerInstance, TEagerInstance e
/**
* Guard type to make sure that lazy methods match what the lazy class implements.
*/
export type LazyMethodsGuard<TMethods extends Array<string | symbol>, TLazyInstance, TEagerInstance> =
export type LazyMethodsGuard<TMethods extends Array<string | number | symbol>, TLazyInstance, TEagerInstance> =
TupleMatches<TMethods, Exclude<keyof TLazyInstance, keyof TEagerInstance>> extends true ? TMethods : never;
/**
@ -172,7 +181,9 @@ export function asyncInstance<TLazyInstance extends TEagerInstance, TEagerInstan
const wrapper = createAsyncInstanceWrapper<TLazyInstance, TEagerInstance>(lazyConstructor);
return new Proxy(wrapper, {
get: (target, property, receiver) => {
get: (target, p, receiver) => {
const property = p as keyof TEagerInstance;
if (property in target) {
return Reflect.get(target, property, receiver);
}
@ -185,11 +196,19 @@ export function asyncInstance<TLazyInstance extends TEagerInstance, TEagerInstan
: value;
}
if (wrapper.eagerInstance && property in wrapper.eagerInstance) {
if (
wrapper.eagerInstance &&
property in wrapper.eagerInstance &&
!wrapper.lazyOverrides?.includes(property)
) {
return Reflect.get(wrapper.eagerInstance, property, receiver);
}
if (wrapper.lazyInstanceMethods && !wrapper.lazyInstanceMethods.includes(property)) {
if (
wrapper.lazyMethods &&
!wrapper.lazyMethods.includes(property) &&
!wrapper.lazyOverrides?.includes(property)
) {
return undefined;
}

View File

@ -39,11 +39,20 @@ describe('AsyncInstance', () => {
expect(await asyncService.isEager()).toBe(false);
});
it('initialize instance for forced eager properties', async () => {
const asyncService = asyncInstance(() => new LazyService());
asyncService.setEagerInstance(new EagerService());
asyncService.setLazyOverrides(['isEager']);
expect(await asyncService.isEager()).toBe(false);
});
it('does not return undefined methods when they are declared', async () => {
const asyncService = asyncInstance<LazyService, EagerService>(() => new LazyService());
asyncService.setEagerInstance(new EagerService());
asyncService.setLazyInstanceMethods(['hello', 'goodbye']);
asyncService.setLazyMethods(['hello', 'goodbye']);
expect(asyncService.hello).not.toBeUndefined();
expect(asyncService.goodbye).not.toBeUndefined();