diff --git a/src/addon/mod/data/providers/sync.ts b/src/addon/mod/data/providers/sync.ts index 03590485a..0553511c4 100644 --- a/src/addon/mod/data/providers/sync.ts +++ b/src/addon/mod/data/providers/sync.ts @@ -235,26 +235,32 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider { protected syncEntry(data: any, entryActions: AddonModDataOfflineAction[], result: any, siteId?: string): Promise { let discardError, timePromise, - entryId = 0, + entryId = entryActions[0].entryid, offlineId, deleted = false; - const promises = []; - - // Sort entries by timemodified. - entryActions = entryActions.sort((a: any, b: any) => a.timemodified - b.timemodified); - - entryId = entryActions[0].entryid; + const editAction = entryActions.find((action) => action.action == 'add' || action.action == 'edit'); + const approveAction = entryActions.find((action) => action.action == 'approve' || action.action == 'disapprove'); + const deleteAction = entryActions.find((action) => action.action == 'delete'); if (entryId > 0) { - timePromise = this.dataProvider.getEntry(data.id, entryId, false, siteId).then((entry) => { + timePromise = this.dataProvider.getEntry(data.id, entryId, true, siteId).then((entry) => { return entry.entry.timemodified; - }).catch(() => { - return -1; + }).catch((error) => { + if (error && this.utils.isWebServiceError(error)) { + // The WebService has thrown an error, this means the entry has been deleted. + return Promise.resolve(-1); + } + + return Promise.reject(error); }); - } else { + } else if (editAction) { + // New entry. offlineId = entryId; timePromise = Promise.resolve(0); + } else { + // New entry but the add action is missing, discard. + timePromise = Promise.resolve(-1); } return timePromise.then((timemodified) => { @@ -266,58 +272,11 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider { return this.dataOffline.deleteAllEntryActions(data.id, entryId, siteId); } - entryActions.forEach((action) => { - let actionPromise; - const proms = []; - - entryId = action.entryid > 0 ? action.entryid : entryId; - - if (action.fields) { - action.fields.forEach((field) => { - // Upload Files if asked. - const value = this.textUtils.parseJSON(field.value); - if (value.online || value.offline) { - let files = value.online || []; - const fileProm = value.offline ? this.dataHelper.getStoredFiles(action.dataid, entryId, field.fieldid) : - Promise.resolve([]); - - proms.push(fileProm.then((offlineFiles) => { - files = files.concat(offlineFiles); - - return this.dataHelper.uploadOrStoreFiles(action.dataid, 0, entryId, field.fieldid, files, false, - siteId).then((filesResult) => { - field.value = JSON.stringify(filesResult); - }); - })); - } - }); - } - - actionPromise = Promise.all(proms).then(() => { - // Perform the action. - switch (action.action) { - case 'add': - return this.dataProvider.addEntryOnline(action.dataid, action.fields, data.groupid, siteId) - .then((result) => { - entryId = result.newentryid; - }); - case 'edit': - return this.dataProvider.editEntryOnline(entryId, action.fields, siteId); - case 'approve': - return this.dataProvider.approveEntryOnline(entryId, true, siteId); - case 'disapprove': - return this.dataProvider.approveEntryOnline(entryId, false, siteId); - case 'delete': - return this.dataProvider.deleteEntryOnline(entryId, siteId).then(() => { - deleted = true; - }); - default: - break; - } - }); - - promises.push(actionPromise.catch((error) => { - if (error && error.wserror) { + if (deleteAction) { + return this.dataProvider.deleteEntryOnline(entryId, siteId).then(() => { + deleted = true; + }).catch((error) => { + if (error && this.utils.isWebServiceError(error)) { // The WebService has thrown an error, this means it cannot be performed. Discard. discardError = this.textUtils.getErrorMessageFromError(error); } else { @@ -328,11 +287,79 @@ export class AddonModDataSyncProvider extends CoreSyncBaseProvider { // Delete the offline data. result.updated = true; - return this.dataOffline.deleteEntry(action.dataid, action.entryid, action.action, siteId); - })); - }); + return this.dataOffline.deleteAllEntryActions(deleteAction.dataid, deleteAction.entryid, siteId); + }); + } + + let editPromise; + + if (editAction) { + editPromise = Promise.all(editAction.fields.map((field) => { + // Upload Files if asked. + const value = this.textUtils.parseJSON(field.value); + if (value.online || value.offline) { + let files = value.online || []; + const fileProm = value.offline ? + this.dataHelper.getStoredFiles(editAction.dataid, entryId, field.fieldid) : + Promise.resolve([]); + + return fileProm.then((offlineFiles) => { + files = files.concat(offlineFiles); + + return this.dataHelper.uploadOrStoreFiles(editAction.dataid, 0, entryId, field.fieldid, files, + false, siteId).then((filesResult) => { + field.value = JSON.stringify(filesResult); + }); + }); + } + })).then(() => { + if (editAction.action == 'add') { + return this.dataProvider.addEntryOnline(editAction.dataid, editAction.fields, editAction.groupid, siteId) + .then((result) => { + entryId = result.newentryid; + }); + } else { + return this.dataProvider.editEntryOnline(entryId, editAction.fields, siteId); + } + }).catch((error) => { + if (error && this.utils.isWebServiceError(error)) { + // The WebService has thrown an error, this means it cannot be performed. Discard. + discardError = this.textUtils.getErrorMessageFromError(error); + } else { + // Couldn't connect to server, reject. + return Promise.reject(error); + } + }).then(() => { + // Delete the offline data. + result.updated = true; + + return this.dataOffline.deleteEntry(editAction.dataid, editAction.entryid, editAction.action, siteId); + }); + } else { + editPromise = Promise.resolve(); + } + + if (approveAction) { + editPromise = editPromise.then(() => { + return this.dataProvider.approveEntryOnline(entryId, approveAction.action == 'approve', siteId); + }).catch((error) => { + if (error && this.utils.isWebServiceError(error)) { + // The WebService has thrown an error, this means it cannot be performed. Discard. + discardError = this.textUtils.getErrorMessageFromError(error); + } else { + // Couldn't connect to server, reject. + return Promise.reject(error); + } + }).then(() => { + // Delete the offline data. + result.updated = true; + + return this.dataOffline.deleteEntry(approveAction.dataid, approveAction.entryid, approveAction.action, siteId); + }); + } + + return editPromise; - return Promise.all(promises); }).then(() => { if (discardError) { // Submission was discarded, add a warning.