2021-02-16 11:18:12 +01:00
|
|
|
// (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';
|
2021-08-26 11:22:53 +02:00
|
|
|
import { CoreError } from '@classes/errors/error';
|
2021-02-16 11:18:12 +01:00
|
|
|
import { CoreSite, CoreSiteWSPreSets } from '@classes/site';
|
|
|
|
import { CoreCourseCommonModWSOptions } from '@features/course/services/course';
|
|
|
|
import { CoreCourseLogHelper } from '@features/course/services/log-helper';
|
2021-03-05 16:38:42 +01:00
|
|
|
import { CoreRatingInfo } from '@features/rating/services/rating';
|
2021-04-06 16:20:26 +02:00
|
|
|
import { CoreTagItem } from '@features/tag/services/tag';
|
2021-02-16 11:18:12 +01:00
|
|
|
import { CoreUser } from '@features/user/services/user';
|
2022-05-11 14:06:42 +02:00
|
|
|
import { CoreNetwork } from '@services/network';
|
2021-04-16 15:15:21 +02:00
|
|
|
import { CoreFileEntry } from '@services/file-helper';
|
2021-02-16 11:18:12 +01:00
|
|
|
import { CoreGroups } from '@services/groups';
|
|
|
|
import { CoreSitesCommonWSOptions, CoreSites, CoreSitesReadingStrategy } from '@services/sites';
|
|
|
|
import { CoreUrlUtils } from '@services/utils/url';
|
|
|
|
import { CoreUtils } from '@services/utils/utils';
|
2021-04-16 15:15:21 +02:00
|
|
|
import { CoreStatusWithWarningsWSResponse, CoreWSExternalFile, CoreWSExternalWarning, CoreWSStoredFile } from '@services/ws';
|
2021-02-16 11:18:12 +01:00
|
|
|
import { makeSingleton, Translate } from '@singletons';
|
2021-03-18 11:19:36 +01:00
|
|
|
import { AddonModForumOffline, AddonModForumOfflineDiscussion, AddonModForumReplyOptions } from './forum-offline';
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
const ROOT_CACHE_KEY = 'mmaModForum:';
|
|
|
|
|
2021-03-01 13:40:17 +01:00
|
|
|
declare module '@singletons/events' {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Augment CoreEventsData interface with events specific to this service.
|
|
|
|
*
|
|
|
|
* @see https://www.typescriptlang.org/docs/handbook/declaration-merging.html#module-augmentation
|
|
|
|
*/
|
|
|
|
export interface CoreEventsData {
|
|
|
|
[AddonModForumProvider.NEW_DISCUSSION_EVENT]: AddonModForumNewDiscussionData;
|
|
|
|
[AddonModForumProvider.REPLY_DISCUSSION_EVENT]: AddonModForumReplyDiscussionData;
|
|
|
|
[AddonModForumProvider.CHANGE_DISCUSSION_EVENT]: AddonModForumChangeDiscussionData;
|
|
|
|
[AddonModForumProvider.MARK_READ_EVENT]: AddonModForumMarkReadData;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-16 11:18:12 +01:00
|
|
|
/**
|
|
|
|
* Service that provides some features for forums.
|
|
|
|
*/
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
|
|
export class AddonModForumProvider {
|
|
|
|
|
|
|
|
static readonly COMPONENT = 'mmaModForum';
|
|
|
|
static readonly DISCUSSIONS_PER_PAGE = 10; // Max of discussions per page.
|
|
|
|
static readonly NEW_DISCUSSION_EVENT = 'addon_mod_forum_new_discussion';
|
|
|
|
static readonly REPLY_DISCUSSION_EVENT = 'addon_mod_forum_reply_discussion';
|
|
|
|
static readonly CHANGE_DISCUSSION_EVENT = 'addon_mod_forum_change_discussion_status';
|
|
|
|
static readonly MARK_READ_EVENT = 'addon_mod_forum_mark_read';
|
|
|
|
static readonly LEAVING_POSTS_PAGE = 'addon_mod_forum_leaving_posts_page';
|
|
|
|
|
|
|
|
static readonly PREFERENCE_SORTORDER = 'forum_discussionlistsortorder';
|
|
|
|
static readonly SORTORDER_LASTPOST_DESC = 1;
|
|
|
|
static readonly SORTORDER_LASTPOST_ASC = 2;
|
|
|
|
static readonly SORTORDER_CREATED_DESC = 3;
|
|
|
|
static readonly SORTORDER_CREATED_ASC = 4;
|
|
|
|
static readonly SORTORDER_REPLIES_DESC = 5;
|
|
|
|
static readonly SORTORDER_REPLIES_ASC = 6;
|
|
|
|
|
|
|
|
static readonly ALL_PARTICIPANTS = -1;
|
|
|
|
static readonly ALL_GROUPS = -2;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for can add discussion WS calls.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param groupId Group ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getCanAddDiscussionCacheKey(forumId: number, groupId: number): string {
|
|
|
|
return this.getCommonCanAddDiscussionCacheKey(forumId) + groupId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get common part of cache key for can add discussion WS calls.
|
|
|
|
* TODO: Use getForumDataCacheKey as a prefix.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getCommonCanAddDiscussionCacheKey(forumId: number): string {
|
|
|
|
return ROOT_CACHE_KEY + 'canadddiscussion:' + forumId + ':';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get prefix cache key for all forum activity data WS calls.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getForumDataPrefixCacheKey(forumId: number): string {
|
|
|
|
return ROOT_CACHE_KEY + forumId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for discussion post data WS calls.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param discussionId Discussion ID.
|
|
|
|
* @param postId Course ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getDiscussionPostDataCacheKey(forumId: number, discussionId: number, postId: number): string {
|
|
|
|
return this.getForumDiscussionDataCacheKey(forumId, discussionId) + ':post:' + postId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for forum data WS calls.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getForumDiscussionDataCacheKey(forumId: number, discussionId: number): string {
|
|
|
|
return this.getForumDataPrefixCacheKey(forumId) + ':discussion:' + discussionId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for forum data WS calls.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getForumDataCacheKey(courseId: number): string {
|
|
|
|
return ROOT_CACHE_KEY + 'forum:' + courseId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for forum access information WS calls.
|
|
|
|
* TODO: Use getForumDataCacheKey as a prefix.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getAccessInformationCacheKey(forumId: number): string {
|
|
|
|
return ROOT_CACHE_KEY + 'accessInformation:' + forumId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for forum discussion posts WS calls.
|
|
|
|
* TODO: Use getForumDiscussionDataCacheKey instead.
|
|
|
|
*
|
|
|
|
* @param discussionId Discussion ID.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getDiscussionPostsCacheKey(discussionId: number): string {
|
|
|
|
return ROOT_CACHE_KEY + 'discussion:' + discussionId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get cache key for forum discussions list WS calls.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param sortOrder Sort order.
|
|
|
|
* @return Cache key.
|
|
|
|
*/
|
|
|
|
protected getDiscussionsListCacheKey(forumId: number, sortOrder: number): string {
|
|
|
|
let key = ROOT_CACHE_KEY + 'discussions:' + forumId;
|
|
|
|
|
|
|
|
if (sortOrder != AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
|
|
|
key += ':' + sortOrder;
|
|
|
|
}
|
|
|
|
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add a new discussion. It will fail if offline or cannot connect.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param subject New discussion's subject.
|
|
|
|
* @param message New discussion's message.
|
|
|
|
* @param options Options (subscribe, pin, ...).
|
|
|
|
* @param groupId Group this discussion belongs to.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the discussion is created.
|
|
|
|
*/
|
|
|
|
async addNewDiscussionOnline(
|
|
|
|
forumId: number,
|
|
|
|
subject: string,
|
|
|
|
message: string,
|
|
|
|
options?: AddonModForumAddDiscussionWSOptionsObject,
|
|
|
|
groupId?: number,
|
|
|
|
siteId?: string,
|
|
|
|
): Promise<number> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumAddDiscussionWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
subject: subject,
|
|
|
|
message: message,
|
|
|
|
|
|
|
|
// eslint-disable-next-line max-len
|
2021-03-02 11:41:04 +01:00
|
|
|
options: CoreUtils.objectToArrayOfObjects<AddonModForumAddDiscussionWSOptionsArray[0], AddonModForumAddDiscussionWSOptionsObject>(
|
2021-02-16 11:18:12 +01:00
|
|
|
options || {},
|
|
|
|
'name',
|
|
|
|
'value',
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
if (groupId) {
|
|
|
|
params.groupid = groupId;
|
|
|
|
}
|
|
|
|
|
|
|
|
const response = await site.write<AddonModForumAddDiscussionWSResponse>('mod_forum_add_discussion', params);
|
|
|
|
|
|
|
|
// Other errors ocurring.
|
2021-03-01 15:38:08 +01:00
|
|
|
return response.discussionid;
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a user can post to a certain group.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param groupId Group ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved with an object with the following properties:
|
|
|
|
* - status (boolean)
|
|
|
|
* - canpindiscussions (boolean)
|
|
|
|
* - cancreateattachment (boolean)
|
|
|
|
*/
|
|
|
|
async canAddDiscussion(
|
|
|
|
forumId: number,
|
|
|
|
groupId: number,
|
|
|
|
options: CoreCourseCommonModWSOptions = {},
|
|
|
|
): Promise<AddonModForumCanAddDiscussion> {
|
|
|
|
const params: AddonModForumCanAddDiscussionWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
groupid: groupId,
|
|
|
|
};
|
|
|
|
const preSets = {
|
|
|
|
cacheKey: this.getCanAddDiscussionCacheKey(forumId, groupId),
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
|
|
|
componentId: options.cmId,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const result = await site.read<AddonModForumCanAddDiscussionWSResponse>('mod_forum_can_add_discussion', params, preSets);
|
|
|
|
|
|
|
|
if (!result) {
|
|
|
|
throw new Error('Invalid response calling mod_forum_can_add_discussion');
|
|
|
|
}
|
|
|
|
|
2021-12-16 10:46:40 +01:00
|
|
|
if (result.canpindiscussions === undefined) {
|
2021-02-16 11:18:12 +01:00
|
|
|
// WS doesn't support it yet, default it to false to prevent students from seeing the option.
|
|
|
|
result.canpindiscussions = false;
|
|
|
|
}
|
2021-12-16 10:46:40 +01:00
|
|
|
if (result.cancreateattachment === undefined) {
|
2021-02-16 11:18:12 +01:00
|
|
|
// WS doesn't support it yet, default it to true since usually the users will be able to create them.
|
|
|
|
result.cancreateattachment = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if a user can post to all groups.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved with an object with the following properties:
|
|
|
|
* - status (boolean)
|
|
|
|
* - canpindiscussions (boolean)
|
|
|
|
* - cancreateattachment (boolean)
|
|
|
|
*/
|
|
|
|
canAddDiscussionToAll(forumId: number, options: CoreCourseCommonModWSOptions = {}): Promise<AddonModForumCanAddDiscussion> {
|
|
|
|
return this.canAddDiscussion(forumId, AddonModForumProvider.ALL_PARTICIPANTS, options);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Delete a post.
|
|
|
|
*
|
|
|
|
* @param postId Post id.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
* @since 3.8
|
|
|
|
*/
|
2021-02-18 11:49:15 +01:00
|
|
|
async deletePost(postId: number, siteId?: string): Promise<AddonModForumDeletePostWSResponse> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumDeletePostWSParams = {
|
|
|
|
postid: postId,
|
|
|
|
};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
return site.write<AddonModForumDeletePostWSResponse>('mod_forum_delete_post', params);
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract the starting post of a discussion from a list of posts. The post is removed from the array passed as a parameter.
|
|
|
|
*
|
|
|
|
* @param posts Posts to search.
|
|
|
|
* @return Starting post or undefined if not found.
|
|
|
|
*/
|
|
|
|
extractStartingPost(posts: AddonModForumPost[]): AddonModForumPost | undefined {
|
|
|
|
const index = posts.findIndex((post) => !post.parentid);
|
|
|
|
|
|
|
|
return index >= 0 ? posts.splice(index, 1).pop() : undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether or not getDiscussionPost WS available or not.
|
|
|
|
*
|
2021-05-11 09:36:26 +02:00
|
|
|
* @return If WS is available.
|
2021-02-16 11:18:12 +01:00
|
|
|
* @since 3.8
|
|
|
|
*/
|
|
|
|
isGetDiscussionPostAvailable(): boolean {
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreSites.wsAvailableInCurrentSite('mod_forum_get_discussion_post');
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether or not getDiscussionPost WS available or not.
|
|
|
|
*
|
|
|
|
* @param site Site. If not defined, current site.
|
2021-05-11 09:36:26 +02:00
|
|
|
* @return If WS is available.
|
2021-02-16 11:18:12 +01:00
|
|
|
* @since 3.7
|
|
|
|
*/
|
|
|
|
isGetDiscussionPostsAvailable(site?: CoreSite): boolean {
|
|
|
|
return site
|
|
|
|
? site.wsAvailable('mod_forum_get_discussion_posts')
|
2021-03-02 11:41:04 +01:00
|
|
|
: CoreSites.wsAvailableInCurrentSite('mod_forum_get_discussion_posts');
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether or not deletePost WS available or not.
|
|
|
|
*
|
2021-05-11 09:36:26 +02:00
|
|
|
* @return If WS is available.
|
2021-02-16 11:18:12 +01:00
|
|
|
* @since 3.8
|
|
|
|
*/
|
|
|
|
isDeletePostAvailable(): boolean {
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreSites.wsAvailableInCurrentSite('mod_forum_delete_post');
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether or not updatePost WS available or not.
|
|
|
|
*
|
2021-05-11 09:36:26 +02:00
|
|
|
* @return If WS is available.
|
2021-02-16 11:18:12 +01:00
|
|
|
* @since 3.8
|
|
|
|
*/
|
|
|
|
isUpdatePostAvailable(): boolean {
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreSites.wsAvailableInCurrentSite('mod_forum_update_discussion_post');
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Format discussions, setting groupname if the discussion group is valid.
|
|
|
|
*
|
|
|
|
* @param cmId Forum cmid.
|
|
|
|
* @param discussions List of discussions to format.
|
|
|
|
* @return Promise resolved with the formatted discussions.
|
|
|
|
*/
|
2021-02-18 11:49:15 +01:00
|
|
|
formatDiscussionsGroups(cmId: number, discussions: AddonModForumDiscussion[]): Promise<AddonModForumDiscussion[]>;
|
|
|
|
formatDiscussionsGroups(cmId: number, discussions: AddonModForumOfflineDiscussion[]): Promise<AddonModForumOfflineDiscussion[]>;
|
|
|
|
formatDiscussionsGroups(
|
|
|
|
cmId: number,
|
|
|
|
discussions: AddonModForumDiscussion[] | AddonModForumOfflineDiscussion[],
|
|
|
|
): Promise<AddonModForumDiscussion[] | AddonModForumOfflineDiscussion[]> {
|
2021-03-02 11:41:04 +01:00
|
|
|
discussions = CoreUtils.clone(discussions);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreGroups.getActivityAllowedGroups(cmId).then((result) => {
|
2021-02-16 11:18:12 +01:00
|
|
|
const strAllParts = Translate.instant('core.allparticipants');
|
|
|
|
const strAllGroups = Translate.instant('core.allgroups');
|
|
|
|
|
|
|
|
// Turn groups into an object where each group is identified by id.
|
|
|
|
const groups = {};
|
|
|
|
result.groups.forEach((fg) => {
|
|
|
|
groups[fg.id] = fg;
|
|
|
|
});
|
|
|
|
|
|
|
|
// Format discussions.
|
|
|
|
discussions.forEach((disc) => {
|
|
|
|
if (disc.groupid == AddonModForumProvider.ALL_PARTICIPANTS) {
|
|
|
|
disc.groupname = strAllParts;
|
|
|
|
} else if (disc.groupid == AddonModForumProvider.ALL_GROUPS) {
|
|
|
|
// Offline discussions only.
|
|
|
|
disc.groupname = strAllGroups;
|
|
|
|
} else {
|
|
|
|
const group = groups[disc.groupid];
|
|
|
|
if (group) {
|
|
|
|
disc.groupname = group.name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return discussions;
|
|
|
|
}).catch(() => discussions);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all course forums.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved when the forums are retrieved.
|
|
|
|
*/
|
|
|
|
async getCourseForums(courseId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModForumData[]> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
const params: AddonModForumGetForumsByCoursesWSParams = {
|
|
|
|
courseids: [courseId],
|
|
|
|
};
|
|
|
|
const preSets: CoreSiteWSPreSets = {
|
|
|
|
cacheKey: this.getForumDataCacheKey(courseId),
|
|
|
|
updateFrequency: CoreSite.FREQUENCY_RARELY,
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy),
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return site.read('mod_forum_get_forums_by_courses', params, preSets);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a particular discussion post.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param discussionId Discussion ID.
|
|
|
|
* @param postId Post ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved when the post is retrieved.
|
|
|
|
*/
|
|
|
|
async getDiscussionPost(
|
|
|
|
forumId: number,
|
|
|
|
discussionId: number,
|
|
|
|
postId: number,
|
|
|
|
options: CoreCourseCommonModWSOptions = {},
|
|
|
|
): Promise<AddonModForumPost> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumGetDiscussionPostWSParams = {
|
|
|
|
postid: postId,
|
|
|
|
};
|
|
|
|
const preSets = {
|
|
|
|
cacheKey: this.getDiscussionPostDataCacheKey(forumId, discussionId, postId),
|
|
|
|
updateFrequency: CoreSite.FREQUENCY_USUALLY,
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
|
|
|
componentId: options.cmId,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const response = await site.read<AddonModForumGetDiscussionPostWSResponse>(
|
|
|
|
'mod_forum_get_discussion_post',
|
|
|
|
params,
|
|
|
|
preSets,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!response.post) {
|
|
|
|
throw new Error('Post not found');
|
|
|
|
}
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
return this.translateWSPost(response.post);
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a forum by course module ID.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @param cmId Course module ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved when the forum is retrieved.
|
|
|
|
*/
|
|
|
|
async getForum(courseId: number, cmId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModForumData> {
|
|
|
|
const forums = await this.getCourseForums(courseId, options);
|
|
|
|
|
|
|
|
const forum = forums.find(forum => forum.cmid == cmId);
|
|
|
|
|
|
|
|
if (!forum) {
|
2021-08-26 11:22:53 +02:00
|
|
|
throw new CoreError(Translate.instant('core.course.modulenotfound'));
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return forum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a forum by forum ID.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved when the forum is retrieved.
|
|
|
|
*/
|
|
|
|
async getForumById(courseId: number, forumId: number, options: CoreSitesCommonWSOptions = {}): Promise<AddonModForumData> {
|
|
|
|
const forums = await this.getCourseForums(courseId, options);
|
|
|
|
const forum = forums.find(forum => forum.id === forumId);
|
|
|
|
|
|
|
|
if (!forum) {
|
|
|
|
throw new Error(`Forum with id ${forumId} not found`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return forum;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get access information for a given forum.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Object with access information.
|
|
|
|
* @since 3.7
|
|
|
|
*/
|
|
|
|
async getAccessInformation(
|
|
|
|
forumId: number,
|
|
|
|
options: CoreCourseCommonModWSOptions = {},
|
|
|
|
): Promise<AddonModForumAccessInformation> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
if (!site.wsAvailable('mod_forum_get_forum_access_information')) {
|
|
|
|
// Access information not available for 3.6 or older sites.
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const params: AddonModForumGetForumAccessInformationWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
};
|
|
|
|
const preSets = {
|
|
|
|
cacheKey: this.getAccessInformationCacheKey(forumId),
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
|
|
|
componentId: options.cmId,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
return site.read<AddonModForumGetForumAccessInformationWSResponse>(
|
|
|
|
'mod_forum_get_forum_access_information',
|
|
|
|
params,
|
|
|
|
preSets,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get forum discussion posts.
|
|
|
|
*
|
|
|
|
* @param discussionId Discussion ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved with forum posts and rating info.
|
|
|
|
*/
|
|
|
|
async getDiscussionPosts(discussionId: number, options: CoreCourseCommonModWSOptions = {}): Promise<{
|
|
|
|
posts: AddonModForumPost[];
|
|
|
|
courseid?: number;
|
|
|
|
forumid?: number;
|
2021-03-05 16:38:42 +01:00
|
|
|
ratinginfo?: CoreRatingInfo;
|
2021-02-16 11:18:12 +01:00
|
|
|
}> {
|
|
|
|
// Convenience function to translate legacy data to new format.
|
2021-02-18 11:49:15 +01:00
|
|
|
const translateLegacyPostsFormat = (posts: AddonModForumLegacyPost[]): AddonModForumPost[] => posts.map((post) => {
|
|
|
|
const newPost: AddonModForumPost = {
|
|
|
|
id: post.id,
|
2021-02-16 11:18:12 +01:00
|
|
|
discussionid: post.discussion,
|
|
|
|
parentid: post.parent,
|
|
|
|
hasparent: !!post.parent,
|
|
|
|
author: {
|
|
|
|
id: post.userid,
|
|
|
|
fullname: post.userfullname,
|
|
|
|
urls: { profileimage: post.userpictureurl },
|
|
|
|
},
|
|
|
|
timecreated: post.created,
|
|
|
|
subject: post.subject,
|
|
|
|
message: post.message,
|
|
|
|
attachments: post.attachments,
|
|
|
|
capabilities: {
|
|
|
|
reply: !!post.canreply,
|
|
|
|
},
|
|
|
|
|
|
|
|
unread: !post.postread,
|
|
|
|
isprivatereply: !!post.isprivatereply,
|
|
|
|
tags: post.tags,
|
|
|
|
};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
if ('groupname' in post && typeof post['groupname'] === 'string') {
|
|
|
|
newPost.author['groups'] = [{ name: post['groupname'] }];
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return newPost;
|
|
|
|
});
|
|
|
|
|
|
|
|
// For some reason, the new WS doesn't use the tags exporter so it returns a different format than other WebServices.
|
|
|
|
// Convert the new format to the exporter one so it's the same as in other WebServices.
|
2021-02-18 11:49:15 +01:00
|
|
|
const translateTagsFormatToLegacy = (posts: AddonModForumWSPost[]): AddonModForumPost[] => {
|
|
|
|
posts.forEach(post => this.translateWSPost(post));
|
2021-02-16 11:18:12 +01:00
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
return posts as unknown as AddonModForumPost[];
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
const params: AddonModForumGetDiscussionPostsWSParams | AddonModForumGetForumDiscussionPostsWSParams = {
|
|
|
|
discussionid: discussionId,
|
|
|
|
};
|
|
|
|
const preSets = {
|
|
|
|
cacheKey: this.getDiscussionPostsCacheKey(discussionId),
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
|
|
|
componentId: options.cmId,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const isGetDiscussionPostsAvailable = this.isGetDiscussionPostsAvailable(site);
|
|
|
|
|
|
|
|
const response = isGetDiscussionPostsAvailable
|
|
|
|
? await site.read<AddonModForumGetDiscussionPostsWSResponse>('mod_forum_get_discussion_posts', params, preSets)
|
|
|
|
: await site.read<AddonModForumGetForumDiscussionPostsWSResponse>(
|
|
|
|
'mod_forum_get_forum_discussion_posts',
|
|
|
|
params,
|
|
|
|
preSets,
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!response) {
|
|
|
|
throw new Error('Could not get forum posts');
|
|
|
|
}
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
const posts = isGetDiscussionPostsAvailable
|
|
|
|
? translateTagsFormatToLegacy((response as AddonModForumGetDiscussionPostsWSResponse).posts)
|
|
|
|
: translateLegacyPostsFormat((response as AddonModForumGetForumDiscussionPostsWSResponse).posts);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
this.storeUserData(posts);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
return {
|
|
|
|
...response,
|
|
|
|
posts,
|
|
|
|
};
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sort forum discussion posts by an specified field.
|
|
|
|
*
|
|
|
|
* @param posts Discussion posts to be sorted in place.
|
|
|
|
* @param direction Direction of the sorting (ASC / DESC).
|
|
|
|
*/
|
|
|
|
sortDiscussionPosts(posts: AddonModForumPost[], direction: string): void {
|
|
|
|
// @todo: Check children when sorting.
|
|
|
|
posts.sort((a, b) => {
|
|
|
|
const timeCreatedA = Number(a.timecreated) || 0;
|
|
|
|
const timeCreatedB = Number(b.timecreated) || 0;
|
|
|
|
if (timeCreatedA == 0 || timeCreatedB == 0) {
|
|
|
|
// Leave 0 at the end.
|
|
|
|
return timeCreatedB - timeCreatedA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (direction == 'ASC') {
|
|
|
|
return timeCreatedA - timeCreatedB;
|
|
|
|
} else {
|
|
|
|
return timeCreatedB - timeCreatedA;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return whether discussion lists can be sorted.
|
|
|
|
*
|
|
|
|
* @param site Site. If not defined, current site.
|
|
|
|
* @return True if discussion lists can be sorted.
|
|
|
|
*/
|
|
|
|
isDiscussionListSortingAvailable(site?: CoreSite): boolean {
|
2021-03-02 11:41:04 +01:00
|
|
|
site = site || CoreSites.getCurrentSite();
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
return !!site?.isVersionGreaterEqualThan('3.7');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the list of available sort orders.
|
|
|
|
*
|
|
|
|
* @return List of sort orders.
|
|
|
|
*/
|
|
|
|
getAvailableSortOrders(): AddonModForumSortOrder[] {
|
|
|
|
const sortOrders = [
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbylastpostdesc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_LASTPOST_DESC,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
if (this.isDiscussionListSortingAvailable()) {
|
|
|
|
sortOrders.push(
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbylastpostasc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_LASTPOST_ASC,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbycreateddesc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_CREATED_DESC,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbycreatedasc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_CREATED_ASC,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbyrepliesdesc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_REPLIES_DESC,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: 'addon.mod_forum.discussionlistsortbyrepliesasc',
|
|
|
|
value: AddonModForumProvider.SORTORDER_REPLIES_ASC,
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sortOrders;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get forum discussions.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param options Other options.
|
|
|
|
* @return Promise resolved with an object with:
|
|
|
|
* - discussions: List of discussions. Note that for every discussion in the list discussion.id is the main post ID but
|
|
|
|
* discussion ID is discussion.discussion.
|
|
|
|
* - canLoadMore: True if there may be more discussions to load.
|
|
|
|
*/
|
|
|
|
async getDiscussions(
|
|
|
|
forumId: number,
|
|
|
|
options: AddonModForumGetDiscussionsOptions = {},
|
|
|
|
): Promise<{ discussions: AddonModForumDiscussion[]; canLoadMore: boolean }> {
|
|
|
|
options.sortOrder = options.sortOrder || AddonModForumProvider.SORTORDER_LASTPOST_DESC;
|
|
|
|
options.page = options.page || 0;
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(options.siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
let method = 'mod_forum_get_forum_discussions_paginated';
|
|
|
|
const params: AddonModForumGetForumDiscussionsPaginatedWSParams | AddonModForumGetForumDiscussionsWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
page: options.page,
|
|
|
|
perpage: AddonModForumProvider.DISCUSSIONS_PER_PAGE,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (site.wsAvailable('mod_forum_get_forum_discussions')) {
|
|
|
|
// Since Moodle 3.7.
|
|
|
|
method = 'mod_forum_get_forum_discussions';
|
|
|
|
(params as AddonModForumGetForumDiscussionsWSParams).sortorder = options.sortOrder;
|
|
|
|
} else {
|
|
|
|
if (options.sortOrder !== AddonModForumProvider.SORTORDER_LASTPOST_DESC) {
|
|
|
|
throw new Error('Sorting not supported with the old WS method.');
|
|
|
|
}
|
|
|
|
|
|
|
|
(params as AddonModForumGetForumDiscussionsPaginatedWSParams).sortby = 'timemodified';
|
|
|
|
(params as AddonModForumGetForumDiscussionsPaginatedWSParams).sortdirection = 'DESC';
|
|
|
|
}
|
|
|
|
|
|
|
|
const preSets = {
|
|
|
|
cacheKey: this.getDiscussionsListCacheKey(forumId, options.sortOrder),
|
|
|
|
component: AddonModForumProvider.COMPONENT,
|
|
|
|
componentId: options.cmId,
|
2021-03-02 11:41:04 +01:00
|
|
|
...CoreSites.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
let response: AddonModForumGetForumDiscussionsPaginatedWSResponse | AddonModForumGetForumDiscussionsWSResponse;
|
|
|
|
try {
|
|
|
|
// eslint-disable-next-line max-len
|
|
|
|
response = await site.read<AddonModForumGetForumDiscussionsPaginatedWSResponse | AddonModForumGetForumDiscussionsWSResponse>(
|
|
|
|
method,
|
|
|
|
params,
|
|
|
|
preSets,
|
|
|
|
);
|
|
|
|
} catch (error) {
|
|
|
|
// Try to get the data from cache stored with the old WS method.
|
|
|
|
if (
|
2022-05-11 14:06:42 +02:00
|
|
|
CoreNetwork.isOnline() ||
|
2021-02-16 11:18:12 +01:00
|
|
|
method !== 'mod_forum_get_forum_discussions' ||
|
|
|
|
options.sortOrder !== AddonModForumProvider.SORTORDER_LASTPOST_DESC
|
|
|
|
) {
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
|
|
|
|
const params: AddonModForumGetForumDiscussionsPaginatedWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
page: options.page,
|
|
|
|
perpage: AddonModForumProvider.DISCUSSIONS_PER_PAGE,
|
|
|
|
sortby: 'timemodified',
|
|
|
|
sortdirection: 'DESC',
|
|
|
|
};
|
2021-06-03 12:15:45 +02:00
|
|
|
Object.assign(preSets, CoreSites.getReadingStrategyPreSets(CoreSitesReadingStrategy.PREFER_CACHE));
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
response = await site.read<AddonModForumGetForumDiscussionsPaginatedWSResponse>(
|
|
|
|
'mod_forum_get_forum_discussions_paginated',
|
|
|
|
params,
|
|
|
|
preSets,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!response) {
|
|
|
|
throw new Error('Could not get discussions');
|
|
|
|
}
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
this.storeUserData(response.discussions);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
return {
|
|
|
|
discussions: response.discussions,
|
|
|
|
canLoadMore: response.discussions.length >= AddonModForumProvider.DISCUSSIONS_PER_PAGE,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get forum discussions in several pages.
|
|
|
|
* 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.
|
|
|
|
* @param startPage Page to start. If not defined, first page.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved with an object with:
|
|
|
|
* - discussions: List of discussions.
|
|
|
|
* - error: True if an error occurred, false otherwise.
|
|
|
|
*/
|
|
|
|
async getDiscussionsInPages(
|
|
|
|
forumId: number,
|
|
|
|
options: AddonModForumGetDiscussionsInPagesOptions = {},
|
|
|
|
): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> {
|
|
|
|
options.page = options.page || 0;
|
|
|
|
|
|
|
|
const result = {
|
|
|
|
discussions: [] as AddonModForumDiscussion[],
|
|
|
|
error: false,
|
|
|
|
};
|
2021-12-16 10:46:40 +01:00
|
|
|
let numPages = options.numPages === undefined ? -1 : options.numPages;
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
if (!numPages) {
|
2021-03-01 15:38:08 +01:00
|
|
|
return result;
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const getPage = (page: number): Promise<{ discussions: AddonModForumDiscussion[]; error: boolean }> =>
|
|
|
|
// Get page discussions.
|
|
|
|
this.getDiscussions(forumId, options).then((response) => {
|
|
|
|
result.discussions = result.discussions.concat(response.discussions);
|
|
|
|
numPages--;
|
|
|
|
|
|
|
|
if (response.canLoadMore && numPages !== 0) {
|
|
|
|
return getPage(page + 1); // Get next page.
|
|
|
|
} else {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}).catch(() => {
|
|
|
|
// Error getting a page.
|
|
|
|
result.error = true;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
})
|
|
|
|
;
|
|
|
|
|
|
|
|
return getPage(options.page);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidates can add discussion WS calls.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateCanAddDiscussion(forumId: number, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
await site.invalidateWsCacheForKeyStartingWith(this.getCommonCanAddDiscussionCacheKey(forumId));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidate the prefetched content except files.
|
|
|
|
*
|
|
|
|
* @param moduleId The module ID.
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @return Promise resolved when data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateContent(moduleId: number, courseId: number): Promise<void> {
|
|
|
|
// Get the forum first, we need the forum ID.
|
|
|
|
const forum = await this.getForum(courseId, moduleId);
|
|
|
|
const promises: Promise<void>[] = [];
|
|
|
|
|
|
|
|
promises.push(this.invalidateForumData(courseId));
|
|
|
|
promises.push(this.invalidateDiscussionsList(forum.id));
|
|
|
|
promises.push(this.invalidateCanAddDiscussion(forum.id));
|
|
|
|
promises.push(this.invalidateAccessInformation(forum.id));
|
|
|
|
|
|
|
|
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, {
|
|
|
|
cmId: forum.cmid,
|
|
|
|
sortOrder: sortOrder.value,
|
2021-06-03 12:15:45 +02:00
|
|
|
readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE,
|
2021-02-16 11:18:12 +01:00
|
|
|
})
|
|
|
|
.then((response) => {
|
|
|
|
// Now invalidate the WS calls.
|
|
|
|
const promises: Promise<void>[] = [];
|
|
|
|
|
|
|
|
response.discussions.forEach((discussion) => {
|
|
|
|
promises.push(this.invalidateDiscussionPosts(discussion.discussion, forum.id));
|
|
|
|
});
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreUtils.allPromises(promises);
|
2021-02-16 11:18:12 +01:00
|
|
|
}),
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
if (this.isDiscussionListSortingAvailable()) {
|
2021-03-02 11:41:04 +01:00
|
|
|
promises.push(CoreUser.invalidateUserPreference(AddonModForumProvider.PREFERENCE_SORTORDER));
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreUtils.allPromises(promises);
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidates access information.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateAccessInformation(forumId: number, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
await site.invalidateWsCacheForKey(this.getAccessInformationCacheKey(forumId));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidates forum discussion posts.
|
|
|
|
*
|
|
|
|
* @param discussionId Discussion ID.
|
|
|
|
* @param forumId Forum ID. If not set, we can't invalidate individual post information.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateDiscussionPosts(discussionId: number, forumId?: number, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const promises = [site.invalidateWsCacheForKey(this.getDiscussionPostsCacheKey(discussionId))];
|
|
|
|
|
|
|
|
if (forumId) {
|
|
|
|
promises.push(site.invalidateWsCacheForKeyStartingWith(this.getForumDiscussionDataCacheKey(forumId, discussionId)));
|
|
|
|
}
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
await CoreUtils.allPromises(promises);
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidates discussion list.
|
|
|
|
*
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateDiscussionsList(forumId: number, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
await CoreUtils.allPromises(
|
2021-02-16 11:18:12 +01:00
|
|
|
this.getAvailableSortOrders()
|
|
|
|
.map(sortOrder => site.invalidateWsCacheForKey(this.getDiscussionsListCacheKey(forumId, sortOrder.value))),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidates forum data.
|
|
|
|
*
|
|
|
|
* @param courseId Course ID.
|
|
|
|
* @return Promise resolved when the data is invalidated.
|
|
|
|
*/
|
|
|
|
async invalidateForumData(courseId: number): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = CoreSites.getCurrentSite();
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
await site?.invalidateWsCacheForKey(this.getForumDataCacheKey(courseId));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Report a forum as being viewed.
|
|
|
|
*
|
|
|
|
* @param id Module ID.
|
|
|
|
* @param name Name of the forum.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the WS call is successful.
|
|
|
|
*/
|
|
|
|
logView(id: number, name?: string, siteId?: string): Promise<void> {
|
|
|
|
const params = {
|
|
|
|
forumid: id,
|
|
|
|
};
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreCourseLogHelper.logSingle(
|
2021-02-16 11:18:12 +01:00
|
|
|
'mod_forum_view_forum',
|
|
|
|
params,
|
|
|
|
AddonModForumProvider.COMPONENT,
|
|
|
|
id,
|
|
|
|
name,
|
|
|
|
'forum',
|
|
|
|
{},
|
|
|
|
siteId,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Report a forum discussion as being viewed.
|
|
|
|
*
|
|
|
|
* @param id Discussion ID.
|
|
|
|
* @param forumId Forum ID.
|
|
|
|
* @param name Name of the forum.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when the WS call is successful.
|
|
|
|
*/
|
|
|
|
logDiscussionView(id: number, forumId: number, name?: string, siteId?: string): Promise<void> {
|
|
|
|
const params = {
|
|
|
|
discussionid: id,
|
|
|
|
};
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreCourseLogHelper.logSingle(
|
2021-02-16 11:18:12 +01:00
|
|
|
'mod_forum_view_forum_discussion',
|
|
|
|
params,
|
|
|
|
AddonModForumProvider.COMPONENT,
|
|
|
|
forumId,
|
|
|
|
name,
|
|
|
|
'forum',
|
|
|
|
params,
|
|
|
|
siteId,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reply to a certain post.
|
|
|
|
*
|
|
|
|
* @param postId ID of the post being replied.
|
|
|
|
* @param discussionId ID of the discussion the user is replying to.
|
|
|
|
* @param forumId ID of the forum the user is replying to.
|
|
|
|
* @param name Forum name.
|
|
|
|
* @param courseId Course ID the forum belongs to.
|
|
|
|
* @param subject New post's subject.
|
|
|
|
* @param message New post's message.
|
|
|
|
* @param options Options (subscribe, attachments, ...).
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @param allowOffline True if it can be stored in offline, false otherwise.
|
|
|
|
* @return Promise resolved with a boolean indicating if the test was sent online or not.
|
|
|
|
*/
|
|
|
|
async replyPost(
|
|
|
|
postId: number,
|
|
|
|
discussionId: number,
|
|
|
|
forumId: number,
|
|
|
|
name: string,
|
|
|
|
courseId: number,
|
|
|
|
subject: string,
|
|
|
|
message: string,
|
|
|
|
options?: AddonModForumReplyOptions,
|
|
|
|
siteId?: string,
|
|
|
|
allowOffline?: boolean,
|
|
|
|
): Promise<boolean> {
|
2021-03-02 11:41:04 +01:00
|
|
|
siteId = siteId || CoreSites.getCurrentSiteId();
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
// Convenience function to store a message to be synchronized later.
|
|
|
|
const storeOffline = async (): Promise<boolean> => {
|
|
|
|
if (!forumId) {
|
|
|
|
// Not enough data to store in offline, reject.
|
|
|
|
throw new Error(Translate.instant('core.networkerrormsg'));
|
|
|
|
}
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
await AddonModForumOffline.replyPost(
|
2021-02-16 11:18:12 +01:00
|
|
|
postId,
|
|
|
|
discussionId,
|
|
|
|
forumId,
|
|
|
|
name,
|
|
|
|
courseId,
|
|
|
|
subject,
|
|
|
|
message,
|
|
|
|
options,
|
|
|
|
siteId,
|
|
|
|
);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
2022-05-11 14:06:42 +02:00
|
|
|
if (!CoreNetwork.isOnline() && allowOffline) {
|
2021-02-16 11:18:12 +01:00
|
|
|
// App is offline, store the action.
|
|
|
|
return storeOffline();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there's already a reply to be sent to the server, discard it first.
|
|
|
|
try {
|
2021-03-02 11:41:04 +01:00
|
|
|
await AddonModForumOffline.deleteReply(postId, siteId);
|
2021-02-18 11:49:15 +01:00
|
|
|
await this.replyPostOnline(
|
|
|
|
postId,
|
|
|
|
subject,
|
|
|
|
message,
|
|
|
|
options as unknown as AddonModForumAddDiscussionPostWSOptionsObject,
|
|
|
|
siteId,
|
|
|
|
);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
2021-03-02 11:41:04 +01:00
|
|
|
if (allowOffline && !CoreUtils.isWebServiceError(error)) {
|
2021-02-16 11:18:12 +01:00
|
|
|
// Couldn't connect to server, store in offline.
|
|
|
|
return storeOffline();
|
|
|
|
} else {
|
|
|
|
// The WebService has thrown an error or offline not supported, reject.
|
2021-03-01 15:38:08 +01:00
|
|
|
throw error;
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reply to a certain post. It will fail if offline or cannot connect.
|
|
|
|
*
|
|
|
|
* @param postId ID of the post being replied.
|
|
|
|
* @param subject New post's subject.
|
|
|
|
* @param message New post's message.
|
|
|
|
* @param options Options (subscribe, attachments, ...).
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved with the created post id.
|
|
|
|
*/
|
|
|
|
async replyPostOnline(
|
|
|
|
postId: number,
|
|
|
|
subject: string,
|
|
|
|
message: string,
|
|
|
|
options?: AddonModForumAddDiscussionPostWSOptionsObject,
|
|
|
|
siteId?: string,
|
|
|
|
): Promise<number> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumAddDiscussionPostWSParams = {
|
|
|
|
postid: postId,
|
|
|
|
subject: subject,
|
|
|
|
message: message,
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
options: CoreUtils.objectToArrayOfObjects<
|
2021-03-01 15:38:08 +01:00
|
|
|
AddonModForumAddDiscussionPostWSOptionsArray[0],
|
|
|
|
AddonModForumAddDiscussionPostWSOptionsObject
|
|
|
|
>(
|
2021-02-16 11:18:12 +01:00
|
|
|
options || {},
|
|
|
|
'name',
|
|
|
|
'value',
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
const response = await site.write<AddonModForumAddDiscussionPostWSResponse>('mod_forum_add_discussion_post', params);
|
|
|
|
|
|
|
|
if (!response || !response.postid) {
|
|
|
|
throw new Error('Post id missing from response');
|
|
|
|
}
|
|
|
|
|
|
|
|
return response.postid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lock or unlock a discussion.
|
|
|
|
*
|
|
|
|
* @param forumId Forum id.
|
|
|
|
* @param discussionId DIscussion id.
|
|
|
|
* @param locked True to lock, false to unlock.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
* @since 3.7
|
|
|
|
*/
|
2021-02-18 11:49:15 +01:00
|
|
|
async setLockState(
|
|
|
|
forumId: number,
|
|
|
|
discussionId: number,
|
|
|
|
locked: boolean,
|
|
|
|
siteId?: string,
|
|
|
|
): Promise<AddonModForumSetLockStateWSResponse> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumSetLockStateWSParams = {
|
|
|
|
forumid: forumId,
|
|
|
|
discussionid: discussionId,
|
|
|
|
targetstate: locked ? 0 : 1,
|
|
|
|
};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
return site.write<AddonModForumSetLockStateWSResponse>('mod_forum_set_lock_state', params);
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether the set pin state WS is available.
|
|
|
|
*
|
|
|
|
* @param site Site. If not defined, current site.
|
|
|
|
* @return Whether it's available.
|
|
|
|
* @since 3.7
|
|
|
|
*/
|
|
|
|
isSetPinStateAvailableForSite(): boolean {
|
2021-03-02 11:41:04 +01:00
|
|
|
return CoreSites.wsAvailableInCurrentSite('mod_forum_set_pin_state');
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pin or unpin a discussion.
|
|
|
|
*
|
|
|
|
* @param discussionId Discussion id.
|
|
|
|
* @param locked True to pin, false to unpin.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
* @since 3.7
|
|
|
|
*/
|
|
|
|
async setPinState(discussionId: number, pinned: boolean, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumSetPinStateWSParams = {
|
|
|
|
discussionid: discussionId,
|
|
|
|
targetstate: pinned ? 1 : 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
await site.write<AddonModForumSetPinStateWSResponse>('mod_forum_set_pin_state', params);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Star or unstar a discussion.
|
|
|
|
*
|
|
|
|
* @param discussionId Discussion id.
|
|
|
|
* @param starred True to star, false to unstar.
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved when done.
|
|
|
|
* @since 3.7
|
|
|
|
*/
|
|
|
|
async toggleFavouriteState(discussionId: number, starred: boolean, siteId?: string): Promise<void> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumToggleFavouriteStateWSParams = {
|
|
|
|
discussionid: discussionId,
|
2021-02-18 11:49:15 +01:00
|
|
|
targetstate: starred,
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
await site.write<AddonModForumToggleFavouriteStateWSResponse>('mod_forum_toggle_favourite_state', params);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Store the users data from a discussions/posts list.
|
|
|
|
*
|
|
|
|
* @param list Array of posts or discussions.
|
|
|
|
*/
|
2021-02-18 11:49:15 +01:00
|
|
|
protected storeUserData(list: AddonModForumPost[] | AddonModForumDiscussion[]): void {
|
2021-02-16 11:18:12 +01:00
|
|
|
const users = {};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
list.forEach((entry: AddonModForumPost | AddonModForumDiscussion) => {
|
|
|
|
if ('author' in entry) {
|
2021-02-16 11:18:12 +01:00
|
|
|
const authorId = Number(entry.author.id);
|
|
|
|
if (!isNaN(authorId) && !users[authorId]) {
|
|
|
|
users[authorId] = {
|
|
|
|
id: entry.author.id,
|
|
|
|
fullname: entry.author.fullname,
|
2021-02-18 11:49:15 +01:00
|
|
|
profileimageurl: entry.author.urls?.profileimage,
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
2021-02-18 11:49:15 +01:00
|
|
|
const userId = parseInt(entry['userid']);
|
|
|
|
if ('userid' in entry && !isNaN(userId) && !users[userId]) {
|
2021-02-16 11:18:12 +01:00
|
|
|
users[userId] = {
|
|
|
|
id: userId,
|
|
|
|
fullname: entry.userfullname,
|
|
|
|
profileimageurl: entry.userpictureurl,
|
|
|
|
};
|
|
|
|
}
|
2021-02-18 11:49:15 +01:00
|
|
|
const userModified = parseInt(entry['usermodified']);
|
|
|
|
if ('usermodified' in entry && !isNaN(userModified) && !users[userModified]) {
|
2021-02-16 11:18:12 +01:00
|
|
|
users[userModified] = {
|
|
|
|
id: userModified,
|
|
|
|
fullname: entry.usermodifiedfullname,
|
|
|
|
profileimageurl: entry.usermodifiedpictureurl,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
CoreUser.storeUsers(CoreUtils.objectToArray(users));
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update a certain post.
|
|
|
|
*
|
|
|
|
* @param postId ID of the post being edited.
|
|
|
|
* @param subject New post's subject.
|
|
|
|
* @param message New post's message.
|
|
|
|
* @param options Options (subscribe, attachments, ...).
|
|
|
|
* @param siteId Site ID. If not defined, current site.
|
|
|
|
* @return Promise resolved with success boolean when done.
|
|
|
|
*/
|
|
|
|
async updatePost(
|
|
|
|
postId: number,
|
|
|
|
subject: string,
|
|
|
|
message: string,
|
|
|
|
options?: AddonModForumUpdateDiscussionPostWSOptionsObject,
|
|
|
|
siteId?: string,
|
|
|
|
): Promise<boolean> {
|
2021-03-02 11:41:04 +01:00
|
|
|
const site = await CoreSites.getSite(siteId);
|
2021-02-16 11:18:12 +01:00
|
|
|
const params: AddonModForumUpdateDiscussionPostWSParams = {
|
|
|
|
postid: postId,
|
|
|
|
subject: subject,
|
|
|
|
message: message,
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
options: CoreUtils.objectToArrayOfObjects<
|
2021-03-01 15:38:08 +01:00
|
|
|
AddonModForumUpdateDiscussionPostWSOptionsArray[0],
|
|
|
|
AddonModForumUpdateDiscussionPostWSOptionsObject
|
|
|
|
>(
|
2021-02-16 11:18:12 +01:00
|
|
|
options || {},
|
|
|
|
'name',
|
|
|
|
'value',
|
|
|
|
),
|
|
|
|
};
|
|
|
|
|
|
|
|
const response = await site.write<AddonModForumUpdateDiscussionPostWSResponse>('mod_forum_update_discussion_post', params);
|
|
|
|
|
|
|
|
return response && response.status;
|
|
|
|
}
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
/**
|
|
|
|
* For some reason, the new WS doesn't use the tags exporter so it returns a different format than other WebServices.
|
|
|
|
* Convert the new format to the exporter one so it's the same as in other WebServices.
|
|
|
|
*
|
|
|
|
* @param post Post returned by the new WS.
|
|
|
|
* @return Post using the same format as other WebServices.
|
|
|
|
*/
|
|
|
|
protected translateWSPost(post: AddonModForumWSPost): AddonModForumPost {
|
|
|
|
(post as unknown as AddonModForumPost).tags = (post.tags || []).map((tag) => {
|
|
|
|
const viewUrl = (tag.urls && tag.urls.view) || '';
|
2021-03-02 11:41:04 +01:00
|
|
|
const params = CoreUrlUtils.extractUrlParams(viewUrl);
|
2021-02-18 11:49:15 +01:00
|
|
|
|
|
|
|
return {
|
|
|
|
id: tag.tagid,
|
|
|
|
taginstanceid: tag.id,
|
|
|
|
flag: tag.flag ? 1 : 0,
|
|
|
|
isstandard: tag.isstandard,
|
|
|
|
rawname: tag.displayname,
|
|
|
|
name: tag.displayname,
|
|
|
|
tagcollid: params.tc ? Number(params.tc) : undefined,
|
|
|
|
taginstancecontextid: params.from ? Number(params.from) : undefined,
|
|
|
|
};
|
|
|
|
});
|
|
|
|
|
|
|
|
return post as unknown as AddonModForumPost;
|
|
|
|
}
|
|
|
|
|
2021-02-16 11:18:12 +01:00
|
|
|
}
|
|
|
|
|
2021-03-02 11:41:04 +01:00
|
|
|
export const AddonModForum = makeSingleton(AddonModForumProvider);
|
2021-02-16 11:18:12 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_forums_by_courses WS.
|
|
|
|
*/
|
|
|
|
type AddonModForumGetForumsByCoursesWSParams = {
|
|
|
|
courseids?: number[]; // Array of Course IDs.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* General forum activity data.
|
|
|
|
*/
|
|
|
|
export type AddonModForumData = {
|
|
|
|
id: number; // Forum id.
|
|
|
|
course: number; // Course id.
|
|
|
|
type: string; // The forum type.
|
|
|
|
name: string; // Forum name.
|
|
|
|
intro: string; // The forum intro.
|
|
|
|
introformat: number; // Intro format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
introfiles?: CoreWSExternalFile[];
|
|
|
|
duedate?: number; // Duedate for the user.
|
|
|
|
cutoffdate?: number; // Cutoffdate for the user.
|
|
|
|
assessed: number; // Aggregate type.
|
|
|
|
assesstimestart: number; // Assess start time.
|
|
|
|
assesstimefinish: number; // Assess finish time.
|
|
|
|
scale: number; // Scale.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
grade_forum: number; // Whole forum grade.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
grade_forum_notify: number; // Whether to send notifications to students upon grading by default.
|
|
|
|
maxbytes: number; // Maximum attachment size.
|
|
|
|
maxattachments: number; // Maximum number of attachments.
|
|
|
|
forcesubscribe: number; // Force users to subscribe.
|
|
|
|
trackingtype: number; // Subscription mode.
|
|
|
|
rsstype: number; // RSS feed for this activity.
|
|
|
|
rssarticles: number; // Number of RSS recent articles.
|
|
|
|
timemodified: number; // Time modified.
|
|
|
|
warnafter: number; // Post threshold for warning.
|
|
|
|
blockafter: number; // Post threshold for blocking.
|
|
|
|
blockperiod: number; // Time period for blocking.
|
|
|
|
completiondiscussions: number; // Student must create discussions.
|
|
|
|
completionreplies: number; // Student must post replies.
|
|
|
|
completionposts: number; // Student must post discussions or replies.
|
|
|
|
cmid: number; // Course module id.
|
|
|
|
numdiscussions?: number; // Number of discussions in the forum.
|
|
|
|
cancreatediscussions?: boolean; // If the user can create discussions.
|
|
|
|
lockdiscussionafter?: number; // After what period a discussion is locked.
|
|
|
|
istracked?: boolean; // If the user is tracking the forum.
|
|
|
|
unreadpostscount?: number; // The number of unread posts for tracked forums.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Forum discussion.
|
|
|
|
*/
|
|
|
|
export type AddonModForumDiscussion = {
|
|
|
|
id: number; // Post id.
|
|
|
|
name: string; // Discussion name.
|
|
|
|
groupid: number; // Group id.
|
2021-02-18 11:49:15 +01:00
|
|
|
groupname?: string; // Group name (not returned by WS).
|
2021-02-16 11:18:12 +01:00
|
|
|
timemodified: number; // Time modified.
|
|
|
|
usermodified: number; // The id of the user who last modified.
|
|
|
|
timestart: number; // Time discussion can start.
|
|
|
|
timeend: number; // Time discussion ends.
|
|
|
|
discussion: number; // Discussion id.
|
|
|
|
parent: number; // Parent id.
|
|
|
|
userid: number; // User who started the discussion id.
|
|
|
|
created: number; // Creation time.
|
|
|
|
modified: number; // Time modified.
|
|
|
|
mailed: number; // Mailed?.
|
|
|
|
subject: string; // The post subject.
|
|
|
|
message: string; // The post message.
|
|
|
|
messageformat: number; // Message format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
messagetrust: number; // Can we trust?.
|
|
|
|
messageinlinefiles?: CoreWSExternalFile[];
|
|
|
|
attachment: string; // Has attachments?.
|
|
|
|
attachments?: CoreWSExternalFile[];
|
|
|
|
totalscore: number; // The post message total score.
|
|
|
|
mailnow: number; // Mail now?.
|
2021-02-24 17:02:15 +01:00
|
|
|
userfullname: string | boolean; // Post author full name.
|
2021-02-16 11:18:12 +01:00
|
|
|
usermodifiedfullname: string; // Post modifier full name.
|
2021-05-06 08:57:10 +02:00
|
|
|
userpictureurl?: string; // Post author picture.
|
2021-02-16 11:18:12 +01:00
|
|
|
usermodifiedpictureurl: string; // Post modifier picture.
|
|
|
|
numreplies: number; // The number of replies in the discussion.
|
|
|
|
numunread: number; // The number of unread discussions.
|
|
|
|
pinned: boolean; // Is the discussion pinned.
|
|
|
|
locked: boolean; // Is the discussion locked.
|
|
|
|
starred?: boolean; // Is the discussion starred.
|
|
|
|
canreply: boolean; // Can the user reply to the discussion.
|
|
|
|
canlock: boolean; // Can the user lock the discussion.
|
|
|
|
canfavourite?: boolean; // Can the user star the discussion.
|
|
|
|
};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
/**
|
|
|
|
* Forum post data returned by web services.
|
|
|
|
*/
|
|
|
|
export type AddonModForumPost = {
|
|
|
|
id: number; // Id.
|
|
|
|
subject: string; // Subject.
|
|
|
|
replysubject?: string; // Replysubject.
|
|
|
|
message: string; // Message.
|
|
|
|
author: {
|
|
|
|
id?: number; // Id.
|
|
|
|
fullname?: string; // Fullname.
|
|
|
|
urls?: {
|
|
|
|
profileimage?: string; // The URL for the use profile image.
|
|
|
|
};
|
|
|
|
groups?: { // Groups.
|
|
|
|
name: string; // Name.
|
|
|
|
}[];
|
|
|
|
};
|
|
|
|
discussionid: number; // Discussionid.
|
|
|
|
hasparent: boolean; // Hasparent.
|
|
|
|
parentid?: number; // Parentid.
|
|
|
|
timecreated: number | false; // Timecreated.
|
|
|
|
unread?: boolean; // Unread.
|
|
|
|
isprivatereply: boolean; // Isprivatereply.
|
|
|
|
capabilities: {
|
|
|
|
reply: boolean; // Whether the user can reply to the post.
|
2021-02-23 12:12:39 +01:00
|
|
|
view?: boolean; // Whether the user can view the post.
|
|
|
|
edit?: boolean; // Whether the user can edit the post.
|
|
|
|
delete?: boolean; // Whether the user can delete the post.
|
|
|
|
split?: boolean; // Whether the user can split the post.
|
|
|
|
selfenrol?: boolean; // Whether the user can self enrol into the course.
|
|
|
|
export?: boolean; // Whether the user can export the post.
|
|
|
|
controlreadstatus?: boolean; // Whether the user can control the read status of the post.
|
|
|
|
canreplyprivately?: boolean; // Whether the user can post a private reply.
|
2021-02-18 11:49:15 +01:00
|
|
|
};
|
|
|
|
attachment?: 0 | 1;
|
2021-04-16 15:15:21 +02:00
|
|
|
attachments?: CoreFileEntry[];
|
2021-02-24 17:02:15 +01:00
|
|
|
messageinlinefiles?: CoreWSExternalFile[];
|
2021-02-23 12:12:39 +01:00
|
|
|
haswordcount?: boolean; // Haswordcount.
|
|
|
|
wordcount?: number; // Wordcount.
|
2021-02-18 11:49:15 +01:00
|
|
|
tags?: { // Tags.
|
|
|
|
id: number; // Tag id.
|
|
|
|
name: string; // Tag name.
|
|
|
|
rawname: string; // The raw, unnormalised name for the tag as entered by users.
|
|
|
|
// isstandard: boolean; // Whether this tag is standard.
|
|
|
|
tagcollid?: number; // Tag collection id.
|
|
|
|
taginstanceid: number; // Tag instance id.
|
|
|
|
taginstancecontextid?: number; // Context the tag instance belongs to.
|
|
|
|
// itemid: number; // Id of the record tagged.
|
|
|
|
// ordering: number; // Tag ordering.
|
|
|
|
flag: number; // Whether the tag is flagged as inappropriate.
|
|
|
|
}[];
|
|
|
|
};
|
|
|
|
|
2021-02-16 11:18:12 +01:00
|
|
|
/**
|
|
|
|
* Legacy forum post data.
|
|
|
|
*/
|
|
|
|
export type AddonModForumLegacyPost = {
|
|
|
|
id: number; // Post id.
|
|
|
|
discussion: number; // Discussion id.
|
|
|
|
parent: number; // Parent id.
|
|
|
|
userid: number; // User id.
|
|
|
|
created: number; // Creation time.
|
|
|
|
modified: number; // Time modified.
|
|
|
|
mailed: number; // Mailed?.
|
|
|
|
subject: string; // The post subject.
|
|
|
|
message: string; // The post message.
|
|
|
|
messageformat: number; // Message format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
messagetrust: number; // Can we trust?.
|
|
|
|
messageinlinefiles?: CoreWSExternalFile[];
|
|
|
|
attachment: string; // Has attachments?.
|
|
|
|
attachments?: CoreWSExternalFile[];
|
|
|
|
totalscore: number; // The post message total score.
|
|
|
|
mailnow: number; // Mail now?.
|
|
|
|
children: number[];
|
|
|
|
canreply: boolean; // The user can reply to posts?.
|
|
|
|
postread: boolean; // The post was read.
|
|
|
|
userfullname: string; // Post author full name.
|
|
|
|
userpictureurl?: string; // Post author picture.
|
|
|
|
deleted: boolean; // This post has been removed.
|
|
|
|
isprivatereply: boolean; // The post is a private reply.
|
2021-04-06 16:20:26 +02:00
|
|
|
tags?: CoreTagItem[]; // Tags.
|
2021-02-16 11:18:12 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Options to pass to get discussions.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionsOptions = CoreCourseCommonModWSOptions & {
|
|
|
|
sortOrder?: number; // Sort order.
|
|
|
|
page?: number; // Page. Defaults to 0.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Options to pass to get discussions in pages.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionsInPagesOptions = AddonModForumGetDiscussionsOptions & {
|
|
|
|
numPages?: number; // Number of pages to get. If not defined, all pages.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Forum access information.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAccessInformation = {
|
|
|
|
canaddinstance?: boolean; // Whether the user has the capability mod/forum:addinstance allowed.
|
|
|
|
canviewdiscussion?: boolean; // Whether the user has the capability mod/forum:viewdiscussion allowed.
|
|
|
|
canviewhiddentimedposts?: boolean; // Whether the user has the capability mod/forum:viewhiddentimedposts allowed.
|
|
|
|
canstartdiscussion?: boolean; // Whether the user has the capability mod/forum:startdiscussion allowed.
|
|
|
|
canreplypost?: boolean; // Whether the user has the capability mod/forum:replypost allowed.
|
|
|
|
canaddnews?: boolean; // Whether the user has the capability mod/forum:addnews allowed.
|
|
|
|
canreplynews?: boolean; // Whether the user has the capability mod/forum:replynews allowed.
|
|
|
|
canviewrating?: boolean; // Whether the user has the capability mod/forum:viewrating allowed.
|
|
|
|
canviewanyrating?: boolean; // Whether the user has the capability mod/forum:viewanyrating allowed.
|
|
|
|
canviewallratings?: boolean; // Whether the user has the capability mod/forum:viewallratings allowed.
|
|
|
|
canrate?: boolean; // Whether the user has the capability mod/forum:rate allowed.
|
|
|
|
canpostprivatereply?: boolean; // Whether the user has the capability mod/forum:postprivatereply allowed.
|
|
|
|
canreadprivatereplies?: boolean; // Whether the user has the capability mod/forum:readprivatereplies allowed.
|
|
|
|
cancreateattachment?: boolean; // Whether the user has the capability mod/forum:createattachment allowed.
|
|
|
|
candeleteownpost?: boolean; // Whether the user has the capability mod/forum:deleteownpost allowed.
|
|
|
|
candeleteanypost?: boolean; // Whether the user has the capability mod/forum:deleteanypost allowed.
|
|
|
|
cansplitdiscussions?: boolean; // Whether the user has the capability mod/forum:splitdiscussions allowed.
|
|
|
|
canmovediscussions?: boolean; // Whether the user has the capability mod/forum:movediscussions allowed.
|
|
|
|
canpindiscussions?: boolean; // Whether the user has the capability mod/forum:pindiscussions allowed.
|
|
|
|
caneditanypost?: boolean; // Whether the user has the capability mod/forum:editanypost allowed.
|
|
|
|
canviewqandawithoutposting?: boolean; // Whether the user has the capability mod/forum:viewqandawithoutposting allowed.
|
|
|
|
canviewsubscribers?: boolean; // Whether the user has the capability mod/forum:viewsubscribers allowed.
|
|
|
|
canmanagesubscriptions?: boolean; // Whether the user has the capability mod/forum:managesubscriptions allowed.
|
|
|
|
canpostwithoutthrottling?: boolean; // Whether the user has the capability mod/forum:postwithoutthrottling allowed.
|
|
|
|
canexportdiscussion?: boolean; // Whether the user has the capability mod/forum:exportdiscussion allowed.
|
|
|
|
canexportforum?: boolean; // Whether the user has the capability mod/forum:exportforum allowed.
|
|
|
|
canexportpost?: boolean; // Whether the user has the capability mod/forum:exportpost allowed.
|
|
|
|
canexportownpost?: boolean; // Whether the user has the capability mod/forum:exportownpost allowed.
|
|
|
|
canaddquestion?: boolean; // Whether the user has the capability mod/forum:addquestion allowed.
|
|
|
|
canallowforcesubscribe?: boolean; // Whether the user has the capability mod/forum:allowforcesubscribe allowed.
|
|
|
|
cancanposttomygroups?: boolean; // Whether the user has the capability mod/forum:canposttomygroups allowed.
|
|
|
|
cancanoverridediscussionlock?: boolean; // Whether the user has the capability mod/forum:canoverridediscussionlock allowed.
|
|
|
|
cancanoverridecutoff?: boolean; // Whether the user has the capability mod/forum:canoverridecutoff allowed.
|
|
|
|
cancantogglefavourite?: boolean; // Whether the user has the capability mod/forum:cantogglefavourite allowed.
|
|
|
|
cangrade?: boolean; // Whether the user has the capability mod/forum:grade allowed.
|
|
|
|
};
|
|
|
|
|
2021-02-23 16:53:19 +01:00
|
|
|
/**
|
2021-08-06 07:57:47 +02:00
|
|
|
* Post creation or edition data.
|
2021-02-23 16:53:19 +01:00
|
|
|
*/
|
2021-08-06 07:57:47 +02:00
|
|
|
export type AddonModForumPostFormData = {
|
2021-02-23 16:53:19 +01:00
|
|
|
id: number;
|
2021-05-06 08:57:10 +02:00
|
|
|
subject: string | null; // Null means original data is not set.
|
|
|
|
message: string | null; // Null means empty or just white space.
|
2021-04-16 15:15:21 +02:00
|
|
|
files: CoreFileEntry[];
|
2021-05-06 08:57:10 +02:00
|
|
|
replyingTo?: number;
|
|
|
|
isEditing?: boolean;
|
|
|
|
isprivatereply?: boolean;
|
2021-02-23 16:53:19 +01:00
|
|
|
};
|
|
|
|
|
2021-02-16 11:18:12 +01:00
|
|
|
/**
|
|
|
|
* Can add discussion info.
|
|
|
|
*/
|
|
|
|
export type AddonModForumCanAddDiscussion = {
|
|
|
|
status: boolean; // True if the user can add discussions, false otherwise.
|
|
|
|
canpindiscussions?: boolean; // True if the user can pin discussions, false otherwise.
|
|
|
|
cancreateattachment?: boolean; // True if the user can add attachments, false otherwise.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sorting order.
|
|
|
|
*/
|
|
|
|
export type AddonModForumSortOrder = {
|
|
|
|
label: string;
|
|
|
|
value: number;
|
|
|
|
};
|
|
|
|
|
2021-02-18 11:49:15 +01:00
|
|
|
/**
|
|
|
|
* Forum post data returned by web services.
|
|
|
|
*/
|
|
|
|
export type AddonModForumWSPost = {
|
|
|
|
id: number; // Id.
|
|
|
|
subject: string; // Subject.
|
|
|
|
replysubject: string; // Replysubject.
|
|
|
|
message: string; // Message.
|
|
|
|
messageformat: number; // Message format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
author: {
|
|
|
|
id?: number; // Id.
|
|
|
|
fullname?: string; // Fullname.
|
|
|
|
isdeleted?: boolean; // Isdeleted.
|
|
|
|
groups?: { // Groups.
|
|
|
|
id: number; // Id.
|
|
|
|
name: string; // Name.
|
|
|
|
urls: {
|
|
|
|
image?: string; // Image.
|
|
|
|
};
|
|
|
|
}[];
|
|
|
|
urls: {
|
|
|
|
profile?: string; // The URL for the use profile page.
|
|
|
|
profileimage?: string; // The URL for the use profile image.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
discussionid: number; // Discussionid.
|
|
|
|
hasparent: boolean; // Hasparent.
|
|
|
|
parentid?: number; // Parentid.
|
|
|
|
timecreated: number; // Timecreated.
|
|
|
|
unread?: boolean; // Unread.
|
|
|
|
isdeleted: boolean; // Isdeleted.
|
|
|
|
isprivatereply: boolean; // Isprivatereply.
|
|
|
|
haswordcount: boolean; // Haswordcount.
|
|
|
|
wordcount?: number; // Wordcount.
|
|
|
|
charcount?: number; // Charcount.
|
|
|
|
capabilities: {
|
|
|
|
view: boolean; // Whether the user can view the post.
|
|
|
|
edit: boolean; // Whether the user can edit the post.
|
|
|
|
delete: boolean; // Whether the user can delete the post.
|
|
|
|
split: boolean; // Whether the user can split the post.
|
|
|
|
reply: boolean; // Whether the user can reply to the post.
|
|
|
|
selfenrol: boolean; // Whether the user can self enrol into the course.
|
|
|
|
export: boolean; // Whether the user can export the post.
|
|
|
|
controlreadstatus: boolean; // Whether the user can control the read status of the post.
|
|
|
|
canreplyprivately: boolean; // Whether the user can post a private reply.
|
|
|
|
};
|
|
|
|
urls?: {
|
|
|
|
view?: string; // The URL used to view the post.
|
|
|
|
viewisolated?: string; // The URL used to view the post in isolation.
|
|
|
|
viewparent?: string; // The URL used to view the parent of the post.
|
|
|
|
edit?: string; // The URL used to edit the post.
|
|
|
|
delete?: string; // The URL used to delete the post.
|
|
|
|
|
|
|
|
// The URL used to split the discussion with the selected post being the first post in the new discussion.
|
|
|
|
split?: string;
|
|
|
|
|
|
|
|
reply?: string; // The URL used to reply to the post.
|
|
|
|
export?: string; // The URL used to export the post.
|
|
|
|
markasread?: string; // The URL used to mark the post as read.
|
|
|
|
markasunread?: string; // The URL used to mark the post as unread.
|
|
|
|
discuss?: string; // Discuss.
|
|
|
|
};
|
2021-04-16 15:15:21 +02:00
|
|
|
attachments: CoreWSStoredFile[]; // Attachments.
|
2021-02-18 11:49:15 +01:00
|
|
|
tags?: { // Tags.
|
|
|
|
id: number; // The ID of the Tag.
|
|
|
|
tagid: number; // The tagid.
|
|
|
|
isstandard: boolean; // Whether this is a standard tag.
|
|
|
|
displayname: string; // The display name of the tag.
|
|
|
|
flag: boolean; // Wehther this tag is flagged.
|
|
|
|
urls: {
|
|
|
|
view: string; // The URL to view the tag.
|
|
|
|
};
|
|
|
|
}[];
|
|
|
|
html?: {
|
|
|
|
rating?: string; // The HTML source to rate the post.
|
|
|
|
taglist?: string; // The HTML source to view the list of tags.
|
|
|
|
authorsubheading?: string; // The HTML source to view the author details.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2021-02-16 11:18:12 +01:00
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_forum_discussions WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionsWSParams = {
|
|
|
|
forumid: number; // Forum instance id.
|
|
|
|
sortorder?: number; // Sort by this element: numreplies, , created or timemodified.
|
|
|
|
page?: number; // Current page.
|
|
|
|
perpage?: number; // Items per page.
|
|
|
|
groupid?: number; // Group id.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_forum_discussions WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionsWSResponse = {
|
|
|
|
discussions: AddonModForumDiscussion[];
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_forum_discussions_paginated WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionsPaginatedWSParams = {
|
|
|
|
forumid: number; // Forum instance id.
|
|
|
|
sortby?: string; // Sort by this element: id, timemodified, timestart or timeend.
|
|
|
|
sortdirection?: string; // Sort direction: ASC or DESC.
|
|
|
|
page?: number; // Current page.
|
|
|
|
perpage?: number; // Items per page.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_forum_discussions_paginated WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionsPaginatedWSResponse = {
|
|
|
|
discussions: AddonModForumDiscussion[];
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_forums_by_courses WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumsByCoursesWSResponse = AddonModForumData[];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array options of mod_forum_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionWSOptionsArray = {
|
|
|
|
// Option name.
|
|
|
|
name: 'discussionsubscribe' | 'discussionpinned' | 'inlineattachmentsid' | 'attachmentsid';
|
|
|
|
|
|
|
|
// Option value.
|
|
|
|
// This param is validated in the external function, expected values are:
|
|
|
|
// discussionsubscribe (bool) - subscribe to the discussion?, default to true
|
|
|
|
// discussionpinned (bool) - is the discussion pinned, default to false
|
|
|
|
// inlineattachmentsid (int) - the draft file area id for inline attachments
|
|
|
|
// attachmentsid (int) - the draft file area id for attachments.
|
|
|
|
value: string;
|
|
|
|
}[];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object options of mod_forum_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionWSOptionsObject = {
|
|
|
|
discussionsubscribe?: string;
|
|
|
|
discussionpinned?: string;
|
|
|
|
inlineattachmentsid?: string;
|
|
|
|
attachmentsid?: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array options of mod_forum_add_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionPostWSOptionsArray = {
|
|
|
|
// Option name.
|
|
|
|
name: 'discussionsubscribe' | 'private' | 'inlineattachmentsid' | 'attachmentsid' | 'topreferredformat';
|
|
|
|
|
|
|
|
// Option value.
|
|
|
|
// This param is validated in the external function, expected values are:
|
|
|
|
// discussionsubscribe (bool) - subscribe to the discussion?, default to true
|
|
|
|
// private (bool) - make this reply private to the author of the parent post, default to false.
|
|
|
|
// inlineattachmentsid (int) - the draft file area id for inline attachments
|
|
|
|
// attachmentsid (int) - the draft file area id for attachments
|
|
|
|
// topreferredformat (bool) - convert the message & messageformat to FORMAT_HTML, defaults to false.
|
|
|
|
value: string;
|
|
|
|
}[];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object options of mod_forum_add_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionPostWSOptionsObject = {
|
|
|
|
discussionsubscribe?: boolean;
|
|
|
|
private?: boolean;
|
|
|
|
inlineattachmentsid?: number;
|
|
|
|
attachmentsid?: number;
|
|
|
|
topreferredformat?: boolean;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Array options of mod_forum_update_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumUpdateDiscussionPostWSOptionsArray = {
|
|
|
|
// Option name.
|
|
|
|
name: 'pinned' | 'discussionsubscribe' | 'inlineattachmentsid' | 'attachmentsid';
|
|
|
|
|
|
|
|
// Option value.
|
|
|
|
// This param is validated in the external function, expected values are:
|
|
|
|
// pinned (bool) - (only for discussions) whether to pin this discussion or not
|
|
|
|
// discussionsubscribe (bool) - whether to subscribe to the post or not
|
|
|
|
// inlineattachmentsid (int) - the draft file area id for inline attachments in the text
|
|
|
|
// attachmentsid (int) - the draft file area id for attachments.
|
|
|
|
value: string; // The value of the option.
|
|
|
|
}[];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Object options of mod_forum_update_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumUpdateDiscussionPostWSOptionsObject = {
|
|
|
|
pinned?: boolean;
|
|
|
|
discussionsubscribe?: boolean;
|
|
|
|
inlineattachmentsid?: number;
|
|
|
|
attachmentsid?: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionWSParams = {
|
|
|
|
forumid: number; // Forum instance ID.
|
|
|
|
subject: string; // New Discussion subject.
|
|
|
|
message: string; // New Discussion message (only html format allowed).
|
|
|
|
groupid?: number; // The group, default to 0.
|
|
|
|
options?: AddonModForumAddDiscussionWSOptionsArray;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionWSResponse = {
|
|
|
|
discussionid: number; // New Discussion ID.
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_add_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionPostWSParams = {
|
|
|
|
postid: number; // The post id we are going to reply to (can be the initial discussion post).
|
|
|
|
subject: string; // New post subject.
|
|
|
|
message: string; // New post message (html assumed if messageformat is not provided).
|
|
|
|
options?: AddonModForumAddDiscussionPostWSOptionsArray;
|
|
|
|
messageformat?: number; // Message format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_add_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumAddDiscussionPostWSResponse = {
|
|
|
|
postid: number; // New post id.
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
2021-02-18 11:49:15 +01:00
|
|
|
post: AddonModForumWSPost;
|
2021-02-16 11:18:12 +01:00
|
|
|
messages?: { // List of warnings.
|
|
|
|
type: string; // The classification to be used in the client side.
|
|
|
|
message: string; // Untranslated english message to explain the warning.
|
|
|
|
}[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_forum_access_information WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumAccessInformationWSParams = {
|
|
|
|
forumid: number; // Forum instance id.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_forum_access_information WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumAccessInformationWSResponse = {
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
} & AddonModForumAccessInformation;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_can_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumCanAddDiscussionWSParams = {
|
|
|
|
forumid: number; // Forum instance ID.
|
|
|
|
groupid?: number; // The group to check, default to active group (Use -1 to check if the user can post in all the groups).
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_can_add_discussion WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumCanAddDiscussionWSResponse = {
|
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
} & AddonModForumCanAddDiscussion;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_delete_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumDeletePostWSParams = {
|
|
|
|
postid: number; // Post to be deleted. It can be a discussion topic post.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_delete_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumDeletePostWSResponse = CoreStatusWithWarningsWSResponse;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionPostWSParams = {
|
|
|
|
postid: number; // Post to fetch.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionPostWSResponse = {
|
2021-02-18 11:49:15 +01:00
|
|
|
post: AddonModForumWSPost;
|
2021-02-16 11:18:12 +01:00
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_discussion_posts WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionPostsWSParams = {
|
|
|
|
discussionid: number; // The ID of the discussion from which to fetch posts.
|
|
|
|
sortby?: string; // Sort by this element: id, created or modified.
|
|
|
|
sortdirection?: string; // Sort direction: ASC or DESC.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_discussion_posts WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetDiscussionPostsWSResponse = {
|
2021-02-18 11:49:15 +01:00
|
|
|
posts: AddonModForumWSPost[];
|
2021-02-16 11:18:12 +01:00
|
|
|
forumid: number; // The forum id.
|
|
|
|
courseid: number; // The forum course id.
|
2021-03-05 16:38:42 +01:00
|
|
|
ratinginfo?: CoreRatingInfo; // Rating information.
|
2021-02-16 11:18:12 +01:00
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_get_forum_discussion_posts WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionPostsWSParams = {
|
|
|
|
discussionid: number; // Discussion ID.
|
|
|
|
sortby?: string; // Sort by this element: id, created or modified.
|
|
|
|
sortdirection?: string; // Sort direction: ASC or DESC.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_get_forum_discussion_posts WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumGetForumDiscussionPostsWSResponse = {
|
|
|
|
posts: AddonModForumLegacyPost[];
|
2021-03-05 16:38:42 +01:00
|
|
|
ratinginfo?: CoreRatingInfo; // Rating information.
|
2021-02-16 11:18:12 +01:00
|
|
|
warnings?: CoreWSExternalWarning[];
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_set_lock_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumSetLockStateWSParams = {
|
|
|
|
forumid: number; // Forum that the discussion is in.
|
|
|
|
discussionid: number; // The discussion to lock / unlock.
|
|
|
|
targetstate: number; // The timestamp for the lock state.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_set_lock_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumSetLockStateWSResponse = {
|
|
|
|
id: number; // The discussion we are locking.
|
|
|
|
locked: boolean; // The locked state of the discussion.
|
|
|
|
times: {
|
|
|
|
locked: number; // The locked time of the discussion.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_set_pin_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumSetPinStateWSParams = {
|
|
|
|
discussionid: number; // The discussion to pin or unpin.
|
|
|
|
targetstate: number; // The target state.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_set_pin_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumSetPinStateWSResponse = {
|
|
|
|
id: number; // Id.
|
|
|
|
forumid: number; // Forumid.
|
|
|
|
pinned: boolean; // Pinned.
|
|
|
|
locked: boolean; // Locked.
|
|
|
|
istimelocked: boolean; // Istimelocked.
|
|
|
|
name: string; // Name.
|
|
|
|
firstpostid: number; // Firstpostid.
|
|
|
|
group?: {
|
|
|
|
name: string; // Name.
|
|
|
|
urls: {
|
|
|
|
picture?: string; // Picture.
|
|
|
|
userlist?: string; // Userlist.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
times: {
|
|
|
|
modified: number; // Modified.
|
|
|
|
start: number; // Start.
|
|
|
|
end: number; // End.
|
|
|
|
locked: number; // Locked.
|
|
|
|
};
|
|
|
|
userstate: {
|
|
|
|
subscribed: boolean; // Subscribed.
|
|
|
|
favourited: boolean; // Favourited.
|
|
|
|
};
|
|
|
|
capabilities: {
|
|
|
|
subscribe: boolean; // Subscribe.
|
|
|
|
move: boolean; // Move.
|
|
|
|
pin: boolean; // Pin.
|
|
|
|
post: boolean; // Post.
|
|
|
|
manage: boolean; // Manage.
|
|
|
|
favourite: boolean; // Favourite.
|
|
|
|
};
|
|
|
|
urls: {
|
|
|
|
view: string; // View.
|
|
|
|
viewlatest?: string; // Viewlatest.
|
|
|
|
viewfirstunread?: string; // Viewfirstunread.
|
|
|
|
markasread: string; // Markasread.
|
|
|
|
subscribe: string; // Subscribe.
|
|
|
|
pin?: string; // Pin.
|
|
|
|
};
|
|
|
|
timed: {
|
|
|
|
istimed?: boolean; // Istimed.
|
|
|
|
visible?: boolean; // Visible.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_toggle_favourite_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumToggleFavouriteStateWSParams = {
|
|
|
|
discussionid: number; // The discussion to subscribe or unsubscribe.
|
|
|
|
targetstate: boolean; // The target state.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_toggle_favourite_state WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumToggleFavouriteStateWSResponse = {
|
|
|
|
id: number; // Id.
|
|
|
|
forumid: number; // Forumid.
|
|
|
|
pinned: boolean; // Pinned.
|
|
|
|
locked: boolean; // Locked.
|
|
|
|
istimelocked: boolean; // Istimelocked.
|
|
|
|
name: string; // Name.
|
|
|
|
firstpostid: number; // Firstpostid.
|
|
|
|
group?: {
|
|
|
|
name: string; // Name.
|
|
|
|
urls: {
|
|
|
|
picture?: string; // Picture.
|
|
|
|
userlist?: string; // Userlist.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
times: {
|
|
|
|
modified: number; // Modified.
|
|
|
|
start: number; // Start.
|
|
|
|
end: number; // End.
|
|
|
|
locked: number; // Locked.
|
|
|
|
};
|
|
|
|
userstate: {
|
|
|
|
subscribed: boolean; // Subscribed.
|
|
|
|
favourited: boolean; // Favourited.
|
|
|
|
};
|
|
|
|
capabilities: {
|
|
|
|
subscribe: boolean; // Subscribe.
|
|
|
|
move: boolean; // Move.
|
|
|
|
pin: boolean; // Pin.
|
|
|
|
post: boolean; // Post.
|
|
|
|
manage: boolean; // Manage.
|
|
|
|
favourite: boolean; // Favourite.
|
|
|
|
};
|
|
|
|
urls: {
|
|
|
|
view: string; // View.
|
|
|
|
viewlatest?: string; // Viewlatest.
|
|
|
|
viewfirstunread?: string; // Viewfirstunread.
|
|
|
|
markasread: string; // Markasread.
|
|
|
|
subscribe: string; // Subscribe.
|
|
|
|
pin?: string; // Pin.
|
|
|
|
};
|
|
|
|
timed: {
|
|
|
|
istimed?: boolean; // Istimed.
|
|
|
|
visible?: boolean; // Visible.
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Params of mod_forum_update_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumUpdateDiscussionPostWSParams = {
|
|
|
|
postid: number; // Post to be updated. It can be a discussion topic post.
|
|
|
|
subject?: string; // Updated post subject.
|
|
|
|
message?: string; // Updated post message (HTML assumed if messageformat is not provided).
|
|
|
|
messageformat?: number; // Message format (1 = HTML, 0 = MOODLE, 2 = PLAIN or 4 = MARKDOWN).
|
|
|
|
options?: AddonModForumUpdateDiscussionPostWSOptionsArray; // Configuration options for the post.
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data returned by mod_forum_update_discussion_post WS.
|
|
|
|
*/
|
|
|
|
export type AddonModForumUpdateDiscussionPostWSResponse = CoreStatusWithWarningsWSResponse;
|
2021-03-01 13:40:17 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Data passed to NEW_DISCUSSION_EVENT event.
|
|
|
|
*/
|
|
|
|
export type AddonModForumNewDiscussionData = {
|
|
|
|
forumId: number;
|
|
|
|
cmId: number;
|
|
|
|
discussionIds?: number[] | null;
|
|
|
|
discTimecreated?: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data passed to REPLY_DISCUSSION_EVENT event.
|
|
|
|
*/
|
|
|
|
export type AddonModForumReplyDiscussionData = {
|
|
|
|
forumId: number;
|
|
|
|
discussionId: number;
|
|
|
|
cmId: number;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data passed to CHANGE_DISCUSSION_EVENT event.
|
|
|
|
*/
|
|
|
|
export type AddonModForumChangeDiscussionData = {
|
|
|
|
forumId: number;
|
|
|
|
discussionId: number;
|
|
|
|
cmId: number;
|
|
|
|
deleted?: boolean;
|
|
|
|
post?: AddonModForumPost;
|
|
|
|
locked?: boolean;
|
|
|
|
pinned?: boolean;
|
|
|
|
starred?: boolean;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Data passed to MARK_READ_EVENT event.
|
|
|
|
*/
|
|
|
|
export type AddonModForumMarkReadData = {
|
|
|
|
courseId: number;
|
|
|
|
moduleId: number;
|
|
|
|
};
|