From e25306b0b2fb2a4af672377b9185719fa3df689a Mon Sep 17 00:00:00 2001 From: Albert Gasset Date: Thu, 16 May 2019 15:04:45 +0200 Subject: [PATCH] MOBILE-3018 forum: Post a copy to all groups --- scripts/langindex.json | 3 + .../index/addon-mod-forum-index.html | 4 +- src/addon/mod/forum/lang/en.json | 2 + .../pages/new-discussion/new-discussion.html | 6 +- .../pages/new-discussion/new-discussion.ts | 95 +++++++------- src/addon/mod/forum/providers/forum.ts | 67 ++-------- src/addon/mod/forum/providers/helper.ts | 116 ++++++++++++++++++ src/addon/mod/forum/providers/offline.ts | 3 +- src/addon/mod/forum/providers/sync.ts | 69 +++++++---- src/assets/lang/en.json | 3 + src/lang/en.json | 1 + 11 files changed, 235 insertions(+), 134 deletions(-) diff --git a/scripts/langindex.json b/scripts/langindex.json index 53faeef0b..76f5cc4a8 100644 --- a/scripts/langindex.json +++ b/scripts/langindex.json @@ -503,6 +503,7 @@ "addon.mod_forum.erroremptysubject": "forum", "addon.mod_forum.errorgetforum": "local_moodlemobileapp", "addon.mod_forum.errorgetgroups": "local_moodlemobileapp", + "addon.mod_forum.errorposttoallgroups": "local_moodlemobileapp", "addon.mod_forum.favouriteupdated": "forum", "addon.mod_forum.forumnodiscussionsyet": "local_moodlemobileapp", "addon.mod_forum.group": "local_moodlemobileapp", @@ -520,6 +521,7 @@ "addon.mod_forum.pinupdated": "forum", "addon.mod_forum.postisprivatereply": "forum", "addon.mod_forum.posttoforum": "forum", + "addon.mod_forum.posttomygroups": "forum", "addon.mod_forum.privatereply": "forum", "addon.mod_forum.re": "forum", "addon.mod_forum.refreshdiscussions": "local_moodlemobileapp", @@ -1219,6 +1221,7 @@ "core.agelocationverification": "moodle", "core.ago": "message", "core.all": "moodle", + "core.allgroups": "moodle", "core.allparticipants": "moodle", "core.android": "local_moodlemobileapp", "core.answer": "moodle", diff --git a/src/addon/mod/forum/components/index/addon-mod-forum-index.html b/src/addon/mod/forum/components/index/addon-mod-forum-index.html index bc35c9d06..0aecbb757 100644 --- a/src/addon/mod/forum/components/index/addon-mod-forum-index.html +++ b/src/addon/mod/forum/components/index/addon-mod-forum-index.html @@ -31,7 +31,7 @@ {{ availabilityMessage }} - +
@@ -41,7 +41,7 @@
- + diff --git a/src/addon/mod/forum/lang/en.json b/src/addon/mod/forum/lang/en.json index 5b2935e89..8cabc5750 100644 --- a/src/addon/mod/forum/lang/en.json +++ b/src/addon/mod/forum/lang/en.json @@ -24,6 +24,7 @@ "erroremptysubject": "Post subject cannot be empty.", "errorgetforum": "Error getting forum data.", "errorgetgroups": "Error getting group settings.", + "errorposttoallgroups": "Could not create new discussion in all groups.", "favouriteupdated": "Your star option has been updated.", "forumnodiscussionsyet": "There are no discussions yet in this forum.", "group": "Group", @@ -41,6 +42,7 @@ "pinupdated": "The pin option has been updated.", "postisprivatereply": "This post was made privately and is not visible to all users.", "posttoforum": "Post to forum", + "posttomygroups": "Post a copy to all groups", "privatereply": "Reply privately", "re": "Re:", "refreshdiscussions": "Refresh discussions", diff --git a/src/addon/mod/forum/pages/new-discussion/new-discussion.html b/src/addon/mod/forum/pages/new-discussion/new-discussion.html index 236b8bcef..95bb6e5ce 100644 --- a/src/addon/mod/forum/pages/new-discussion/new-discussion.html +++ b/src/addon/mod/forum/pages/new-discussion/new-discussion.html @@ -27,9 +27,13 @@ {{ 'addon.mod_forum.advanced' | translate }} + + {{ 'addon.mod_forum.posttomygroups' | translate }} + + {{ 'addon.mod_forum.group' | translate }} - + {{ group.name }} diff --git a/src/addon/mod/forum/pages/new-discussion/new-discussion.ts b/src/addon/mod/forum/pages/new-discussion/new-discussion.ts index aaad29946..be2fb7383 100644 --- a/src/addon/mod/forum/pages/new-discussion/new-discussion.ts +++ b/src/addon/mod/forum/pages/new-discussion/new-discussion.ts @@ -53,15 +53,18 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { forum: any; showForm = false; groups = []; + groupIds = []; newDiscussion = { subject: '', message: null, // Null means empty or just white space. + postToAllGroups: false, groupId: 0, subscribe: true, pin: false, files: [] }; advanced = false; // Display all form fields. + accessInfo: any = {}; protected courseId: number; protected cmId: number; @@ -146,9 +149,13 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { return promise.then((forumGroups) => { if (forumGroups.length > 0) { this.groups = forumGroups; + this.groupIds = forumGroups.map((group) => group.id).filter((id) => id > 0); // Do not override group id. this.newDiscussion.groupId = this.newDiscussion.groupId || forumGroups[0].id; this.showGroups = true; + if (this.groupIds.length <= 1) { + this.newDiscussion.postToAllGroups = false; + } } else { const message = mode === CoreGroupsProvider.SEPARATEGROUPS ? 'addon.mod_forum.cannotadddiscussionall' : 'addon.mod_forum.cannotadddiscussion'; @@ -159,6 +166,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { })); } else { this.showGroups = false; + this.newDiscussion.postToAllGroups = false; // Use the canAddDiscussion WS to check if the user can add attachments and pin discussions. promises.push(this.forumProvider.canAddDiscussionToAll(this.forumId).then((response) => { @@ -174,10 +182,18 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { this.forum = forum; })); + // Get access information. + promises.push(this.forumProvider.getAccessInformation(this.forumId).then((accessInfo) => { + this.accessInfo = accessInfo; + })); + + return Promise.all(promises); + }).then(() => { // If editing a discussion, get offline data. if (this.timeCreated && !refresh) { this.syncId = this.forumSync.getForumSyncId(this.forumId); - promises.push(this.forumSync.waitForSync(this.syncId).then(() => { + + return this.forumSync.waitForSync(this.syncId).then(() => { // Do not block if the scope is already destroyed. if (!this.isDestroyed) { this.syncProvider.blockOperation(AddonModForumProvider.COMPONENT, this.syncId); @@ -186,7 +202,13 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { return this.forumOffline.getNewDiscussion(this.forumId, this.timeCreated).then((discussion) => { this.hasOffline = true; discussion.options = discussion.options || {}; - this.newDiscussion.groupId = discussion.groupid ? discussion.groupid : this.newDiscussion.groupId; + if (discussion.groupid == AddonModForumProvider.ALL_GROUPS) { + this.newDiscussion.groupId = this.groups[0].id; + this.newDiscussion.postToAllGroups = true; + } else { + this.newDiscussion.groupId = discussion.groupid; + this.newDiscussion.postToAllGroups = false; + } this.newDiscussion.subject = discussion.subject; this.newDiscussion.message = discussion.message; this.newDiscussion.subscribe = discussion.options.discussionsubscribe; @@ -203,15 +225,15 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { return Promise.resolve(promise).then(() => { // Show advanced fields by default if any of them has not the default value. - if (!this.newDiscussion.subscribe || this.newDiscussion.pin || this.newDiscussion.files.length) { + if (!this.newDiscussion.subscribe || this.newDiscussion.pin || this.newDiscussion.files.length || + this.groups.length > 0 && this.newDiscussion.groupId != this.groups[0].id || + this.newDiscussion.postToAllGroups) { this.advanced = true; } }); }); - })); + }); } - - return Promise.all(promises); }).then(() => { if (!this.originalData) { // Initialize original data. @@ -232,9 +254,9 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { * Validate which of the groups returned by getActivityAllowedGroups in visible groups should be shown to post to. * * @param {any[]} forumGroups Forum groups. - * @return {Promise} Promise resolved when done. + * @return {Promise} Promise resolved with the list of groups. */ - protected validateVisibleGroups(forumGroups: any[]): Promise { + protected validateVisibleGroups(forumGroups: any[]): Promise { // We first check if the user can post to all the groups. return this.forumProvider.canAddDiscussionToAll(this.forumId).catch(() => { // The call failed, let's assume he can't. @@ -331,7 +353,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { if (canAdd) { groups.unshift({ courseid: this.courseId, - id: -1, + id: AddonModForumProvider.ALL_PARTICIPANTS, name: this.translate.instant('core.allparticipants') }); } @@ -362,14 +384,14 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { /** * Convenience function to update or return to discussions depending on device. * - * @param {number} [discussionId] Id of the new discussion. + * @param {number} [discussionIds] Ids of the new discussions. * @param {number} [discTimecreated] The time created of the discussion (if offline). */ - protected returnToDiscussions(discussionId?: number, discTimecreated?: number): void { + protected returnToDiscussions(discussionIds?: number[], discTimecreated?: number): void { const data: any = { forumId: this.forumId, cmId: this.cmId, - discussionId: discussionId, + discussionIds: discussionIds, discTimecreated: discTimecreated }; this.eventsProvider.trigger(AddonModForumProvider.NEW_DISCUSSION_EVENT, data, this.sitesProvider.getCurrentSiteId()); @@ -383,6 +405,7 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { this.newDiscussion.subject = ''; this.newDiscussion.message = null; this.newDiscussion.files = []; + this.newDiscussion.postToAllGroups = false; this.messageEditor.clearText(); this.originalData = this.utils.clone(this.newDiscussion); @@ -414,13 +437,11 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { const subject = this.newDiscussion.subject; let message = this.newDiscussion.message; const pin = this.newDiscussion.pin; - const groupId = this.newDiscussion.groupId; const attachments = this.newDiscussion.files; const discTimecreated = this.timeCreated || Date.now(); const options: any = { discussionsubscribe: !!this.newDiscussion.subscribe }; - let saveOffline = false; if (!subject) { this.domUtils.showErrorModal('addon.mod_forum.erroremptysubject', true); @@ -434,51 +455,29 @@ export class AddonModForumNewDiscussionPage implements OnDestroy { } const modal = this.domUtils.showModalLoading('core.sending', true); - let promise; // Add some HTML to the message if needed. message = this.textUtils.formatHtmlLines(message); - // Upload attachments first if any. - if (attachments.length) { - promise = this.forumHelper.uploadOrStoreNewDiscussionFiles(this.forumId, discTimecreated, attachments, false) - .catch(() => { - // Cannot upload them in online, save them in offline. - saveOffline = true; - - return this.forumHelper.uploadOrStoreNewDiscussionFiles(this.forumId, discTimecreated, attachments, true); - }); - } else { - promise = Promise.resolve(); + if (pin) { + options.discussionpinned = true; } - promise.then((attach) => { - if (attach) { - options.attachmentsid = attach; - } - if (pin) { - options.discussionpinned = true; - } + const groupIds = this.newDiscussion.postToAllGroups ? this.groupIds : [this.newDiscussion.groupId]; - if (saveOffline) { - // Save discussion in offline. - return this.forumOffline.addNewDiscussion(this.forumId, forumName, this.courseId, subject, - message, options, groupId, discTimecreated).then(() => { - // Don't return anything. - }); - } else { - // Try to send it to server. - // Don't allow offline if there are attachments since they were uploaded fine. - return this.forumProvider.addNewDiscussion(this.forumId, forumName, this.courseId, subject, message, options, - groupId, undefined, discTimecreated, !attachments.length); - } - }).then((discussionId) => { - if (discussionId) { + this.forumHelper.addNewDiscussion(this.forumId, forumName, this.courseId, subject, message, attachments, options, groupIds, + discTimecreated).then((discussionIds) => { + if (discussionIds) { // Data sent to server, delete stored files (if any). this.forumHelper.deleteNewDiscussionStoredFiles(this.forumId, discTimecreated); } - this.returnToDiscussions(discussionId, discTimecreated); + if (discussionIds && discussionIds.length < groupIds.length) { + // Some discussions could not be created. + this.domUtils.showErrorModalDefault(null, 'addon.mod_forum.errorposttoallgroups', true); + } + + this.returnToDiscussions(discussionIds, discTimecreated); }).catch((message) => { this.domUtils.showErrorModalDefault(message, 'addon.mod_forum.cannotcreatediscussion', true); }).finally(() => { diff --git a/src/addon/mod/forum/providers/forum.ts b/src/addon/mod/forum/providers/forum.ts index 0f6683e11..8bdb7bffa 100644 --- a/src/addon/mod/forum/providers/forum.ts +++ b/src/addon/mod/forum/providers/forum.ts @@ -46,6 +46,9 @@ export class AddonModForumProvider { static SORTORDER_REPLIES_DESC = 5; static SORTORDER_REPLIES_ASC = 6; + static ALL_PARTICIPANTS = -1; + static ALL_GROUPS = -2; + protected ROOT_CACHE_KEY = 'mmaModForum:'; constructor(private appProvider: CoreAppProvider, @@ -126,62 +129,6 @@ export class AddonModForumProvider { return key; } - /** - * Add a new discussion. - * - * @param {number} forumId Forum ID. - * @param {string} name Forum name. - * @param {number} courseId Course ID the forum belongs to. - * @param {string} subject New discussion's subject. - * @param {string} message New discussion's message. - * @param {any} [options] Options (subscribe, pin, ...). - * @param {string} [groupId] Group this discussion belongs to. - * @param {string} [siteId] Site ID. If not defined, current site. - * @param {number} [timeCreated] The time the discussion was created. Only used when editing discussion. - * @param {boolean} allowOffline True if it can be stored in offline, false otherwise. - * @return {Promise} Promise resolved with discussion ID if sent online, resolved with false if stored offline. - */ - addNewDiscussion(forumId: number, name: string, courseId: number, subject: string, message: string, options?: any, - groupId?: number, siteId?: string, timeCreated?: number, allowOffline?: boolean): Promise { - siteId = siteId || this.sitesProvider.getCurrentSiteId(); - - // Convenience function to store a message to be synchronized later. - const storeOffline = (): Promise => { - return this.forumOffline.addNewDiscussion(forumId, name, courseId, subject, message, options, - groupId, timeCreated, siteId).then(() => { - return false; - }); - }; - - // If we are editing an offline discussion, discard previous first. - let discardPromise; - if (timeCreated) { - discardPromise = this.forumOffline.deleteNewDiscussion(forumId, timeCreated, siteId); - } else { - discardPromise = Promise.resolve(); - } - - return discardPromise.then(() => { - if (!this.appProvider.isOnline() && allowOffline) { - // App is offline, store the action. - return storeOffline(); - } - - return this.addNewDiscussionOnline(forumId, subject, message, options, groupId, siteId).then((id) => { - // Success, return the discussion ID. - return id; - }).catch((error) => { - if (!allowOffline || this.utils.isWebServiceError(error)) { - // The WebService has thrown an error or offline not supported, reject. - return Promise.reject(error); - } - - // Couldn't connect to server, store in offline. - return storeOffline(); - }); - }); - } - /** * Add a new discussion. It will fail if offline or cannot connect. * @@ -268,7 +215,7 @@ export class AddonModForumProvider { * - cancreateattachment (boolean) */ canAddDiscussionToAll(forumId: number): Promise { - return this.canAddDiscussion(forumId, -1); + return this.canAddDiscussion(forumId, AddonModForumProvider.ALL_PARTICIPANTS); } /** @@ -309,6 +256,7 @@ export class AddonModForumProvider { return this.groupsProvider.getActivityAllowedGroups(cmId).then((forumGroups) => { const strAllParts = this.translate.instant('core.allparticipants'); + const strAllGroups = this.translate.instant('core.allgroups'); // Turn groups into an object where each group is identified by id. const groups = {}; @@ -318,8 +266,11 @@ export class AddonModForumProvider { // Format discussions. discussions.forEach((disc) => { - if (disc.groupid === -1) { + 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) { diff --git a/src/addon/mod/forum/providers/helper.ts b/src/addon/mod/forum/providers/helper.ts index 5c568c911..fb46fab35 100644 --- a/src/addon/mod/forum/providers/helper.ts +++ b/src/addon/mod/forum/providers/helper.ts @@ -14,10 +14,12 @@ import { Injectable } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; +import { CoreAppProvider } from '@providers/app'; import { CoreFileProvider } from '@providers/file'; import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploader'; import { CoreSitesProvider } from '@providers/sites'; import { CoreTimeUtilsProvider } from '@providers/utils/time'; +import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreUserProvider } from '@core/user/providers/user'; import { AddonModForumProvider } from './forum'; import { AddonModForumOfflineProvider } from './offline'; @@ -33,9 +35,123 @@ export class AddonModForumHelperProvider { private uploaderProvider: CoreFileUploaderProvider, private timeUtils: CoreTimeUtilsProvider, private userProvider: CoreUserProvider, + private appProvider: CoreAppProvider, + private utils: CoreUtilsProvider, private forumProvider: AddonModForumProvider, private forumOffline: AddonModForumOfflineProvider) {} + /** + * Add a new discussion. + * + * @param {number} forumId Forum ID. + * @param {string} name Forum name. + * @param {number} courseId Course ID the forum belongs to. + * @param {string} subject New discussion's subject. + * @param {string} message New discussion's message. + * @param {any[]} [attachments] New discussion's attachments. + * @param {any} [options] Options (subscribe, pin, ...). + * @param {number[]} [groupIds] Groups this discussion belongs to. + * @param {number} [timeCreated] The time the discussion was created. Only used when editing discussion. + * @param {string} [siteId] Site ID. If not defined, current site. + * @return {Promise} Promise resolved with ids of the created discussions or null if stored offline + */ + addNewDiscussion(forumId: number, name: string, courseId: number, subject: string, message: string, attachments?: any[], + options?: any, groupIds?: number[], timeCreated?: number, siteId?: string): Promise { + + siteId = siteId || this.sitesProvider.getCurrentSiteId(); + groupIds = groupIds && groupIds.length > 0 ? groupIds : [0]; + + let saveOffline = false; + const attachmentsIds = []; + let offlineAttachments: any; + + // Convenience function to store a message to be synchronized later. + const storeOffline = (): Promise => { + // Multiple groups, the discussion is being posted to all groups. + const groupId = groupIds.length > 1 ? AddonModForumProvider.ALL_GROUPS : groupIds[0]; + + if (offlineAttachments) { + options.attachmentsid = offlineAttachments; + } + + return this.forumOffline.addNewDiscussion(forumId, name, courseId, subject, message, options, + groupId, timeCreated, siteId).then(() => { + return null; + }); + }; + + // First try to upload attachments, once per group. + let promise; + if (attachments && attachments.length > 0) { + const promises = groupIds.map(() => { + return this.uploadOrStoreNewDiscussionFiles(forumId, timeCreated, attachments, false).then((attach) => { + attachmentsIds.push(attach); + }); + }); + + promise = Promise.all(promises).catch(() => { + // Cannot upload them in online, save them in offline. + saveOffline = true; + + return this.uploadOrStoreNewDiscussionFiles(forumId, timeCreated, attachments, true).then((attach) => { + offlineAttachments = attach; + }); + }); + } else { + promise = Promise.resolve(); + } + + return promise.then(() => { + // If we are editing an offline discussion, discard previous first. + let discardPromise; + if (timeCreated) { + discardPromise = this.forumOffline.deleteNewDiscussion(forumId, timeCreated, siteId); + } else { + discardPromise = Promise.resolve(); + } + + return discardPromise.then(() => { + if (saveOffline || !this.appProvider.isOnline()) { + return storeOffline(); + } + + const errors = []; + const discussionIds = []; + + const promises = groupIds.map((groupId, index) => { + const grouOptions = this.utils.clone(options); + if (attachmentsIds[index]) { + grouOptions.attachmentsid = attachmentsIds[index]; + } + + return this.forumProvider.addNewDiscussionOnline(forumId, subject, message, grouOptions, groupId, siteId) + .then((discussionId) => { + discussionIds.push(discussionId); + }).catch((error) => { + errors.push(error); + }); + }); + + return Promise.all(promises).then(() => { + if (errors.length == groupIds.length) { + // All requests have failed. + for (let i = 0; i < errors.length; i++) { + if (this.utils.isWebServiceError(errors[i]) || attachments.length > 0) { + // The WebService has thrown an error or offline not supported, reject. + return Promise.reject(errors[i]); + } + } + + // Couldn't connect to server, store offline. + return storeOffline(); + } + + return discussionIds; + }); + }); + }); + } + /** * Convert offline reply to online format in order to be compatible with them. * diff --git a/src/addon/mod/forum/providers/offline.ts b/src/addon/mod/forum/providers/offline.ts index a5223f786..af6a08b11 100644 --- a/src/addon/mod/forum/providers/offline.ts +++ b/src/addon/mod/forum/providers/offline.ts @@ -16,6 +16,7 @@ import { Injectable } from '@angular/core'; import { CoreFileProvider } from '@providers/file'; import { CoreSitesProvider, CoreSiteSchema } from '@providers/sites'; import { CoreTextUtilsProvider } from '@providers/utils/text'; +import { AddonModForumProvider } from './forum'; /** * Service to handle offline forum. @@ -248,7 +249,7 @@ export class AddonModForumOfflineProvider { subject: subject, message: message, options: JSON.stringify(options || {}), - groupid: groupId || -1, + groupid: groupId || AddonModForumProvider.ALL_PARTICIPANTS, userid: userId || site.getUserId(), timecreated: timeCreated || new Date().getTime() }; diff --git a/src/addon/mod/forum/providers/sync.ts b/src/addon/mod/forum/providers/sync.ts index a829d2662..5ad34cbb6 100644 --- a/src/addon/mod/forum/providers/sync.ts +++ b/src/addon/mod/forum/providers/sync.ts @@ -21,6 +21,7 @@ import { CoreFileUploaderProvider } from '@core/fileuploader/providers/fileuploa import { CoreAppProvider } from '@providers/app'; import { CoreLoggerProvider } from '@providers/logger'; import { CoreEventsProvider } from '@providers/events'; +import { CoreGroupsProvider } from '@providers/groups'; import { CoreSitesProvider } from '@providers/sites'; import { CoreSyncProvider } from '@providers/sync'; import { CoreTextUtilsProvider } from '@providers/utils/text'; @@ -46,6 +47,7 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider { appProvider: CoreAppProvider, courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider, + private groupsProvider: CoreGroupsProvider, loggerProvider: CoreLoggerProvider, sitesProvider: CoreSitesProvider, syncProvider: CoreSyncProvider, @@ -222,38 +224,57 @@ export class AddonModForumSyncProvider extends CoreSyncBaseProvider { const promises = []; discussions.forEach((data) => { - data.options = data.options || {}; + let groupsPromise; + if (data.groupid == AddonModForumProvider.ALL_GROUPS) { + // Fetch all group ids. + groupsPromise = this.forumProvider.getForumById(data.courseid, data.forumid, siteId).then((forum) => { + return this.groupsProvider.getActivityAllowedGroups(forum.cmid).then((groups) => { + return groups.map((group) => group.id); + }); + }); + } else { + groupsPromise = Promise.resolve([data.groupid]); + } - // First of all upload the attachments (if any). - const promise = this.uploadAttachments(forumId, data, true, siteId, userId).then((itemId) => { - // Now try to add the discussion. - data.options.attachmentsid = itemId; + promises.push(groupsPromise.then((groupIds) => { + const errors = []; - return this.forumProvider.addNewDiscussionOnline(forumId, data.subject, data.message, - data.options, data.groupid, siteId); - }); + return Promise.all(groupIds.map((groupId) => { + // First of all upload the attachments (if any). + return this.uploadAttachments(forumId, data, true, siteId, userId).then((itemId) => { + // Now try to add the discussion. + const options = this.utils.clone(data.options || {}); + options.attachmentsid = itemId; - promises.push(promise.then(() => { - result.updated = true; + return this.forumProvider.addNewDiscussionOnline(forumId, data.subject, data.message, options, + groupId, siteId); + }).catch((error) => { + errors.push(error); + }); + })).then(() => { + if (errors.length == groupIds.length) { + // All requests have failed, reject if errors were not returned by WS. + for (let i = 0; i < errors.length; i++) { + if (!this.utils.isWebServiceError(errors[i])) { + return Promise.reject(errors[i]); + } + } + } - return this.deleteNewDiscussion(forumId, data.timecreated, siteId, userId); - }).catch((error) => { - if (this.utils.isWebServiceError(error)) { - // The WebService has thrown an error, this means that responses cannot be submitted. Delete them. + // All requests succeeded, some failed or all failed with a WS error. result.updated = true; return this.deleteNewDiscussion(forumId, data.timecreated, siteId, userId).then(() => { - // Responses deleted, add a warning. - result.warnings.push(this.translate.instant('core.warningofflinedatadeleted', { - component: this.componentTranslate, - name: data.name, - error: this.textUtils.getErrorMessageFromError(error) - })); + if (errors.length == groupIds.length) { + // All requests failed with WS error. + result.warnings.push(this.translate.instant('core.warningofflinedatadeleted', { + component: this.componentTranslate, + name: data.name, + error: this.textUtils.getErrorMessageFromError(errors[0]) + })); + } }); - } else { - // Couldn't connect to server, reject. - return Promise.reject(error); - } + }); })); }); diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index 9a3acd3d6..311fb6fcc 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -503,6 +503,7 @@ "addon.mod_forum.erroremptysubject": "Post subject cannot be empty.", "addon.mod_forum.errorgetforum": "Error getting forum data.", "addon.mod_forum.errorgetgroups": "Error getting group settings.", + "addon.mod_forum.errorposttoallgroups": "Could not create new discussion in all groups.", "addon.mod_forum.favouriteupdated": "Your star option has been updated.", "addon.mod_forum.forumnodiscussionsyet": "There are no discussions yet in this forum.", "addon.mod_forum.group": "Group", @@ -520,6 +521,7 @@ "addon.mod_forum.pinupdated": "The pin option has been updated.", "addon.mod_forum.postisprivatereply": "This post was made privately and is not visible to all users.", "addon.mod_forum.posttoforum": "Post to forum", + "addon.mod_forum.posttomygroups": "Post a copy to all groups", "addon.mod_forum.privatereply": "Reply privately", "addon.mod_forum.re": "Re:", "addon.mod_forum.refreshdiscussions": "Refresh discussions", @@ -1219,6 +1221,7 @@ "core.agelocationverification": "Age and location verification", "core.ago": "{{$a}} ago", "core.all": "All", + "core.allgroups": "All groups", "core.allparticipants": "All participants", "core.android": "Android", "core.answer": "Answer", diff --git a/src/lang/en.json b/src/lang/en.json index 5e594fcc6..bf2f305e5 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -4,6 +4,7 @@ "agelocationverification": "Age and location verification", "ago": "{{$a}} ago", "all": "All", + "allgroups": "All groups", "allparticipants": "All participants", "android": "Android", "answer": "Answer",