Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/addon/mod/forum/components/index/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
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;
if (this.usesGroups) {
promise = this.forumProvider.formatDiscussionsGroups(this.forum.cmid, response.discussions);
Expand Down
9 changes: 5 additions & 4 deletions src/addon/mod/forum/pages/discussion/discussion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
let ratingInfo;

return syncPromise.then(() => {
return this.forumProvider.getDiscussionPosts(this.discussionId).then((response) => {
return this.forumProvider.getDiscussionPosts(this.discussionId, this.cmId).then((response) => {
onlinePosts = response.posts;
ratingInfo = response.ratinginfo;
}).then(() => {
Expand Down Expand Up @@ -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.
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);
Expand Down Expand Up @@ -479,13 +479,14 @@ export class AddonModForumDiscussionPage implements OnDestroy {
* Convenience function to load discussion.
*
* @param forumId Forum ID.
* @param cmId Forum cmid.
* @param discussionId Discussion ID.
* @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.
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.discussionId = this.discussion.discussion;
}).catch(() => {
Expand Down
24 changes: 16 additions & 8 deletions src/addon/mod/forum/providers/forum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,15 +492,18 @@ export class AddonModForumProvider {
* Get forum discussion posts.
*
* @param discussionId Discussion ID.
* @param cmId Forum cmid.
* @param siteId Site ID. If not defined, current site.
* @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 = {
discussionid: discussionId
};
const preSets = {
cacheKey: this.getDiscussionPostsCacheKey(discussionId)
cacheKey: this.getDiscussionPostsCacheKey(discussionId),
component: AddonModForumProvider.COMPONENT,
componentId: cmId
};

return this.sitesProvider.getSite(siteId).then((site) => {
Expand Down Expand Up @@ -592,6 +595,7 @@ export class AddonModForumProvider {
* Get forum discussions.
*
* @param forumId Forum ID.
* @param cmId Forum cmid
* @param sortOrder Sort order.
* @param page Page.
* @param forceCache True to always get the value from cache. false otherwise.
Expand All @@ -601,7 +605,8 @@ export class AddonModForumProvider {
* discussion ID is discussion.discussion.
* - 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;

return this.sitesProvider.getSite(siteId).then((site) => {
Expand All @@ -626,7 +631,9 @@ export class AddonModForumProvider {
}
}
const preSets: CoreSiteWSPreSets = {
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder)
cacheKey: this.getDiscussionsListCacheKey(forumId, sortOrder),
component: AddonModForumProvider.COMPONENT,
componentId: cmId
};
if (forceCache) {
preSets.omitExpires = true;
Expand Down Expand Up @@ -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.
*
* @param forumId Forum ID.
* @param cmId Forum cmid.
* @param sortOrder Sort order.
* @param forceCache True to always get the value from cache, false otherwise.
* @param numPages Number of pages to get. If not defined, all pages.
Expand All @@ -682,8 +690,8 @@ export class AddonModForumProvider {
* - discussions: List of discussions.
* - error: True if an error occurred, false otherwise.
*/
getDiscussionsInPages(forumId: number, sortOrder?: number, forceCache?: boolean, numPages?: number, startPage?: number,
siteId?: string): Promise<any> {
getDiscussionsInPages(forumId: number, cmId: number, sortOrder?: number, forceCache?: boolean,
numPages?: number, startPage?: number, siteId?: string): Promise<any> {
if (typeof numPages == 'undefined') {
numPages = -1;
}
Expand All @@ -700,7 +708,7 @@ export class AddonModForumProvider {

const getPage = (page: number): Promise<any> => {
// 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);
numPages--;

Expand Down Expand Up @@ -753,7 +761,7 @@ export class AddonModForumProvider {

this.getAvailableSortOrders().forEach((sortOrder) => {
// 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.
const promises = [];

Expand Down
5 changes: 3 additions & 2 deletions src/addon/mod/forum/providers/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,16 @@ export class AddonModForumHelperProvider {
* This function is inefficient because it needs to fetch all discussion pages in the worst case.
*
* @param forumId Forum ID.
* @param cmId Forum cmid
* @param discussionId Discussion ID.
* @param siteId Site ID. If not defined, current site.
* @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();

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) {
// Note that discussion.id is the main post ID but discussion ID is discussion.discussion.
const discussion = response.discussions.find((discussion) => discussion.discussion == discussionId);
Expand Down
5 changes: 3 additions & 2 deletions src/addon/mod/forum/providers/prefetch-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,16 @@ export class AddonModForumPrefetchHandler extends CoreCourseActivityPrefetchHand
protected getPostsForPrefetch(forum: any, siteId?: string): Promise<any[]> {
const promises = this.forumProvider.getAvailableSortOrders().map((sortOrder) => {
// 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) {
return Promise.reject(null);
}

const promises = [];

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);
Expand Down
12 changes: 10 additions & 2 deletions src/addon/storagemanager/pages/course-storage/course-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { CoreCourseHelperProvider } from '@core/course/providers/helper';
import { CoreDomUtilsProvider } from '@providers/utils/dom';
import { TranslateService } from '@ngx-translate/core';
import { CoreConstants } from '@core/constants';
import { CoreSitesProvider } from '@providers/sites';

/**
* Page that displays the amount of file storage used by each activity on the course, and allows
Expand All @@ -39,6 +40,7 @@ export class AddonStorageManagerCourseStoragePage {
totalSize: number;

constructor(navParams: NavParams,
private sitesProvider: CoreSitesProvider,
private courseProvider: CoreCourseProvider,
private prefetchDelegate: CoreCourseModulePrefetchDelegate,
private courseHelperProvider: CoreCourseHelperProvider,
Expand Down Expand Up @@ -70,7 +72,7 @@ export class AddonStorageManagerCourseStoragePage {
// But these aren't necessarily consistent, for example mod_frog vs mmaModFrog.
// There is nothing enforcing correct values.
// Most modules which have large files are downloadable, so I think this is sufficient.
const promise = this.prefetchDelegate.getModuleDownloadedSize(module, this.course.id).
const promise = this.prefetchDelegate.getModuleStoredSize(module, this.course.id).
then((size) => {
// There are some cases where the return from this is not a valid number.
if (!isNaN(size)) {
Expand Down Expand Up @@ -185,7 +187,13 @@ export class AddonStorageManagerCourseStoragePage {
modules.forEach((module) => {
// Remove the files.
const promise = this.prefetchDelegate.removeModuleFiles(module, this.course.id).then(() => {
// When the files are removed, update the size.
const handler = this.prefetchDelegate.getPrefetchHandlerFor(module);
if (handler) {

return this.sitesProvider.getCurrentSite().deleteComponentFromCache(handler.component, module.id);
}
}).then(() => {
// When the files and cache are removed, update the size.
module.parentSection.totalSize -= module.totalSize;
this.totalSize -= module.totalSize;
module.totalSize = 0;
Expand Down
89 changes: 88 additions & 1 deletion src/classes/site.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,17 @@ export interface CoreSiteWSPreSets {
* Defaults to CoreSite.FREQUENCY_USUALLY.
*/
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;
}

/**
Expand Down Expand Up @@ -197,7 +208,7 @@ export class CoreSite {
protected wsProvider: CoreWSProvider;

// Variables for the database.
static WS_CACHE_TABLE = 'wscache';
static WS_CACHE_TABLE = 'wscache_2';
static CONFIG_TABLE = 'core_site_config';

// Versions of Moodle releases.
Expand Down Expand Up @@ -1089,6 +1100,25 @@ export class CoreSite {
});
}

/**
* Gets the size of cached data for a specific component or component instance.
*
* @param component Component name
* @param componentId Optional component id (if not included, returns sum for whole component)
* @return Promise resolved when we have calculated the size
*/
getComponentCacheSize(component: string, componentId?: string): Promise<number> {
const params = [component];
let extraClause = '';
if (componentId) {
params.push(componentId);
extraClause = ' AND componentId = ?';
}

return this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE +
' WHERE component = ?' + extraClause, params);
}

/**
* Save a WS response to cache.
*
Expand Down Expand Up @@ -1128,6 +1158,13 @@ export class CoreSite {
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);
});
}
Expand Down Expand Up @@ -1155,6 +1192,33 @@ export class CoreSite {
return this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, { id: id });
}

/**
* Deletes WS cache entries for all methods relating to a specific component (and
* optionally component id).
*
* @param component Component name.
* @param componentId Component id.
* @return Promise resolved when the entries are deleted.
*/
async deleteComponentFromCache(component: string, componentId?: string): Promise<void> {
if (!component) {
return;
}

if (!this.db) {
throw new Error('Site DB not initialized');
}

const params = {
component: component
} as any;
if (componentId) {
params.componentId = componentId;
}

return this.db.deleteRecords(CoreSite.WS_CACHE_TABLE, params);
}

/*
* Uploads a file using Cordova File API.
*
Expand Down Expand Up @@ -1324,6 +1388,29 @@ export class CoreSite {
}
}

/**
* Gets an approximation of the cache table usage of the site.
*
* Currently this is just the total length of the data fields in the cache table.
*
* @return Promise resolved with the total size of all data in the cache table (bytes)
*/
getCacheUsage(): Promise<number> {
return this.db.getFieldSql('SELECT SUM(length(data)) FROM ' + CoreSite.WS_CACHE_TABLE);
}

/**
* Gets a total of the file and cache usage.
*
* @return Promise with the total of getSpaceUsage and getCacheUsage
*/
async getTotalUsage(): Promise<number> {
const space = await this.getSpaceUsage();
const cache = await this.getCacheUsage();

return space + cache;
}

/**
* Returns the URL to the documentation of the app, based on Moodle version and current language.
*
Expand Down
7 changes: 6 additions & 1 deletion src/core/course/providers/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,11 @@ export class CoreCourseHelperProvider {

await this.prefetchDelegate.removeModuleFiles(module, courseId);

const handler = this.prefetchDelegate.getPrefetchHandlerFor(module);
if (handler) {
await this.sitesProvider.getCurrentSite().deleteComponentFromCache(handler.component, String(module.id));
}

done && done();

} catch (error) {
Expand Down Expand Up @@ -1131,7 +1136,7 @@ export class CoreCourseHelperProvider {
this.prefetchDelegate.invalidateModuleStatusCache(module);
}

promises.push(this.prefetchDelegate.getModuleDownloadedSize(module, courseId).then((moduleSize) => {
promises.push(this.prefetchDelegate.getModuleStoredSize(module, courseId).then((moduleSize) => {
moduleInfo.size = moduleSize;
moduleInfo.sizeReadable = this.textUtils.bytesToSize(moduleSize, 2);
}));
Expand Down
30 changes: 30 additions & 0 deletions src/core/course/providers/module-prefetch-delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,36 @@ export class CoreCourseModulePrefetchDelegate extends CoreDelegate {
return Promise.resolve(0);
}

/**
* Gets the estimated total size of data stored for a module. This includes
* the files downloaded for it (getModuleDownloadedSize) and also the total
* size of web service requests stored for it.
*
* @param module Module to get the size.
* @param courseId Course ID the module belongs to.
* @return Promise resolved with the total size (0 if unknown)
*/
getModuleStoredSize(module: any, courseId: number): Promise<number> {
return this.getModuleDownloadedSize(module, courseId).then((downloadedSize) => {
if (isNaN(downloadedSize)) {
downloadedSize = 0;
}
const handler = this.getPrefetchHandlerFor(module);
if (handler) {
const site = this.sitesProvider.getCurrentSite();

return site.getComponentCacheSize(handler.component, module.id).then((cachedSize) => {
return cachedSize + downloadedSize;
});
} else {
// If there is no handler then we can't find out the component name.
// So we can't work out the cached size, so just return downloaded size.

return downloadedSize;
}
});
}

/**
* Get module files.
*
Expand Down
Loading