MOBILE-4526 filter: Use get_all_states WS if available
parent
41e4292c48
commit
4fad121172
|
@ -15,7 +15,7 @@
|
|||
import { Injectable, ViewContainerRef } from '@angular/core';
|
||||
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreFilter, CoreFilterFilter, CoreFilterFormatTextOptions } from './filter';
|
||||
import { CoreFilter, CoreFilterFilter, CoreFilterFormatTextOptions, CoreFilterStateValue } from './filter';
|
||||
import { CoreFilterDefaultHandler } from './handlers/default-filter';
|
||||
import { CoreDelegate, CoreDelegateHandler } from '@classes/delegate';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
|
@ -169,7 +169,7 @@ export class CoreFilterDelegateService extends CoreDelegate<CoreFilterHandler> {
|
|||
filter: handler.filterName,
|
||||
inheritedstate: 1,
|
||||
instanceid: instanceId,
|
||||
localstate: 1,
|
||||
localstate: CoreFilterStateValue.ON,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,10 @@ export class CoreFilterDelegateService extends CoreDelegate<CoreFilterHandler> {
|
|||
skipFilters?: string[],
|
||||
): boolean {
|
||||
|
||||
if (filter.localstate == -1 || (filter.localstate == 0 && filter.inheritedstate == -1)) {
|
||||
if (
|
||||
filter.localstate === CoreFilterStateValue.OFF ||
|
||||
(filter.localstate === CoreFilterStateValue.INHERIT && filter.inheritedstate === CoreFilterStateValue.OFF)
|
||||
) {
|
||||
// Filter is disabled, ignore it.
|
||||
return false;
|
||||
}
|
||||
|
@ -255,7 +258,7 @@ export class CoreFilterDelegateService extends CoreDelegate<CoreFilterHandler> {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (skipFilters && skipFilters.indexOf(filter.filter) != -1) {
|
||||
if (skipFilters && skipFilters.indexOf(filter.filter) !== -1) {
|
||||
// Skip this filter.
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ import {
|
|||
CoreFilterFormatTextOptions,
|
||||
CoreFilterClassifiedFilters,
|
||||
CoreFiltersGetAvailableInContextWSParamContext,
|
||||
CoreFilterStateValue,
|
||||
CoreFilterAllStates,
|
||||
} from './filter';
|
||||
import { CoreCourse } from '@features/course/services/course';
|
||||
import { CoreCourses } from '@features/courses/services/courses';
|
||||
|
@ -177,7 +179,7 @@ export class CoreFilterHelperProvider {
|
|||
siteId?: string,
|
||||
): Promise<CoreFilterFilter[]> {
|
||||
// Check the right context to use.
|
||||
const newContext = CoreFilter.convertContext(contextLevel, instanceId, { courseId: options.courseId });
|
||||
const newContext = CoreFilter.getEffectiveContext(contextLevel, instanceId, { courseId: options.courseId });
|
||||
contextLevel = newContext.contextLevel;
|
||||
instanceId = newContext.instanceId;
|
||||
|
||||
|
@ -198,6 +200,11 @@ export class CoreFilterHelperProvider {
|
|||
return await CoreFilterDelegate.getEnabledFilters(contextLevel, instanceId);
|
||||
}
|
||||
|
||||
const filters = await this.getFiltersInContextUsingAllStates(contextLevel, instanceId, options, site);
|
||||
if (filters) {
|
||||
return filters;
|
||||
}
|
||||
|
||||
const courseId = options.courseId;
|
||||
let hasFilters = true;
|
||||
|
||||
|
@ -238,6 +245,95 @@ export class CoreFilterHelperProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filters in context using the all states data.
|
||||
*
|
||||
* @param contextLevel The context level.
|
||||
* @param instanceId Instance ID related to the context.
|
||||
* @param options Options.
|
||||
* @param site Site.
|
||||
* @returns Filters, undefined if all states cannot be used.
|
||||
*/
|
||||
protected async getFiltersInContextUsingAllStates(
|
||||
contextLevel: ContextLevel,
|
||||
instanceId: number,
|
||||
options: CoreFilterFormatTextOptions = {},
|
||||
site?: CoreSite,
|
||||
): Promise<CoreFilterFilter[] | undefined> {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
if (!CoreFilter.canGetAllStatesInSite(site)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const allStates = await CoreFilter.getAllStates({ siteId: site?.getId() });
|
||||
if (
|
||||
contextLevel !== ContextLevel.SYSTEM &&
|
||||
contextLevel !== ContextLevel.COURSECAT &&
|
||||
this.hasCategoryOverride(allStates)
|
||||
) {
|
||||
// A category has an override, we cannot calculate the right filters for child contexts.
|
||||
return;
|
||||
}
|
||||
|
||||
const contexts = CoreFilter.getContextsTreeList(contextLevel, instanceId, { courseId: options.courseId });
|
||||
const contextId = Object.values(allStates[contextLevel]?.[instanceId] ?? {})[0]?.contextid;
|
||||
|
||||
const filters: Record<string, CoreFilterFilter> = {};
|
||||
contexts.reverse().forEach((context) => {
|
||||
const isParentContext = context.contextLevel !== contextLevel;
|
||||
const filtersInContext = allStates[context.contextLevel]?.[context.instanceId];
|
||||
if (!filtersInContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const name in filtersInContext) {
|
||||
const filterInContext = filtersInContext[name];
|
||||
if (filterInContext.localstate === CoreFilterStateValue.DISABLED) {
|
||||
// Ignore disabled filters to make it consistent with available in context.
|
||||
continue;
|
||||
}
|
||||
|
||||
filters[name] = {
|
||||
contextlevel: contextLevel,
|
||||
instanceid: instanceId,
|
||||
contextid: contextId,
|
||||
filter: name,
|
||||
localstate: isParentContext ? CoreFilterStateValue.INHERIT : filterInContext.localstate,
|
||||
inheritedstate: isParentContext ?
|
||||
filterInContext.localstate :
|
||||
filters[name]?.inheritedstate ?? filterInContext.localstate,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
return Object.values(filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is an override for a category in the states of all filters.
|
||||
*
|
||||
* @param states States to check.
|
||||
* @returns True if has category override, false otherwise.
|
||||
*/
|
||||
protected hasCategoryOverride(states: CoreFilterAllStates): boolean {
|
||||
if (!states[ContextLevel.COURSECAT]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const instanceId in states[ContextLevel.COURSECAT]) {
|
||||
for (const name in states[ContextLevel.COURSECAT][instanceId]) {
|
||||
if (
|
||||
states[ContextLevel.COURSECAT][instanceId][name].localstate !== states[ContextLevel.SYSTEM][0][name].localstate
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filters and format text.
|
||||
*
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { CoreNetwork } from '@services/network';
|
||||
import { CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreSites, CoreSitesCommonWSOptions, CoreSitesReadingStrategy } from '@services/sites';
|
||||
import { CoreSite } from '@classes/sites/site';
|
||||
import { CoreWSExternalWarning } from '@services/ws';
|
||||
import { CoreTextUtils } from '@services/utils/text';
|
||||
|
@ -62,11 +62,37 @@ export class CoreFilterProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if getting all states is available in site.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @returns Whether it's available.
|
||||
* @since 4.4
|
||||
*/
|
||||
async canGetAllStates(siteId?: string): Promise<boolean> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
return this.canGetAllStatesInSite(site);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if getting all states is available in site.
|
||||
*
|
||||
* @param site Site. If not defined, current site.
|
||||
* @returns Whether it's available.
|
||||
* @since 4.4
|
||||
*/
|
||||
canGetAllStatesInSite(site?: CoreSite): boolean {
|
||||
site = site || CoreSites.getCurrentSite();
|
||||
|
||||
return !!(site?.wsAvailable('core_filters_get_all_states'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not we can get the available filters: the WS is available and the feature isn't disabled.
|
||||
*
|
||||
* @param siteId Site ID. If not defined, current site.
|
||||
* @returns Promise resolved with boolean: whethe can get filters.
|
||||
* @returns Whether can get filters.
|
||||
*/
|
||||
async canGetFilters(siteId?: string): Promise<boolean> {
|
||||
const disabled = await this.checkFiltersDisabled(siteId);
|
||||
|
@ -78,7 +104,7 @@ export class CoreFilterProvider {
|
|||
* Returns whether or not we can get the available filters: the WS is available and the feature isn't disabled.
|
||||
*
|
||||
* @param site Site. If not defined, current site.
|
||||
* @returns Promise resolved with boolean: whethe can get filters.
|
||||
* @returns Whether can get filters.
|
||||
*/
|
||||
canGetFiltersInSite(site?: CoreSite): boolean {
|
||||
return !this.checkFiltersDisabledInSite(site);
|
||||
|
@ -153,7 +179,7 @@ export class CoreFilterProvider {
|
|||
// Simulate the system context based on the inherited data.
|
||||
filter.contextlevel = ContextLevel.SYSTEM;
|
||||
filter.instanceid = 0;
|
||||
filter.contextid = -1;
|
||||
filter.contextid = undefined;
|
||||
filter.localstate = filter.inheritedstate;
|
||||
}
|
||||
|
||||
|
@ -171,7 +197,7 @@ export class CoreFilterProvider {
|
|||
* @param options Options.
|
||||
* @returns Context to use.
|
||||
*/
|
||||
convertContext(
|
||||
getEffectiveContext(
|
||||
contextLevel: ContextLevel,
|
||||
instanceId: number,
|
||||
options: {courseId?: number} = {},
|
||||
|
@ -241,6 +267,53 @@ export class CoreFilterProvider {
|
|||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for get all states WS call.
|
||||
*
|
||||
* @returns Cache key.
|
||||
*/
|
||||
protected getAllStatesCacheKey(): string {
|
||||
return this.ROOT_CACHE_KEY + 'allStates';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the states for filters.
|
||||
*
|
||||
* @param options Options.
|
||||
* @returns Promise resolved with the filters classified by context.
|
||||
* @since 4.4
|
||||
*/
|
||||
async getAllStates(options: CoreSitesCommonWSOptions = {}): Promise<CoreFilterAllStates> {
|
||||
const site = await CoreSites.getSite(options.siteId);
|
||||
|
||||
const preSets: CoreSiteWSPreSets = {
|
||||
cacheKey: this.getAllStatesCacheKey(),
|
||||
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
||||
// Use stale while revalidate by default, but always use the first value. If data is updated it will be stored in DB.
|
||||
...CoreSites.getReadingStrategyPreSets(options.readingStrategy ?? CoreSitesReadingStrategy.STALE_WHILE_REVALIDATE),
|
||||
};
|
||||
|
||||
const result = await site.read<CoreFilterGetAllStatesWSResponse>('core_filters_get_all_states', {}, preSets);
|
||||
|
||||
const classified: CoreFilterAllStates = {};
|
||||
|
||||
result.filters.forEach((filter) => {
|
||||
classified[filter.contextlevel] = classified[filter.contextlevel] || {};
|
||||
classified[filter.contextlevel][filter.instanceid] = classified[filter.contextlevel][filter.instanceid] || {};
|
||||
|
||||
classified[filter.contextlevel][filter.instanceid][filter.filter] = {
|
||||
contextlevel: filter.contextlevel,
|
||||
instanceid: filter.instanceid,
|
||||
contextid: filter.contextid,
|
||||
filter: filter.filter,
|
||||
localstate: filter.state,
|
||||
inheritedstate: filter.state,
|
||||
};
|
||||
});
|
||||
|
||||
return classified;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache key for available in contexts WS calls.
|
||||
*
|
||||
|
@ -370,6 +443,45 @@ export class CoreFilterProvider {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a context, return the list of contexts used in the filters inheritance tree, from bottom to top.
|
||||
* E.g. when using module, it will return the module context, course context (if course ID is supplied), category context
|
||||
* (if categoy ID is supplied) and system context.
|
||||
*
|
||||
* @param contextLevel Context level.
|
||||
* @param instanceId Instance ID.
|
||||
* @param options Options
|
||||
* @returns List of contexts.
|
||||
*/
|
||||
getContextsTreeList(
|
||||
contextLevel: ContextLevel,
|
||||
instanceId: number,
|
||||
options: {courseId?: number; categoryId?: number} = {},
|
||||
): { contextLevel: ContextLevel; instanceId: number }[] {
|
||||
// Make sure context has been converted.
|
||||
const newContext = CoreFilter.getEffectiveContext(contextLevel, instanceId, options);
|
||||
contextLevel = newContext.contextLevel;
|
||||
instanceId = newContext.instanceId;
|
||||
|
||||
const contexts = [
|
||||
{ contextLevel, instanceId },
|
||||
];
|
||||
|
||||
if (contextLevel === ContextLevel.MODULE && options.courseId) {
|
||||
contexts.push({ contextLevel: ContextLevel.COURSE, instanceId: options.courseId });
|
||||
}
|
||||
|
||||
if ((contextLevel === ContextLevel.MODULE || contextLevel === ContextLevel.COURSE) && options.categoryId) {
|
||||
contexts.push({ contextLevel: ContextLevel.COURSECAT, instanceId: options.categoryId });
|
||||
}
|
||||
|
||||
if (contextLevel !== ContextLevel.SYSTEM) {
|
||||
contexts.push({ contextLevel: ContextLevel.SYSTEM, instanceId: 0 });
|
||||
}
|
||||
|
||||
return contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates all available in context WS calls.
|
||||
*
|
||||
|
@ -382,6 +494,18 @@ export class CoreFilterProvider {
|
|||
await site.invalidateWsCacheForKeyStartingWith(this.getAvailableInContextsPrefixCacheKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates get all states WS call.
|
||||
*
|
||||
* @param siteId Site ID (empty for current site).
|
||||
* @returns Promise resolved when the data is invalidated.
|
||||
*/
|
||||
async invalidateAllStates(siteId?: string): Promise<void> {
|
||||
const site = await CoreSites.getSite(siteId);
|
||||
|
||||
await site.invalidateWsCacheForKey(this.getAllStatesCacheKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidates available in context WS call.
|
||||
*
|
||||
|
@ -499,15 +623,15 @@ export type CoreFiltersGetAvailableInContextWSParamContext = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Filter object returned by core_filters_get_available_in_context.
|
||||
* Filter data.
|
||||
*/
|
||||
export type CoreFilterFilter = {
|
||||
contextlevel: ContextLevel; // The context level where the filters are: (coursecat, course, module).
|
||||
instanceid: number; // The instance id of item associated with the context.
|
||||
contextid: number; // The context id.
|
||||
contextid?: number; // The context id. It will be undefined in cases where it cannot be calculated in the app.
|
||||
filter: string; // Filter plugin name.
|
||||
localstate: number; // Filter state: 1 for on, -1 for off, 0 if inherit.
|
||||
inheritedstate: number; // 1 or 0 to use when localstate is set to inherit.
|
||||
localstate: CoreFilterStateValue; // Filter state.
|
||||
inheritedstate: CoreFilterStateValue; // State to use when localstate is set to inherit.
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -518,6 +642,36 @@ export type CoreFilterGetAvailableInContextResult = {
|
|||
warnings: CoreWSExternalWarning[]; // List of warnings.
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter state returned by core_filters_get_all_states.
|
||||
*/
|
||||
export type CoreFilterState = {
|
||||
contextlevel: ContextLevel; // The context level where the filters are: (coursecat, course, module).
|
||||
instanceid: number; // The instance id of item associated with the context.
|
||||
contextid: number; // The context id.
|
||||
filter: string; // Filter plugin name.
|
||||
state: CoreFilterStateValue; // Filter state.
|
||||
sortorder: number; // Sort order.
|
||||
};
|
||||
|
||||
/**
|
||||
* Context levels enumeration.
|
||||
*/
|
||||
export const enum CoreFilterStateValue {
|
||||
ON = 1,
|
||||
INHERIT = 0,
|
||||
OFF = -1,
|
||||
DISABLED = -9999,
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of core_filters_get_all_states.
|
||||
*/
|
||||
export type CoreFilterGetAllStatesWSResponse = {
|
||||
filters: CoreFilterState[]; // Filter state.
|
||||
warnings: CoreWSExternalWarning[]; // List of warnings.
|
||||
};
|
||||
|
||||
/**
|
||||
* Options that can be passed to format text.
|
||||
*/
|
||||
|
@ -541,3 +695,14 @@ export type CoreFilterClassifiedFilters = {
|
|||
[instanceid: number]: CoreFilterFilter[];
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* All filter states classified by context, instance and filter name.
|
||||
*/
|
||||
export type CoreFilterAllStates = {
|
||||
[contextlevel: string]: {
|
||||
[instanceid: number]: {
|
||||
[filtername: string]: CoreFilterFilter;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue