Skip to content

Commit 6590907

Browse files
committed
MOBILE-2272 quiz: Support deleting attachments
1 parent 5b0059a commit 6590907

File tree

2 files changed

+97
-1
lines changed

2 files changed

+97
-1
lines changed

src/addon/qtype/essay/providers/handler.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,15 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
278278
// Store the files in the answers.
279279
answers[attachmentsInput.name + '_offline'] = JSON.stringify(result);
280280
} else {
281+
// Check if any attachment was deleted.
282+
const originalAttachments = this.questionHelper.getResponseFileAreaFiles(question, 'attachments');
283+
const filesToDelete = CoreFileUploader.instance.getFilesToDelete(originalAttachments, attachments);
284+
285+
if (filesToDelete.length > 0) {
286+
// Delete files.
287+
await CoreFileUploader.instance.deleteDraftFiles(draftId, filesToDelete, siteId);
288+
}
289+
281290
await CoreFileUploader.instance.uploadFiles(draftId, attachments, siteId);
282291
}
283292
}
@@ -304,9 +313,17 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
304313
}
305314

306315
if (answers && answers.attachments_offline) {
307-
// Check if it has new attachments to upload.
308316
const attachmentsData = this.textUtils.parseJSON(answers.attachments_offline, {});
309317

318+
// Check if any attachment was deleted.
319+
const originalAttachments = this.questionHelper.getResponseFileAreaFiles(question, 'attachments');
320+
const filesToDelete = CoreFileUploader.instance.getFilesToDelete(originalAttachments, attachmentsData.online);
321+
322+
if (filesToDelete.length > 0) {
323+
// Delete files.
324+
await CoreFileUploader.instance.deleteDraftFiles(answers.attachments, filesToDelete, siteId);
325+
}
326+
310327
if (attachmentsData.offline) {
311328
// Upload the offline files.
312329
const offlineFiles = await this.questionHelper.getStoredQuestionFiles(question, component, componentId, siteId);

src/core/fileuploader/providers/fileuploader.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
2929
import { CoreWSFileUploadOptions, CoreWSExternalFile } from '@providers/ws';
3030
import { Subject } from 'rxjs';
3131
import { CoreApp } from '@providers/app';
32+
import { CoreSite } from '@classes/site';
3233
import { makeSingleton } from '@singletons/core.singletons';
3334

3435
/**
@@ -106,6 +107,36 @@ export class CoreFileUploaderProvider {
106107
return false;
107108
}
108109

110+
/**
111+
* Check if a certain site allows deleting draft files.
112+
*
113+
* @param siteId Site Id. If not defined, use current site.
114+
* @return Promise resolved with true if can delete.
115+
* @since 3.10
116+
*/
117+
async canDeleteDraftFiles(siteId?: string): Promise<boolean> {
118+
try {
119+
const site = await this.sitesProvider.getSite(siteId);
120+
121+
return this.canDeleteDraftFilesInSite(site);
122+
} catch (error) {
123+
return false;
124+
}
125+
}
126+
127+
/**
128+
* Check if a certain site allows deleting draft files.
129+
*
130+
* @param site Site. If not defined, use current site.
131+
* @return Whether draft files can be deleted.
132+
* @since 3.10
133+
*/
134+
canDeleteDraftFilesInSite(site?: CoreSite): boolean {
135+
site = site || this.sitesProvider.getCurrentSite();
136+
137+
return site.wsAvailable('core_files_delete_draft_files');
138+
}
139+
109140
/**
110141
* Start the audio recorder application and return information about captured audio clip files.
111142
*
@@ -175,6 +206,25 @@ export class CoreFileUploaderProvider {
175206
});
176207
}
177208

209+
/**
210+
* Delete draft files.
211+
*
212+
* @param draftId Draft ID.
213+
* @param files Files to delete.
214+
* @param siteId Site ID. If not defined, current site.
215+
* @return Promise resolved when done.
216+
*/
217+
async deleteDraftFiles(draftId: number, files: {filepath: string, filename: string}[], siteId?: string): Promise<void> {
218+
const site = await this.sitesProvider.getSite(siteId);
219+
220+
const params = {
221+
draftitemid: draftId,
222+
files: files,
223+
};
224+
225+
return site.write('core_files_delete_draft_files', params);
226+
}
227+
178228
/**
179229
* Get the upload options for a file taken with the Camera Cordova plugin.
180230
*
@@ -217,6 +267,35 @@ export class CoreFileUploaderProvider {
217267
return options;
218268
}
219269

270+
/**
271+
* Given a list of original files and a list of current files, return the list of files to delete.
272+
*
273+
* @param originalFiles Original files.
274+
* @param currentFiles Current files.
275+
* @return List of files to delete.
276+
*/
277+
getFilesToDelete(originalFiles: CoreWSExternalFile[], currentFiles: (CoreWSExternalFile | FileEntry)[])
278+
: {filepath: string, filename: string}[] {
279+
280+
const filesToDelete: {filepath: string, filename: string}[] = [];
281+
currentFiles = currentFiles || [];
282+
283+
originalFiles.forEach((file) => {
284+
const stillInList = currentFiles.some((currentFile) => {
285+
return (<CoreWSExternalFile> currentFile).fileurl == file.fileurl;
286+
});
287+
288+
if (!stillInList) {
289+
filesToDelete.push({
290+
filepath: file.filepath,
291+
filename: file.filename,
292+
});
293+
}
294+
});
295+
296+
return filesToDelete;
297+
}
298+
220299
/**
221300
* Get the upload options for a file of any type.
222301
*

0 commit comments

Comments
 (0)