MOBILE-3188 Web services: Record component that owns WS cache item
This commit adds optional component and componentId fields to the preSets variable, which are recorded in the wscache table. These are then used by (a) core site plugins where a module cmid is available, and (b) the forum (as an example core implementation) so that module site plugins and forum provide the new data. (Note that this is not going to be very useful where we retrieve data for multiple activities at once, which happens for activities like Page. Still, it is optional.)main
parent
b67ea14abb
commit
d0c93f6416
|
@ -354,7 +354,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
||||||
this.page = 0;
|
this.page = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.forumProvider.getDiscussions(this.forum.id, this.selectedSortOrder.value, this.page).then((response) => {
|
return this.forumProvider.getDiscussions(this.forum.id, this.forum.cmid,
|
||||||
|
this.selectedSortOrder.value, this.page).then((response) => {
|
||||||
let promise;
|
let promise;
|
||||||
if (this.usesGroups) {
|
if (this.usesGroups) {
|
||||||
promise = this.forumProvider.formatDiscussionsGroups(this.forum.cmid, response.discussions);
|
promise = this.forumProvider.formatDiscussionsGroups(this.forum.cmid, response.discussions);
|
||||||
|
|
|
@ -323,7 +323,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
||||||
let ratingInfo;
|
let ratingInfo;
|
||||||
|
|
||||||
return syncPromise.then(() => {
|
return syncPromise.then(() => {
|
||||||
return this.forumProvider.getDiscussionPosts(this.discussionId).then((response) => {
|
return this.forumProvider.getDiscussionPosts(this.discussionId, this.cmId).then((response) => {
|
||||||
onlinePosts = response.posts;
|
onlinePosts = response.posts;
|
||||||
ratingInfo = response.ratinginfo;
|
ratingInfo = response.ratinginfo;
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
|
@ -412,7 +412,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
||||||
|
|
||||||
// The discussion object was not passed as parameter and there is no starting post. Should not happen.
|
// The discussion object was not passed as parameter and there is no starting post. Should not happen.
|
||||||
if (!this.discussion) {
|
if (!this.discussion) {
|
||||||
promises.push(this.loadDiscussion(this.forumId, this.discussionId));
|
promises.push(this.loadDiscussion(this.forumId, this.cmId, this.discussionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
|
@ -479,13 +479,14 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
||||||
* Convenience function to load discussion.
|
* Convenience function to load discussion.
|
||||||
*
|
*
|
||||||
* @param forumId Forum ID.
|
* @param forumId Forum ID.
|
||||||
|
* @param cmId Forum cmid.
|
||||||
* @param discussionId Discussion ID.
|
* @param discussionId Discussion ID.
|
||||||
* @return Promise resolved when done.
|
* @return Promise resolved when done.
|
||||||
*/
|
*/
|
||||||
protected loadDiscussion(forumId: number, discussionId: number): Promise<void> {
|
protected loadDiscussion(forumId: number, cmId: number, discussionId: number): Promise<void> {
|
||||||
// Fetch the discussion if not passed as parameter.
|
// Fetch the discussion if not passed as parameter.
|
||||||
if (!this.discussion && forumId) {
|
if (!this.discussion && forumId) {
|
||||||
return this.forumHelper.getDiscussionById(forumId, discussionId).then((discussion) => {
|
return this.forumHelper.getDiscussionById(forumId, cmId, discussionId).then((discussion) => {
|
||||||
this.discussion = discussion;
|
this.discussion = discussion;
|
||||||
this.discussionId = this.discussion.discussion;
|
this.discussionId = this.discussion.discussion;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
|
|
|
@ -492,15 +492,18 @@ export class AddonModForumProvider {
|
||||||
* Get forum discussion posts.
|
* Get forum discussion posts.
|
||||||
*
|
*
|
||||||
* @param discussionId Discussion ID.
|
* @param discussionId Discussion ID.
|
||||||
|
* @param cmId Forum cmid.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with forum posts and rating info.
|
* @return Promise resolved with forum posts and rating info.
|
||||||
*/
|
*/
|
||||||
getDiscussionPosts(discussionId: number, siteId?: string): Promise<{posts: any[], ratinginfo?: CoreRatingInfo}> {
|
getDiscussionPosts(discussionId: number, cmId: number, siteId?: string): Promise<{posts: any[], ratinginfo?: CoreRatingInfo}> {
|
||||||
const params = {
|
const params = {
|
||||||
discussionid: discussionId
|
discussionid: discussionId
|
||||||
};
|
};
|
||||||
const preSets = {
|
const preSets = {
|
||||||
cacheKey: this.getDiscussionPostsCacheKey(discussionId)
|
cacheKey: this.getDiscussionPostsCacheKey(discussionId),
|
||||||
|
component: AddonModForumProvider.COMPONENT,
|
||||||
|
componentId: cmId
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -592,6 +595,7 @@ export class AddonModForumProvider {
|
||||||
* Get forum discussions.
|
* Get forum discussions.
|
||||||
*
|
*
|
||||||
* @param forumId Forum ID.
|
* @param forumId Forum ID.
|
||||||
|
* @param cmId Forum cmid
|
||||||
* @param sortOrder Sort order.
|
* @param sortOrder Sort order.
|
||||||
* @param page Page.
|
* @param page Page.
|
||||||
* @param forceCache True to always get the value from cache. false otherwise.
|
* @param forceCache True to always get the value from cache. false otherwise.
|
||||||
|
@ -601,7 +605,8 @@ export class AddonModForumProvider {
|
||||||
* discussion ID is discussion.discussion.
|
* discussion ID is discussion.discussion.
|
||||||
* - canLoadMore: True if there may be more discussions to load.
|
* - canLoadMore: True if there may be more discussions to load.
|
||||||
*/
|
*/
|
||||||
getDiscussions(forumId: number, sortOrder?: number, page: number = 0, forceCache?: boolean, siteId?: string): Promise<any> {
|
getDiscussions(forumId: number, cmId: number, sortOrder?: number, page: number = 0,
|
||||||
|
forceCache?: boolean, siteId?: string): Promise<any> {
|
||||||
sortOrder = sortOrder || AddonModForumProvider.SORTORDER_LASTPOST_DESC;
|
sortOrder = sortOrder || AddonModForumProvider.SORTORDER_LASTPOST_DESC;
|
||||||
|
|
||||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
@ -626,7 +631,9 @@ export class AddonModForumProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const preSets: CoreSiteWSPreSets = {
|
const preSets: CoreSiteWSPreSets = {
|
||||||
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder)
|
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder),
|
||||||
|
component: AddonModForumProvider.COMPONENT,
|
||||||
|
componentId: cmId
|
||||||
};
|
};
|
||||||
if (forceCache) {
|
if (forceCache) {
|
||||||
preSets.omitExpires = true;
|
preSets.omitExpires = true;
|
||||||
|
@ -673,6 +680,7 @@ export class AddonModForumProvider {
|
||||||
* If a page fails, the discussions until that page will be returned along with a flag indicating an error occurred.
|
* If a page fails, the discussions until that page will be returned along with a flag indicating an error occurred.
|
||||||
*
|
*
|
||||||
* @param forumId Forum ID.
|
* @param forumId Forum ID.
|
||||||
|
* @param cmId Forum cmid.
|
||||||
* @param sortOrder Sort order.
|
* @param sortOrder Sort order.
|
||||||
* @param forceCache True to always get the value from cache, false otherwise.
|
* @param forceCache True to always get the value from cache, false otherwise.
|
||||||
* @param numPages Number of pages to get. If not defined, all pages.
|
* @param numPages Number of pages to get. If not defined, all pages.
|
||||||
|
@ -682,8 +690,8 @@ export class AddonModForumProvider {
|
||||||
* - discussions: List of discussions.
|
* - discussions: List of discussions.
|
||||||
* - error: True if an error occurred, false otherwise.
|
* - error: True if an error occurred, false otherwise.
|
||||||
*/
|
*/
|
||||||
getDiscussionsInPages(forumId: number, sortOrder?: number, forceCache?: boolean, numPages?: number, startPage?: number,
|
getDiscussionsInPages(forumId: number, cmId: number, sortOrder?: number, forceCache?: boolean,
|
||||||
siteId?: string): Promise<any> {
|
numPages?: number, startPage?: number, siteId?: string): Promise<any> {
|
||||||
if (typeof numPages == 'undefined') {
|
if (typeof numPages == 'undefined') {
|
||||||
numPages = -1;
|
numPages = -1;
|
||||||
}
|
}
|
||||||
|
@ -700,7 +708,7 @@ export class AddonModForumProvider {
|
||||||
|
|
||||||
const getPage = (page: number): Promise<any> => {
|
const getPage = (page: number): Promise<any> => {
|
||||||
// Get page discussions.
|
// Get page discussions.
|
||||||
return this.getDiscussions(forumId, sortOrder, page, forceCache, siteId).then((response) => {
|
return this.getDiscussions(forumId, cmId, sortOrder, page, forceCache, siteId).then((response) => {
|
||||||
result.discussions = result.discussions.concat(response.discussions);
|
result.discussions = result.discussions.concat(response.discussions);
|
||||||
numPages--;
|
numPages--;
|
||||||
|
|
||||||
|
@ -753,7 +761,7 @@ export class AddonModForumProvider {
|
||||||
|
|
||||||
this.getAvailableSortOrders().forEach((sortOrder) => {
|
this.getAvailableSortOrders().forEach((sortOrder) => {
|
||||||
// We need to get the list of discussions to be able to invalidate their posts.
|
// We need to get the list of discussions to be able to invalidate their posts.
|
||||||
promises.push(this.getDiscussionsInPages(forum.id, sortOrder.value, true).then((response) => {
|
promises.push(this.getDiscussionsInPages(forum.id, forum.cmid, sortOrder.value, true).then((response) => {
|
||||||
// Now invalidate the WS calls.
|
// Now invalidate the WS calls.
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
|
|
|
@ -270,15 +270,16 @@ export class AddonModForumHelperProvider {
|
||||||
* This function is inefficient because it needs to fetch all discussion pages in the worst case.
|
* This function is inefficient because it needs to fetch all discussion pages in the worst case.
|
||||||
*
|
*
|
||||||
* @param forumId Forum ID.
|
* @param forumId Forum ID.
|
||||||
|
* @param cmId Forum cmid
|
||||||
* @param discussionId Discussion ID.
|
* @param discussionId Discussion ID.
|
||||||
* @param siteId Site ID. If not defined, current site.
|
* @param siteId Site ID. If not defined, current site.
|
||||||
* @return Promise resolved with the discussion data.
|
* @return Promise resolved with the discussion data.
|
||||||
*/
|
*/
|
||||||
getDiscussionById(forumId: number, discussionId: number, siteId?: string): Promise<any> {
|
getDiscussionById(forumId: number, cmId: number, discussionId: number, siteId?: string): Promise<any> {
|
||||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
const findDiscussion = (page: number): Promise<any> => {
|
const findDiscussion = (page: number): Promise<any> => {
|
||||||
return this.forumProvider.getDiscussions(forumId, undefined, page, false, siteId).then((response) => {
|
return this.forumProvider.getDiscussions(forumId, cmId, undefined, page, false, siteId).then((response) => {
|
||||||
if (response.discussions && response.discussions.length > 0) {
|
if (response.discussions && response.discussions.length > 0) {
|
||||||
// Note that discussion.id is the main post ID but discussion ID is discussion.discussion.
|
// Note that discussion.id is the main post ID but discussion ID is discussion.discussion.
|
||||||
const discussion = response.discussions.find((discussion) => discussion.discussion == discussionId);
|
const discussion = response.discussions.find((discussion) => discussion.discussion == discussionId);
|
||||||
|
|
|
@ -114,7 +114,8 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
||||||
protected getPostsForPrefetch(forum: any, siteId?: string): Promise<any[]> {
|
protected getPostsForPrefetch(forum: any, siteId?: string): Promise<any[]> {
|
||||||
const promises = this.forumProvider.getAvailableSortOrders().map((sortOrder) => {
|
const promises = this.forumProvider.getAvailableSortOrders().map((sortOrder) => {
|
||||||
// Get discussions in first 2 pages.
|
// Get discussions in first 2 pages.
|
||||||
return this.forumProvider.getDiscussionsInPages(forum.id, sortOrder.value, false, 2, 0, siteId).then((response) => {
|
return this.forumProvider.getDiscussionsInPages(forum.id, forum.cmid,
|
||||||
|
sortOrder.value, false, 2, 0, siteId).then((response) => {
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
return Promise.reject(null);
|
return Promise.reject(null);
|
||||||
}
|
}
|
||||||
|
@ -122,7 +123,7 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
response.discussions.forEach((discussion) => {
|
response.discussions.forEach((discussion) => {
|
||||||
promises.push(this.forumProvider.getDiscussionPosts(discussion.discussion, siteId));
|
promises.push(this.forumProvider.getDiscussionPosts(discussion.discussion, forum.cmid, siteId));
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
|
|
|
@ -127,6 +127,17 @@ export interface CoreSiteWSPreSets {
|
||||||
* Defaults to CoreSite.FREQUENCY_USUALLY.
|
* Defaults to CoreSite.FREQUENCY_USUALLY.
|
||||||
*/
|
*/
|
||||||
updateFrequency?: number;
|
updateFrequency?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component name. Optionally included if this request is being made on behalf of a specific
|
||||||
|
* component (e.g. activity).
|
||||||
|
*/
|
||||||
|
component?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component id. Optionally included when 'component' is set.
|
||||||
|
*/
|
||||||
|
componentId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,7 +208,7 @@ export class CoreSite {
|
||||||
protected wsProvider: CoreWSProvider;
|
protected wsProvider: CoreWSProvider;
|
||||||
|
|
||||||
// Variables for the database.
|
// Variables for the database.
|
||||||
static WS_CACHE_TABLE = 'wscache';
|
static WS_CACHE_TABLE = 'ws_cache';
|
||||||
static CONFIG_TABLE = 'core_site_config';
|
static CONFIG_TABLE = 'core_site_config';
|
||||||
|
|
||||||
// Versions of Moodle releases.
|
// Versions of Moodle releases.
|
||||||
|
@ -1128,6 +1139,13 @@ export class CoreSite {
|
||||||
entry.key = preSets.cacheKey;
|
entry.key = preSets.cacheKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (preSets.component) {
|
||||||
|
entry.component = preSets.component;
|
||||||
|
if (preSets.componentId) {
|
||||||
|
entry.componentId = preSets.componentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.db.insertRecord(CoreSite.WS_CACHE_TABLE, entry);
|
return this.db.insertRecord(CoreSite.WS_CACHE_TABLE, entry);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,4 +9,4 @@
|
||||||
</core-context-menu>
|
</core-context-menu>
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
|
|
||||||
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [method]="method" [args]="args" [initResult]="initResult" [data]="jsData" [pageTitle]="pageTitle" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-plugins-plugin-content>
|
<core-site-plugins-plugin-content *ngIf="component && method" [component]="component" [componentId]="componentId" [method]="method" [args]="args" [initResult]="initResult" [data]="jsData" [pageTitle]="pageTitle" (onContentLoaded)="contentLoaded($event)" (onLoadingContent)="contentLoading($event)"></core-site-plugins-plugin-content>
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
||||||
@ViewChild(CoreSitePluginsPluginContentComponent) content: CoreSitePluginsPluginContentComponent;
|
@ViewChild(CoreSitePluginsPluginContentComponent) content: CoreSitePluginsPluginContentComponent;
|
||||||
|
|
||||||
component: string;
|
component: string;
|
||||||
|
componentId: number;
|
||||||
method: string;
|
method: string;
|
||||||
args: any;
|
args: any;
|
||||||
initResult: any;
|
initResult: any;
|
||||||
|
@ -77,6 +78,7 @@ export class CoreSitePluginsModuleIndexComponent implements OnInit, OnDestroy, C
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
this.component = handler.plugin.component;
|
this.component = handler.plugin.component;
|
||||||
|
this.componentId = this.module.id;
|
||||||
this.method = handler.handlerSchema.method;
|
this.method = handler.handlerSchema.method;
|
||||||
this.args = {
|
this.args = {
|
||||||
courseid: this.courseId,
|
courseid: this.courseId,
|
||||||
|
|
|
@ -32,6 +32,7 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck {
|
||||||
@ViewChild('compile') compileComponent: ElementRef;
|
@ViewChild('compile') compileComponent: ElementRef;
|
||||||
|
|
||||||
@Input() component: string;
|
@Input() component: string;
|
||||||
|
@Input() componentId?: number;
|
||||||
@Input() method: string;
|
@Input() method: string;
|
||||||
@Input() args: any;
|
@Input() args: any;
|
||||||
@Input() initResult: any; // Result of the init WS call of the handler.
|
@Input() initResult: any; // Result of the init WS call of the handler.
|
||||||
|
@ -92,7 +93,13 @@ export class CoreSitePluginsPluginContentComponent implements OnInit, DoCheck {
|
||||||
|
|
||||||
this.forceCompile = false;
|
this.forceCompile = false;
|
||||||
|
|
||||||
return this.sitePluginsProvider.getContent(this.component, this.method, this.args, this.preSets).then((result) => {
|
const preSets = Object.assign({}, this.preSets);
|
||||||
|
preSets.component = this.component;
|
||||||
|
if (this.componentId) {
|
||||||
|
preSets.componentId = this.componentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.sitePluginsProvider.getContent(this.component, this.method, this.args, preSets).then((result) => {
|
||||||
this.content = result.templates.length ? result.templates[0].html : ''; // Load first template.
|
this.content = result.templates.length ? result.templates[0].html : ''; // Load first template.
|
||||||
this.javascript = result.javascript;
|
this.javascript = result.javascript;
|
||||||
this.otherData = result.otherdata;
|
this.otherData = result.otherdata;
|
||||||
|
|
|
@ -514,7 +514,14 @@ export class CoreSitePluginsProvider {
|
||||||
promises.push(this.callWS(method, params, {cacheKey: cacheKey}));
|
promises.push(this.callWS(method, params, {cacheKey: cacheKey}));
|
||||||
} else {
|
} else {
|
||||||
// It's a method to get content.
|
// It's a method to get content.
|
||||||
promises.push(this.getContent(component, method, args).then((result) => {
|
const preSets = {
|
||||||
|
component: component,
|
||||||
|
componentId: undefined
|
||||||
|
};
|
||||||
|
if (module) {
|
||||||
|
preSets.componentId = module.id;
|
||||||
|
}
|
||||||
|
promises.push(this.getContent(component, method, args, preSets).then((result) => {
|
||||||
const subPromises = [];
|
const subPromises = [];
|
||||||
|
|
||||||
// Prefetch the files in the content.
|
// Prefetch the files in the content.
|
||||||
|
|
|
@ -360,7 +360,7 @@ export class CoreSitesProvider {
|
||||||
// Site schema for this provider.
|
// Site schema for this provider.
|
||||||
protected siteSchema: CoreSiteSchema = {
|
protected siteSchema: CoreSiteSchema = {
|
||||||
name: 'CoreSitesProvider',
|
name: 'CoreSitesProvider',
|
||||||
version: 1,
|
version: 2,
|
||||||
canBeCleared: [ CoreSite.WS_CACHE_TABLE ],
|
canBeCleared: [ CoreSite.WS_CACHE_TABLE ],
|
||||||
tables: [
|
tables: [
|
||||||
{
|
{
|
||||||
|
@ -382,6 +382,14 @@ export class CoreSitesProvider {
|
||||||
{
|
{
|
||||||
name: 'expirationTime',
|
name: 'expirationTime',
|
||||||
type: 'INTEGER'
|
type: 'INTEGER'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'component',
|
||||||
|
type: 'TEXT'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'componentId',
|
||||||
|
type: 'INTEGER'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -399,7 +407,27 @@ export class CoreSitesProvider {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
async migrate (db: SQLiteDB, oldVersion: number, siteId: string): Promise<any> {
|
||||||
|
if (oldVersion && oldVersion < 2) {
|
||||||
|
const newTable = CoreSite.WS_CACHE_TABLE;
|
||||||
|
const oldTable = 'wscache';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.tableExists(oldTable);
|
||||||
|
} catch (error) {
|
||||||
|
// Old table does not exist, ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Cannot use insertRecordsFrom because there are extra fields, so manually code INSERT INTO.
|
||||||
|
await db.execute(
|
||||||
|
'INSERT INTO ' + newTable + ' ' +
|
||||||
|
'SELECT id, data, key, expirationTime, NULL as component, NULL as componentId ' +
|
||||||
|
'FROM ' + oldTable);
|
||||||
|
|
||||||
|
return await db.dropTable(oldTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(logger: CoreLoggerProvider,
|
constructor(logger: CoreLoggerProvider,
|
||||||
|
|
Loading…
Reference in New Issue