MOBILE-2272 quiz: Support deleting attachments
parent
5b0059a617
commit
65909073fa
|
@ -278,6 +278,15 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
|
||||||
// Store the files in the answers.
|
// Store the files in the answers.
|
||||||
answers[attachmentsInput.name + '_offline'] = JSON.stringify(result);
|
answers[attachmentsInput.name + '_offline'] = JSON.stringify(result);
|
||||||
} else {
|
} else {
|
||||||
|
// Check if any attachment was deleted.
|
||||||
|
const originalAttachments = this.questionHelper.getResponseFileAreaFiles(question, 'attachments');
|
||||||
|
const filesToDelete = CoreFileUploader.instance.getFilesToDelete(originalAttachments, attachments);
|
||||||
|
|
||||||
|
if (filesToDelete.length > 0) {
|
||||||
|
// Delete files.
|
||||||
|
await CoreFileUploader.instance.deleteDraftFiles(draftId, filesToDelete, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
await CoreFileUploader.instance.uploadFiles(draftId, attachments, siteId);
|
await CoreFileUploader.instance.uploadFiles(draftId, attachments, siteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,9 +313,17 @@ export class AddonQtypeEssayHandler implements CoreQuestionHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (answers && answers.attachments_offline) {
|
if (answers && answers.attachments_offline) {
|
||||||
// Check if it has new attachments to upload.
|
|
||||||
const attachmentsData = this.textUtils.parseJSON(answers.attachments_offline, {});
|
const attachmentsData = this.textUtils.parseJSON(answers.attachments_offline, {});
|
||||||
|
|
||||||
|
// Check if any attachment was deleted.
|
||||||
|
const originalAttachments = this.questionHelper.getResponseFileAreaFiles(question, 'attachments');
|
||||||
|
const filesToDelete = CoreFileUploader.instance.getFilesToDelete(originalAttachments, attachmentsData.online);
|
||||||
|
|
||||||
|
if (filesToDelete.length > 0) {
|
||||||
|
// Delete files.
|
||||||
|
await CoreFileUploader.instance.deleteDraftFiles(answers.attachments, filesToDelete, siteId);
|
||||||
|
}
|
||||||
|
|
||||||
if (attachmentsData.offline) {
|
if (attachmentsData.offline) {
|
||||||
// Upload the offline files.
|
// Upload the offline files.
|
||||||
const offlineFiles = await this.questionHelper.getStoredQuestionFiles(question, component, componentId, siteId);
|
const offlineFiles = await this.questionHelper.getStoredQuestionFiles(question, component, componentId, siteId);
|
||||||
|
|
|
@ -29,6 +29,7 @@ import { CoreUtilsProvider } from '@providers/utils/utils';
|
||||||
import { CoreWSFileUploadOptions, CoreWSExternalFile } from '@providers/ws';
|
import { CoreWSFileUploadOptions, CoreWSExternalFile } from '@providers/ws';
|
||||||
import { Subject } from 'rxjs';
|
import { Subject } from 'rxjs';
|
||||||
import { CoreApp } from '@providers/app';
|
import { CoreApp } from '@providers/app';
|
||||||
|
import { CoreSite } from '@classes/site';
|
||||||
import { makeSingleton } from '@singletons/core.singletons';
|
import { makeSingleton } from '@singletons/core.singletons';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,6 +107,36 @@ export class CoreFileUploaderProvider {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a certain site allows deleting draft files.
|
||||||
|
*
|
||||||
|
* @param siteId Site Id. If not defined, use current site.
|
||||||
|
* @return Promise resolved with true if can delete.
|
||||||
|
* @since 3.10
|
||||||
|
*/
|
||||||
|
async canDeleteDraftFiles(siteId?: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
const site = await this.sitesProvider.getSite(siteId);
|
||||||
|
|
||||||
|
return this.canDeleteDraftFilesInSite(site);
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a certain site allows deleting draft files.
|
||||||
|
*
|
||||||
|
* @param site Site. If not defined, use current site.
|
||||||
|
* @return Whether draft files can be deleted.
|
||||||
|
* @since 3.10
|
||||||
|
*/
|
||||||
|
canDeleteDraftFilesInSite(site?: CoreSite): boolean {
|
||||||
|
site = site || this.sitesProvider.getCurrentSite();
|
||||||
|
|
||||||
|
return site.wsAvailable('core_files_delete_draft_files');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the audio recorder application and return information about captured audio clip files.
|
* Start the audio recorder application and return information about captured audio clip files.
|
||||||
*
|
*
|
||||||
|
@ -175,6 +206,25 @@ export class CoreFileUploaderProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete draft files.
|
||||||
|
*
|
||||||
|
* @param draftId Draft ID.
|
||||||
|
* @param files Files to delete.
|
||||||
|
* @param siteId Site ID. If not defined, current site.
|
||||||
|
* @return Promise resolved when done.
|
||||||
|
*/
|
||||||
|
async deleteDraftFiles(draftId: number, files: {filepath: string, filename: string}[], siteId?: string): Promise<void> {
|
||||||
|
const site = await this.sitesProvider.getSite(siteId);
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
draftitemid: draftId,
|
||||||
|
files: files,
|
||||||
|
};
|
||||||
|
|
||||||
|
return site.write('core_files_delete_draft_files', params);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the upload options for a file taken with the Camera Cordova plugin.
|
* Get the upload options for a file taken with the Camera Cordova plugin.
|
||||||
*
|
*
|
||||||
|
@ -217,6 +267,35 @@ export class CoreFileUploaderProvider {
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of original files and a list of current files, return the list of files to delete.
|
||||||
|
*
|
||||||
|
* @param originalFiles Original files.
|
||||||
|
* @param currentFiles Current files.
|
||||||
|
* @return List of files to delete.
|
||||||
|
*/
|
||||||
|
getFilesToDelete(originalFiles: CoreWSExternalFile[], currentFiles: (CoreWSExternalFile | FileEntry)[])
|
||||||
|
: {filepath: string, filename: string}[] {
|
||||||
|
|
||||||
|
const filesToDelete: {filepath: string, filename: string}[] = [];
|
||||||
|
currentFiles = currentFiles || [];
|
||||||
|
|
||||||
|
originalFiles.forEach((file) => {
|
||||||
|
const stillInList = currentFiles.some((currentFile) => {
|
||||||
|
return (<CoreWSExternalFile> currentFile).fileurl == file.fileurl;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!stillInList) {
|
||||||
|
filesToDelete.push({
|
||||||
|
filepath: file.filepath,
|
||||||
|
filename: file.filename,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return filesToDelete;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the upload options for a file of any type.
|
* Get the upload options for a file of any type.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue