MOBILE-3018 forum: Post a copy to all groups

main
Albert Gasset 2019-05-16 15:04:45 +02:00
parent 84caaaeaa9
commit e25306b0b2
11 changed files with 235 additions and 134 deletions

View File

@ -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",

View File

@ -31,7 +31,7 @@
<ion-icon name="information-circle"></ion-icon> {{ availabilityMessage }}
</ion-card>
<core-empty-box *ngIf="forum && discussions.length == 0" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate">
<core-empty-box *ngIf="forum && discussions.length == 0 && offlineDiscussions.length == 0" icon="chatbubbles" [message]="'addon.mod_forum.forumnodiscussionsyet' | translate">
</core-empty-box>
<div text-wrap *ngIf="sortingAvailable && selectedSortOrder" ion-row padding-horizontal padding-top margin-bottom>
@ -41,7 +41,7 @@
</button>
</div>
<ng-container *ngIf="forum && discussions.length > 0">
<ng-container *ngIf="forum">
<ion-card *ngFor="let discussion of offlineDiscussions" (click)="openNewDiscussion(discussion.timecreated)" [class.addon-forum-discussion-selected]="discussion.timecreated == -selectedDiscussion">
<ion-item text-wrap>
<ion-avatar core-user-avatar [user]="discussion" item-start [courseId]="courseId"></ion-avatar>

View File

@ -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",

View File

@ -27,9 +27,13 @@
{{ 'addon.mod_forum.advanced' | translate }}
</ion-item-divider>
<ng-container *ngIf="advanced">
<ion-item *ngIf="showGroups && groupIds.length > 1 && accessInfo.cancanposttomygroups">
<ion-label>{{ 'addon.mod_forum.posttomygroups' | translate }}</ion-label>
<ion-toggle [(ngModel)]="newDiscussion.postToAllGroups"></ion-toggle>
</ion-item>
<ion-item *ngIf="showGroups">
<ion-label id="addon-mod-forum-groupslabel">{{ 'addon.mod_forum.group' | translate }}</ion-label>
<ion-select [(ngModel)]="newDiscussion.groupId" aria-labelledby="addon-mod-forum-groupslabel" interface="action-sheet">
<ion-select [(ngModel)]="newDiscussion.groupId" [disabled]="newDiscussion.postToAllGroups" aria-labelledby="addon-mod-forum-groupslabel" interface="action-sheet">
<ion-option *ngFor="let group of groups" [value]="group.id">{{ group.name }}</ion-option>
</ion-select>
</ion-item>

View File

@ -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<any>} Promise resolved when done.
* @return {Promise<any[]>} Promise resolved with the list of groups.
*/
protected validateVisibleGroups(forumGroups: any[]): Promise<any> {
protected validateVisibleGroups(forumGroups: any[]): Promise<any[]> {
// 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(() => {

View File

@ -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<any>} 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<any> {
siteId = siteId || this.sitesProvider.getCurrentSiteId();
// Convenience function to store a message to be synchronized later.
const storeOffline = (): Promise<any> => {
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<any> {
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) {

View File

@ -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<number[]>} 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<number[]> {
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<number[]> => {
// 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.
*

View File

@ -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()
};

View File

@ -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);
}
});
}));
});

View File

@ -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",

View File

@ -4,6 +4,7 @@
"agelocationverification": "Age and location verification",
"ago": "{{$a}} ago",
"all": "All",
"allgroups": "All groups",
"allparticipants": "All participants",
"android": "Android",
"answer": "Answer",