diff --git a/client/src/modules/contentmanager.js b/client/src/modules/contentmanager.js index 3a8aa4c6..2022fde9 100644 --- a/client/src/modules/contentmanager.js +++ b/client/src/modules/contentmanager.js @@ -256,6 +256,36 @@ export default class { } } + /** + * Delete content. + * @param {Content|String} content Content to delete + * @param {Boolean} force If true the content will be deleted even if an exception is thrown when disabling/unloading/deleting + */ + static async deleteContent(content, force) { + content = this.findContent(content); + if (!content) throw {message: `Could not find a ${this.contentType} from ${content}.`}; + + try { + await Modals.confirm(`Delete ${this.contentType} ?`, `Are you sure you want to delete ${content.info.name} ?`, 'Delete').promise; + } catch (err) { + return false; + } + + try { + const unload = this.unloadContent(content, force, false); + + if (!force) + await unload; + + await FileUtils.directoryExists(content.paths.contentPath); + FileUtils.deleteDirectory(content.paths.contentPath); + return true; + } catch (err) { + Logger.err(this.moduleName, err); + throw err; + } + } + /** * Unload content. * @param {Content|String} content Content to unload diff --git a/client/src/modules/pluginmanager.js b/client/src/modules/pluginmanager.js index c18c6aaa..bcc93e32 100644 --- a/client/src/modules/pluginmanager.js +++ b/client/src/modules/pluginmanager.js @@ -124,6 +124,7 @@ export default class extends ContentManager { return instance; } + static get deletePlugin() { return this.deleteContent } static get unloadPlugin() { return this.unloadContent } static get reloadPlugin() { return this.reloadContent } diff --git a/client/src/modules/thememanager.js b/client/src/modules/thememanager.js index 1a1b5811..3ed2b3f7 100644 --- a/client/src/modules/thememanager.js +++ b/client/src/modules/thememanager.js @@ -53,6 +53,7 @@ export default class ThemeManager extends ContentManager { } } + static get deleteTheme() { return this.deleteContent } static get unloadTheme() { return this.unloadContent } static async reloadTheme(theme) { theme = await this.reloadContent(theme); diff --git a/common/modules/utils.js b/common/modules/utils.js index fca6d957..a28b49f2 100644 --- a/common/modules/utils.js +++ b/common/modules/utils.js @@ -11,6 +11,7 @@ import fs from 'fs'; import _ from 'lodash'; import filetype from 'file-type'; +import { join as pathJoin } from 'path'; export class Utils { static overload(fn, cb) { @@ -493,4 +494,32 @@ export class FileUtils { if (!type) type = (await this.getFileType(buffer)).mime; return `data:${type};base64,${buffer.toString('base64')}`; } + + /** + * Delete a directory + * @param {String} path The directory's path + * @return {Promise} + */ + static async deleteDirectory(path) { + try { + await this.directoryExists(path); + const files = await this.listDirectory(path); + + for (const file of files) { + const pathToFile = pathJoin(path, file); + try { + await this.directoryExists(pathToFile); + await this.deleteDirectory(pathToFile); + } catch (err) { + fs.unlinkSync(pathToFile); + } + } + + fs.rmdirSync(path); + + return true; + } catch (err) { + throw err; + } + } }