Merge pull request #1887 from albertgasset/MOBILE-2988
MOBILE-2988 forum: Add the ability to lock discussions manuallymain
commit
561dd1d4f8
|
@ -494,11 +494,13 @@
|
|||
"addon.mod_forum.errorgetgroups": "local_moodlemobileapp",
|
||||
"addon.mod_forum.forumnodiscussionsyet": "local_moodlemobileapp",
|
||||
"addon.mod_forum.group": "local_moodlemobileapp",
|
||||
"addon.mod_forum.locked": "forum",
|
||||
"addon.mod_forum.message": "forum",
|
||||
"addon.mod_forum.modeflatnewestfirst": "forum",
|
||||
"addon.mod_forum.modeflatoldestfirst": "forum",
|
||||
"addon.mod_forum.modenested": "forum",
|
||||
"addon.mod_forum.modulenameplural": "forum",
|
||||
"addon.mod_forum.notlocked": "forum",
|
||||
"addon.mod_forum.numdiscussions": "local_moodlemobileapp",
|
||||
"addon.mod_forum.numreplies": "local_moodlemobileapp",
|
||||
"addon.mod_forum.postisprivatereply": "forum",
|
||||
|
|
|
@ -58,6 +58,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
protected replyObserver: any;
|
||||
protected newDiscObserver: any;
|
||||
protected viewDiscObserver: any;
|
||||
protected changeDiscObserver: any;
|
||||
|
||||
hasOfflineRatings: boolean;
|
||||
protected ratingOfflineObserver: any;
|
||||
|
@ -94,6 +95,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
this.eventReceived.bind(this, true));
|
||||
this.replyObserver = this.eventsProvider.on(AddonModForumProvider.REPLY_DISCUSSION_EVENT,
|
||||
this.eventReceived.bind(this, false));
|
||||
this.changeDiscObserver = this.eventsProvider.on(AddonModForumProvider.CHANGE_DISCUSSION_EVENT,
|
||||
this.eventReceived.bind(this, false));
|
||||
|
||||
// Select the current opened discussion.
|
||||
this.viewDiscObserver = this.eventsProvider.on(AddonModForumProvider.VIEW_DISCUSSION_EVENT, (data) => {
|
||||
|
@ -446,9 +449,8 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
courseId: this.courseId,
|
||||
cmId: this.module.id,
|
||||
forumId: this.forum.id,
|
||||
discussionId: discussion.discussion,
|
||||
discussion: discussion,
|
||||
trackPosts: this.trackPosts,
|
||||
locked: discussion.locked
|
||||
};
|
||||
this.splitviewCtrl.push('AddonModForumDiscussionPage', params);
|
||||
}
|
||||
|
@ -480,6 +482,7 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
|
|||
this.newDiscObserver && this.newDiscObserver.off();
|
||||
this.replyObserver && this.replyObserver.off();
|
||||
this.viewDiscObserver && this.viewDiscObserver.off();
|
||||
this.changeDiscObserver && this.changeDiscObserver.off();
|
||||
this.ratingOfflineObserver && this.ratingOfflineObserver.off();
|
||||
this.ratingSyncObserver && this.ratingSyncObserver.off();
|
||||
}
|
||||
|
|
|
@ -18,11 +18,13 @@
|
|||
"errorgetgroups": "Error getting group settings.",
|
||||
"forumnodiscussionsyet": "There are no discussions yet in this forum.",
|
||||
"group": "Group",
|
||||
"locked": "Locked",
|
||||
"message": "Message",
|
||||
"modeflatnewestfirst": "Display replies flat, with newest first",
|
||||
"modeflatoldestfirst": "Display replies flat, with oldest first",
|
||||
"modenested": "Display replies in nested form",
|
||||
"modulenameplural": "Forums",
|
||||
"notlocked": "Lock",
|
||||
"numdiscussions": "{{numdiscussions}} discussions",
|
||||
"numreplies": "{{numreplies}} replies",
|
||||
"postisprivatereply": "This post was made privately and is not visible to all users.",
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
<core-context-menu-item [hidden]="sort == 'flat-oldest'" [priority]="500" [content]="'addon.mod_forum.modeflatoldestfirst' | translate" (action)="changeSort('flat-oldest')" iconAction="arrow-round-down"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="sort == 'flat-newest'" [priority]="450" [content]="'addon.mod_forum.modeflatnewestfirst' | translate" (action)="changeSort('flat-newest')" iconAction="arrow-round-up"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="sort == 'nested'" [priority]="400" [content]="'addon.mod_forum.modenested' | translate" (action)="changeSort('nested')" iconAction="swap"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!discussion || !discussion.canlock || discussion.locked" [priority]="300" [content]="'addon.mod_forum.notlocked' | translate" (action)="setLockState(true)" iconAction="fa-unlock"></core-context-menu-item>
|
||||
<core-context-menu-item [hidden]="!discussion || !discussion.canlock || !discussion.locked" [priority]="300" [content]="'addon.mod_forum.locked' | translate" (action)="setLockState(false)" iconAction="fa-lock"></core-context-menu-item>
|
||||
</core-context-menu>
|
||||
</core-navbar-buttons>
|
||||
<ion-content>
|
||||
|
@ -26,7 +28,7 @@
|
|||
<ion-icon name="warning"></ion-icon> {{ 'core.hasdatatosync' | translate:{$a: discussionStr} }}
|
||||
</ion-card>
|
||||
|
||||
<ion-card class="core-warning-card" *ngIf="locked">
|
||||
<ion-card class="core-warning-card" *ngIf="discussion && discussion.locked">
|
||||
<ion-icon name="warning"></ion-icon> {{ 'addon.mod_forum.discussionlocked' | translate }}
|
||||
</ion-card>
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
defaultSubject: string;
|
||||
isOnline: boolean;
|
||||
isSplitViewOn: boolean;
|
||||
locked: boolean;
|
||||
postHasOffline: boolean;
|
||||
sort: SortType = 'flat-oldest';
|
||||
trackPosts: boolean;
|
||||
|
@ -108,9 +107,9 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
this.courseId = navParams.get('courseId');
|
||||
this.cmId = navParams.get('cmId');
|
||||
this.forumId = navParams.get('forumId');
|
||||
this.discussionId = navParams.get('discussionId');
|
||||
this.discussion = navParams.get('discussion');
|
||||
this.discussionId = this.discussion ? this.discussion.discussion : navParams.get('discussionId');
|
||||
this.trackPosts = navParams.get('trackPosts');
|
||||
this.locked = navParams.get('locked');
|
||||
this.postId = navParams.get('postId');
|
||||
|
||||
this.isOnline = this.appProvider.isOnline();
|
||||
|
@ -222,7 +221,7 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
}
|
||||
|
||||
/**
|
||||
* Convenience function to get forum discussions.
|
||||
* Convenience function to get the posts.
|
||||
*
|
||||
* @param {boolean} [sync] Whether to try to synchronize the discussion.
|
||||
* @param {boolean} [showErrors] Whether to show errors in a modal.
|
||||
|
@ -243,11 +242,12 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
let onlinePosts = [];
|
||||
const offlineReplies = [];
|
||||
let hasUnreadPosts = false;
|
||||
let ratingInfo;
|
||||
|
||||
return syncPromise.then(() => {
|
||||
return this.forumProvider.getDiscussionPosts(this.discussionId).then((response) => {
|
||||
onlinePosts = response.posts;
|
||||
this.ratingInfo = response.ratinginfo;
|
||||
ratingInfo = response.ratinginfo;
|
||||
}).then(() => {
|
||||
// Check if there are responses stored in offline.
|
||||
return this.forumOffline.getDiscussionReplies(this.discussionId).then((replies) => {
|
||||
|
@ -285,34 +285,23 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
});
|
||||
});
|
||||
}).then(() => {
|
||||
const posts = offlineReplies.concat(onlinePosts);
|
||||
this.discussion = this.forumProvider.extractStartingPost(posts);
|
||||
|
||||
if (!this.discussion) {
|
||||
return Promise.reject('Invalid forum discussion');
|
||||
}
|
||||
let posts = offlineReplies.concat(onlinePosts);
|
||||
|
||||
// If sort type is nested, normal sorting is disabled and nested posts will be displayed.
|
||||
if (this.sort == 'nested') {
|
||||
// Sort first by creation date to make format tree work.
|
||||
this.forumProvider.sortDiscussionPosts(posts, 'ASC');
|
||||
this.posts = this.utils.formatTree(posts, 'parent', 'id', this.discussion.id);
|
||||
posts = this.utils.formatTree(posts, 'parent', 'id', this.discussion.id);
|
||||
} else {
|
||||
// Set default reply subject.
|
||||
const direction = this.sort == 'flat-newest' ? 'DESC' : 'ASC';
|
||||
this.forumProvider.sortDiscussionPosts(posts, direction);
|
||||
this.posts = posts;
|
||||
}
|
||||
this.defaultSubject = this.translate.instant('addon.mod_forum.re') + ' ' + this.discussion.subject;
|
||||
this.replyData.subject = this.defaultSubject;
|
||||
|
||||
// Now try to get the forum.
|
||||
return this.fetchForum().then((forum) => {
|
||||
if (this.discussion.userfullname && this.discussion.parent == 0 && forum.type == 'single') {
|
||||
// Hide author for first post and type single.
|
||||
this.discussion.userfullname = null;
|
||||
}
|
||||
|
||||
// "forum.istracked" is more reliable than "trackPosts".
|
||||
if (typeof forum.istracked != 'undefined') {
|
||||
this.trackPosts = forum.istracked;
|
||||
|
@ -321,14 +310,44 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
this.forumId = forum.id;
|
||||
this.cmId = forum.cmid;
|
||||
this.forum = forum;
|
||||
}).then(() => {
|
||||
return this.forumProvider.getAccessInformation(this.forum.id).then((accessInfo) => {
|
||||
|
||||
const promises = [];
|
||||
|
||||
promises.push(this.forumProvider.getAccessInformation(this.forum.id).then((accessInfo) => {
|
||||
this.accessInfo = accessInfo;
|
||||
});
|
||||
}));
|
||||
|
||||
// Fetch the discussion if not passed as parameter.
|
||||
if (!this.discussion) {
|
||||
promises.push(this.forumHelper.getDiscussionById(forum.id, this.discussionId).then((discussion) => {
|
||||
this.discussion = discussion;
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
}));
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
}).catch(() => {
|
||||
// Ignore errors.
|
||||
this.forum = {};
|
||||
this.accessInfo = {};
|
||||
}).then(() => {
|
||||
const startingPost = this.forumProvider.extractStartingPost(posts);
|
||||
if (startingPost) {
|
||||
// Update discussion data from first post.
|
||||
this.discussion = Object.assign(this.discussion || {}, startingPost);
|
||||
} else if (!this.discussion) {
|
||||
// The discussion object was not passed as parameter and there is no starting post.
|
||||
return Promise.reject('Invalid forum discussion.');
|
||||
}
|
||||
|
||||
if (this.discussion.userfullname && this.discussion.parent == 0 && this.forum.type == 'single') {
|
||||
// Hide author for first post and type single.
|
||||
this.discussion.userfullname = null;
|
||||
}
|
||||
|
||||
this.posts = posts;
|
||||
this.ratingInfo = ratingInfo;
|
||||
});
|
||||
}).then(() => {
|
||||
return this.ratingOffline.hasRatings('mod_forum', 'post', 'module', this.cmId, this.discussionId).then((hasRatings) => {
|
||||
|
@ -454,6 +473,31 @@ export class AddonModForumDiscussionPage implements OnDestroy {
|
|||
return this.fetchPosts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock or unlock the discussion.
|
||||
*
|
||||
* @param {boolean} locked True to lock the discussion, false to unlock.
|
||||
*/
|
||||
setLockState(locked: boolean): void {
|
||||
const modal = this.domUtils.showModalLoading('core.sending', true);
|
||||
|
||||
this.forumProvider.setLockState(this.forumId, this.discussionId, locked).then((response) => {
|
||||
this.discussion.locked = response.locked;
|
||||
|
||||
const data = {
|
||||
forumId: this.forumId,
|
||||
discussionId: this.discussionId,
|
||||
cmId: this.cmId,
|
||||
locked: this.discussion.locked
|
||||
};
|
||||
this.eventsProvider.trigger(AddonModForumProvider.CHANGE_DISCUSSION_EVENT, data, this.sitesProvider.getCurrentSiteId());
|
||||
}).catch((error) => {
|
||||
this.domUtils.showErrorModal(error);
|
||||
}).finally(() => {
|
||||
modal.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* New post added.
|
||||
*/
|
||||
|
|
|
@ -34,6 +34,7 @@ export class AddonModForumProvider {
|
|||
static NEW_DISCUSSION_EVENT = 'addon_mod_forum_new_discussion';
|
||||
static REPLY_DISCUSSION_EVENT = 'addon_mod_forum_reply_discussion';
|
||||
static VIEW_DISCUSSION_EVENT = 'addon_mod_forum_view_discussion';
|
||||
static CHANGE_DISCUSSION_EVENT = 'addon_mod_forum_lock_discussion';
|
||||
static MARK_READ_EVENT = 'addon_mod_forum_mark_read';
|
||||
|
||||
protected ROOT_CACHE_KEY = 'mmaModForum:';
|
||||
|
@ -761,6 +762,28 @@ export class AddonModForumProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock or unlock a discussion.
|
||||
*
|
||||
* @param {number} forumId Forum id.
|
||||
* @param {number} discussionId DIscussion id.
|
||||
* @param {boolean} locked True to lock, false to unlock.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resvoled when done.
|
||||
* @since 3.7
|
||||
*/
|
||||
setLockState(forumId: number, discussionId: number, locked: boolean, siteId?: string): Promise<any> {
|
||||
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||
const params = {
|
||||
forumid: forumId,
|
||||
discussionid: discussionId,
|
||||
targetstate: locked ? 0 : 1
|
||||
};
|
||||
|
||||
return site.write('mod_forum_set_lock_state', params);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the users data from a discussions/posts list.
|
||||
*
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
import { CoreFileProvider } from '@providers/file';
|
||||
import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader';
|
||||
import { CoreSitesProvider } from '@providers/sites';
|
||||
import { CoreUserProvider } from '@core/user/providers/user';
|
||||
import { AddonModForumProvider } from './forum';
|
||||
import { AddonModForumOfflineProvider } from './offline';
|
||||
|
@ -25,8 +26,10 @@ import { AddonModForumOfflineProvider } from './offline';
|
|||
@Injectable()
|
||||
export class AddonModForumHelperProvider {
|
||||
constructor(private fileProvider: CoreFileProvider,
|
||||
private sitesProvider: CoreSitesProvider,
|
||||
private uploaderProvider: CoreFileUploaderProvider,
|
||||
private userProvider: CoreUserProvider,
|
||||
private forumProvider: AddonModForumProvider,
|
||||
private forumOffline: AddonModForumOfflineProvider) {}
|
||||
|
||||
/**
|
||||
|
@ -119,6 +122,38 @@ export class AddonModForumHelperProvider {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a forum discussion by id.
|
||||
*
|
||||
* This function is inefficient because it needs to fetch all discussion pages in the worst case.
|
||||
*
|
||||
* @param {number} forumId Forum ID.
|
||||
* @param {number} discussionId Discussion ID.
|
||||
* @param {string} [siteId] Site ID. If not defined, current site.
|
||||
* @return {Promise<any>} Promise resolved with the discussion data.
|
||||
*/
|
||||
getDiscussionById(forumId: number, discussionId: number, siteId?: string): Promise<any> {
|
||||
siteId = siteId || this.sitesProvider.getCurrentSiteId();
|
||||
|
||||
const findDiscussion = (page: number): Promise<any> => {
|
||||
return this.forumProvider.getDiscussions(forumId, page, false, siteId).then((response) => {
|
||||
if (response.discussions && response.discussions.length > 0) {
|
||||
const discussion = response.discussions.find((discussion) => discussion.id == discussionId);
|
||||
if (discussion) {
|
||||
return discussion;
|
||||
}
|
||||
if (response.canLoadMore) {
|
||||
return findDiscussion(page + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.reject(null);
|
||||
});
|
||||
};
|
||||
|
||||
return findDiscussion(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of stored attachment files for a new discussion. See AddonModForumHelper#storeNewDiscussionFiles.
|
||||
*
|
||||
|
|
|
@ -494,11 +494,13 @@
|
|||
"addon.mod_forum.errorgetgroups": "Error getting group settings.",
|
||||
"addon.mod_forum.forumnodiscussionsyet": "There are no discussions yet in this forum.",
|
||||
"addon.mod_forum.group": "Group",
|
||||
"addon.mod_forum.locked": "Locked",
|
||||
"addon.mod_forum.message": "Message",
|
||||
"addon.mod_forum.modeflatnewestfirst": "Display replies flat, with newest first",
|
||||
"addon.mod_forum.modeflatoldestfirst": "Display replies flat, with oldest first",
|
||||
"addon.mod_forum.modenested": "Display replies in nested form",
|
||||
"addon.mod_forum.modulenameplural": "Forums",
|
||||
"addon.mod_forum.notlocked": "Lock",
|
||||
"addon.mod_forum.numdiscussions": "{{numdiscussions}} discussions",
|
||||
"addon.mod_forum.numreplies": "{{numreplies}} replies",
|
||||
"addon.mod_forum.postisprivatereply": "This post was made privately and is not visible to all users.",
|
||||
|
|
Loading…
Reference in New Issue