MOBILE-4653 utils: Move file related utils functions

main
Pau Ferrer Ocaña 2024-11-15 13:49:21 +01:00
parent 94b0266794
commit 5e3d233272
9 changed files with 109 additions and 43 deletions

View File

@ -25,7 +25,7 @@ import { Injectable, Type } from '@angular/core';
import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader'; import { CoreFileUploader, CoreFileUploaderStoreFilesResult } from '@features/fileuploader/services/fileuploader';
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper'; import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
import { CoreFileSession } from '@services/file-session'; import { CoreFileSession } from '@services/file-session';
import { CoreUtils } from '@services/utils/utils'; import { CoreFileUtils } from '@singletons/file-utils';
import { CoreWSFile } from '@services/ws'; import { CoreWSFile } from '@services/ws';
import { makeSingleton } from '@singletons'; import { makeSingleton } from '@singletons';
import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
@ -242,7 +242,7 @@ export class AddonModAssignSubmissionFileHandlerService implements AddonModAssig
// Data has changed, we need to upload new files and re-upload all the existing files. // Data has changed, we need to upload new files and re-upload all the existing files.
const currentFiles = CoreFileSession.getFiles(ADDON_MOD_ASSIGN_COMPONENT, assign.id); const currentFiles = CoreFileSession.getFiles(ADDON_MOD_ASSIGN_COMPONENT, assign.id);
const error = CoreUtils.hasRepeatedFilenames(currentFiles); const error = CoreFileUtils.hasRepeatedFilenames(currentFiles);
if (error) { if (error) {
throw error; throw error;

View File

@ -45,7 +45,7 @@ import { CoreSync } from '@services/sync';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { AddonModForumHelper } from '../../services/forum-helper'; import { AddonModForumHelper } from '../../services/forum-helper';
import { AddonModForumOffline } from '../../services/forum-offline'; import { AddonModForumOffline } from '../../services/forum-offline';
import { CoreUtils } from '@services/utils/utils'; import { CoreFileUtils } from '@singletons/file-utils';
import { CoreRatingInfo } from '@features/rating/services/rating'; import { CoreRatingInfo } from '@features/rating/services/rating';
import { CoreForms } from '@singletons/form'; import { CoreForms } from '@singletons/form';
import { CoreFileEntry, CoreFileHelper } from '@services/file-helper'; import { CoreFileEntry, CoreFileHelper } from '@services/file-helper';
@ -506,7 +506,7 @@ export class AddonModForumPostComponent implements OnInit, OnDestroy, OnChanges
} }
// Use prepare post for edition to avoid re-uploading all files. // Use prepare post for edition to avoid re-uploading all files.
let filesToKeep = files.filter((file): file is CoreWSFile => !CoreUtils.isFileEntry(file)); let filesToKeep = files.filter((file): file is CoreWSFile => !CoreFileUtils.isFileEntry(file));
let removedFiles: { filepath: string; filename: string }[] | undefined; let removedFiles: { filepath: string; filename: string }[] | undefined;
if (previousAttachments.length && !filesToKeep.length) { if (previousAttachments.length && !filesToKeep.length) {

View File

@ -19,6 +19,7 @@ import { MediaFile, CaptureError, CaptureVideoOptions } from '@awesome-cordova-p
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { CoreFile, CoreFileProvider } from '@services/file'; import { CoreFile, CoreFileProvider } from '@services/file';
import { CoreFileUtils } from '@singletons/file-utils';
import { CoreFilepool } from '@services/filepool'; import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
@ -557,7 +558,7 @@ export class CoreFileUploaderProvider {
await CoreFile.removeUnusedFiles(folderPath, files); await CoreFile.removeUnusedFiles(folderPath, files);
await Promise.all(files.map(async (file) => { await Promise.all(files.map(async (file) => {
if (!CoreUtils.isFileEntry(file)) { if (!CoreFileUtils.isFileEntry(file)) {
// It's an online file, add it to the result and ignore it. // It's an online file, add it to the result and ignore it.
result.online.push({ result.online.push({
filename: file.filename, filename: file.filename,
@ -632,7 +633,7 @@ export class CoreFileUploaderProvider {
const usedNames: {[name: string]: CoreFileEntry} = {}; const usedNames: {[name: string]: CoreFileEntry} = {};
const filesToUpload: FileEntry[] = []; const filesToUpload: FileEntry[] = [];
files.forEach((file) => { files.forEach((file) => {
if (CoreUtils.isFileEntry(file)) { if (CoreFileUtils.isFileEntry(file)) {
filesToUpload.push(<FileEntry> file); filesToUpload.push(<FileEntry> file);
} else { } else {
// It's an online file. // It's an online file.
@ -679,9 +680,9 @@ export class CoreFileUploaderProvider {
let fileName = ''; let fileName = '';
let fileEntry: FileEntry | undefined; let fileEntry: FileEntry | undefined;
const isOnline = !CoreUtils.isFileEntry(file); const isOnline = !CoreFileUtils.isFileEntry(file);
if (CoreUtils.isFileEntry(file)) { if (CoreFileUtils.isFileEntry(file)) {
// Local file, we already have the file entry. // Local file, we already have the file entry.
fileName = file.name; fileName = file.name;
fileEntry = file; fileEntry = file;

View File

@ -17,6 +17,7 @@ import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
import { CoreNetwork } from '@services/network'; import { CoreNetwork } from '@services/network';
import { CoreFile } from '@services/file'; import { CoreFile } from '@services/file';
import { CoreFileUtils } from '@singletons/file-utils';
import { CoreFilepool } from '@services/filepool'; import { CoreFilepool } from '@services/filepool';
import { CoreSites } from '@services/sites'; import { CoreSites } from '@services/sites';
import { CoreWS, CoreWSFile } from '@services/ws'; import { CoreWS, CoreWSFile } from '@services/ws';
@ -489,7 +490,7 @@ export class CoreFileHelperProvider {
* @returns The file name. * @returns The file name.
*/ */
getFilenameFromPath(file: CoreFileEntry): string | undefined { getFilenameFromPath(file: CoreFileEntry): string | undefined {
const path = CoreUtils.isFileEntry(file) ? file.fullPath : file.filepath; const path = CoreFileUtils.isFileEntry(file) ? file.fullPath : file.filepath;
if (path === undefined || path.length == 0) { if (path === undefined || path.length == 0) {
return; return;

View File

@ -17,7 +17,7 @@ import { Injectable } from '@angular/core';
import { FileEntry, DirectoryEntry, Entry, Metadata, IFile } from '@awesome-cordova-plugins/file/ngx'; import { FileEntry, DirectoryEntry, Entry, Metadata, IFile } from '@awesome-cordova-plugins/file/ngx';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
import { CoreUtils } from '@services/utils/utils'; import { CoreFileUtils } from '@singletons/file-utils';
import { CoreConstants } from '@/core/constants'; import { CoreConstants } from '@/core/constants';
import { CoreError } from '@classes/errors/error'; import { CoreError } from '@classes/errors/error';
@ -1304,7 +1304,7 @@ export class CoreFileProvider {
* @returns The file name. * @returns The file name.
*/ */
getFileName(file: CoreFileEntry): string | undefined { getFileName(file: CoreFileEntry): string | undefined {
return CoreUtils.isFileEntry(file) ? file.name : file.filename; return CoreFileUtils.isFileEntry(file) ? file.name : file.filename;
} }
} }

View File

@ -16,11 +16,11 @@ import { Injectable } from '@angular/core';
import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
import { CoreFile } from '@services/file'; import { CoreFile } from '@services/file';
import { CoreFileUtils } from '@singletons/file-utils';
import { CoreText } from '@singletons/text'; import { CoreText } from '@singletons/text';
import { makeSingleton, Translate } from '@singletons'; import { makeSingleton, Translate } from '@singletons';
import { CoreLogger } from '@singletons/logger'; import { CoreLogger } from '@singletons/logger';
import { CoreWSFile } from '@services/ws'; import { CoreWSFile } from '@services/ws';
import { CoreUtils } from '@services/utils/utils';
import extToMime from '@/assets/exttomime.json'; import extToMime from '@/assets/exttomime.json';
import mimeToExt from '@/assets/mimetoext.json'; import mimeToExt from '@/assets/mimetoext.json';
@ -168,11 +168,11 @@ export class CoreMimetypeUtilsProvider {
* @returns The embedded HTML string. * @returns The embedded HTML string.
*/ */
getEmbeddedHtml(file: CoreFileEntry, path?: string): string { getEmbeddedHtml(file: CoreFileEntry, path?: string): string {
const filename = CoreUtils.isFileEntry(file) ? (file as FileEntry).name : file.filename; const filename = CoreFileUtils.isFileEntry(file) ? (file as FileEntry).name : file.filename;
const extension = !CoreUtils.isFileEntry(file) && file.mimetype const extension = !CoreFileUtils.isFileEntry(file) && file.mimetype
? this.getExtension(file.mimetype) ? this.getExtension(file.mimetype)
: (filename && this.getFileExtension(filename)); : (filename && this.getFileExtension(filename));
const mimeType = !CoreUtils.isFileEntry(file) && file.mimetype const mimeType = !CoreFileUtils.isFileEntry(file) && file.mimetype
? file.mimetype ? file.mimetype
: (extension && this.getMimeType(extension)); : (extension && this.getMimeType(extension));
@ -185,7 +185,7 @@ export class CoreMimetypeUtilsProvider {
// @todo linting: See if this can be removed // @todo linting: See if this can be removed
(file as { embedType?: string }).embedType = embedType; (file as { embedType?: string }).embedType = embedType;
path = path ?? (CoreUtils.isFileEntry(file) ? CoreFile.getFileEntryURL(file) : CoreFileHelper.getFileUrl(file)); path = path ?? (CoreFileUtils.isFileEntry(file) ? CoreFile.getFileEntryURL(file) : CoreFileHelper.getFileUrl(file));
path = path && CoreFile.convertFileSrc(path); path = path && CoreFile.convertFileSrc(path);
switch (embedType) { switch (embedType) {
@ -424,7 +424,7 @@ export class CoreMimetypeUtilsProvider {
let mimetype: string | undefined = ''; let mimetype: string | undefined = '';
let extension: string | undefined = ''; let extension: string | undefined = '';
if (typeof obj == 'object' && CoreUtils.isFileEntry(obj)) { if (typeof obj == 'object' && CoreFileUtils.isFileEntry(obj)) {
// It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable. // It's a FileEntry. Don't use the file function because it's asynchronous and the type isn't reliable.
filename = obj.name; filename = obj.name;
} else if (typeof obj == 'object') { } else if (typeof obj == 'object') {

View File

@ -16,6 +16,7 @@ import { Injectable } from '@angular/core';
import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser'; import { InAppBrowserObject } from '@awesome-cordova-plugins/in-app-browser';
import { FileEntry } from '@awesome-cordova-plugins/file/ngx'; import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
import { CoreFile } from '@services/file'; import { CoreFile } from '@services/file';
import { CoreFileUtils } from '@singletons/file-utils';
import { CoreLang, CoreLangFormat } from '@services/lang'; import { CoreLang, CoreLangFormat } from '@services/lang';
import { CoreWS } from '@services/ws'; import { CoreWS } from '@services/ws';
import { CoreMimetypeUtils } from '@services/utils/mimetype'; import { CoreMimetypeUtils } from '@services/utils/mimetype';
@ -288,7 +289,7 @@ export class CoreUtilsProvider {
return source; return source;
} }
if (this.valueIsFileEntry(source)) { if (CoreFileUtils.valueIsFileEntry(source)) {
// Don't clone FileEntry. It has a lot of depth and they shouldn't be modified. // Don't clone FileEntry. It has a lot of depth and they shouldn't be modified.
return source; return source;
} else if (Array.isArray(source)) { } else if (Array.isArray(source)) {
@ -717,9 +718,10 @@ export class CoreUtilsProvider {
* *
* @param file File. * @param file File.
* @returns Type guard indicating if the file is a FileEntry. * @returns Type guard indicating if the file is a FileEntry.
* @deprecated since 5.0. Use CoreFile.isFileEntry singleton instead.
*/ */
isFileEntry(file: CoreFileEntry): file is FileEntry { isFileEntry(file: CoreFileEntry): file is FileEntry {
return 'isFile' in file; return CoreFileUtils.isFileEntry(file);
} }
/** /**
@ -727,11 +729,10 @@ export class CoreUtilsProvider {
* *
* @param file Object to check. * @param file Object to check.
* @returns Type guard indicating if the file is a FileEntry. * @returns Type guard indicating if the file is a FileEntry.
* @deprecated since 5.0. Use CoreFile.valueIsFileEntry singleton instead.
*/ */
valueIsFileEntry(file: unknown): file is FileEntry { valueIsFileEntry(file: unknown): file is FileEntry {
// We cannot use instanceof because FileEntry is a type. Check some of the properties. return CoreFileUtils.valueIsFileEntry(file);
return !!(file && typeof file == 'object' && 'isFile' in file && 'filesystem' in file &&
'toInternalURL' in file && 'copyTo' in file);
} }
/** /**
@ -749,27 +750,10 @@ export class CoreUtilsProvider {
* *
* @param files List of files. * @param files List of files.
* @returns String with error message if repeated, false if no repeated. * @returns String with error message if repeated, false if no repeated.
* @deprecated since 5.0. Use CoreFileUtils.hasRepeatedFilenames instead.
*/ */
hasRepeatedFilenames(files: CoreFileEntry[]): string | false { hasRepeatedFilenames(files: CoreFileEntry[]): string | false {
if (!files || !files.length) { return CoreFileUtils.hasRepeatedFilenames(files);
return false;
}
const names: string[] = [];
// Check if there are 2 files with the same name.
for (let i = 0; i < files.length; i++) {
const file = files[i];
const name = (this.isFileEntry(file) ? file.name : file.filename) || '';
if (names.indexOf(name) > -1) {
return Translate.instant('core.filenameexist', { $a: name });
}
names.push(name);
}
return false;
} }
/** /**
@ -956,7 +940,7 @@ export class CoreUtilsProvider {
// Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so. // Path needs to be decoded, the file won't be opened if the path has %20 instead of spaces and so.
try { try {
path = decodeURIComponent(path); path = decodeURIComponent(path);
} catch (ex) { } catch {
// Error, use the original path. // Error, use the original path.
} }

View File

@ -0,0 +1,79 @@
// (C) Copyright 2015 Moodle Pty Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { CoreFileEntry } from '@services/file-helper';
import { FileEntry } from '@awesome-cordova-plugins/file/ngx';
import { Translate } from '@singletons';
/**
* Helpers to interact with the file system.
*/
export class CoreFileUtils {
// Avoid creating singleton instances.
private constructor() {
// Nothing to do.
}
/**
* Check if a file is a FileEntry
*
* @param file File.
* @returns Type guard indicating if the file is a FileEntry.
*/
static isFileEntry(file: CoreFileEntry): file is FileEntry {
return 'isFile' in file;
}
/**
* Check if an unknown value is a FileEntry.
*
* @param file Object to check.
* @returns Type guard indicating if the file is a FileEntry.
*/
static valueIsFileEntry(file: unknown): file is FileEntry {
// We cannot use instanceof because FileEntry is a type. Check some of the properties.
return !!(file && typeof file == 'object' && 'isFile' in file && 'filesystem' in file &&
'toInternalURL' in file && 'copyTo' in file);
}
/**
* Given a list of files, check if there are repeated names.
*
* @param files List of files.
* @returns String with error message if repeated, false if no repeated.
*/
static hasRepeatedFilenames(files: CoreFileEntry[]): string | false {
if (!files || !files.length) {
return false;
}
const names: string[] = [];
// Check if there are 2 files with the same name.
for (let i = 0; i < files.length; i++) {
const file = files[i];
const name = (this.isFileEntry(file) ? file.name : file.filename) || '';
if (names.indexOf(name) > -1) {
return Translate.instant('core.filenameexist', { $a: name });
}
names.push(name);
}
return false;
}
}

View File

@ -83,7 +83,8 @@ export class CoreWindow {
try { try {
await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename }); await CoreFileHelper.showConfirmOpenUnsupportedFile(false, { filename });
} catch { } catch {
return; // Cancelled, stop. // Cancelled, stop.
return;
} }
} }