diff --git a/client/scripts/actions/TorrentActions.js b/client/scripts/actions/TorrentActions.js
index fc81017a..351a78c3 100644
--- a/client/scripts/actions/TorrentActions.js
+++ b/client/scripts/actions/TorrentActions.js
@@ -54,8 +54,8 @@ const TorrentActions = {
});
},
- deleteTorrents: (hash) => {
- return axios.post('/api/client/torrents/delete', {hash})
+ deleteTorrents: (hash, deleteData) => {
+ return axios.post('/api/client/torrents/delete', {hash, deleteData})
.then((json = {}) => {
return json.data;
})
@@ -64,7 +64,8 @@ const TorrentActions = {
type: ActionTypes.CLIENT_REMOVE_TORRENT_SUCCESS,
data: {
data,
- count: hash.length
+ count: hash.length,
+ deleteData
}
});
})
diff --git a/client/scripts/components/Modals/RemoveTorrentsModal/index.js b/client/scripts/components/Modals/RemoveTorrentsModal/index.js
new file mode 100644
index 00000000..a62bae09
--- /dev/null
+++ b/client/scripts/components/Modals/RemoveTorrentsModal/index.js
@@ -0,0 +1,140 @@
+import _ from 'lodash';
+import classnames from 'classnames';
+import {formatMessage, FormattedMessage, injectIntl} from 'react-intl';
+import React from 'react';
+
+import Checkbox from '../../General/FormElements/Checkbox';
+import Modal from '../Modal';
+import SettingsStore from '../../../stores/SettingsStore';
+import stringUtil from '../../../../../shared/util/stringUtil';
+import TorrentActions from '../../../actions/TorrentActions';
+import TorrentStore from '../../../stores/TorrentStore';
+
+const METHODS_TO_BIND = [
+ 'handleRemovalConfirmation',
+ 'handleCheckboxChange'
+];
+
+class RemoveTorrentsModal extends React.Component {
+ constructor() {
+ super();
+
+ this.state = {
+ deleteData: SettingsStore.getFloodSettings('deleteTorrentData')
+ };
+
+ METHODS_TO_BIND.forEach((method) => {
+ this[method] = this[method].bind(this);
+ });
+ }
+
+ getActions(torrents) {
+ if (torrents.length === 0) {
+ return [
+ {
+ clickHandler: null,
+ content: 'OK',
+ triggerDismiss: true,
+ type: 'primary'
+ }
+ ];
+ }
+
+ return [
+ {
+ clickHandler: this.handleRemoveTorrentDecline,
+ content: this.props.intl.formatMessage({
+ id: 'button.no',
+ defaultMessage: 'No'
+ }),
+ triggerDismiss: true,
+ type: 'secondary'
+ },
+ {
+ clickHandler: this.handleRemovalConfirmation.bind(this, torrents),
+ content: this.props.intl.formatMessage({
+ id: 'button.yes',
+ defaultMessage: 'Yes'
+ }),
+ triggerDismiss: true,
+ type: 'primary'
+ }
+ ];
+ }
+
+ getContent(torrents) {
+ let modalContent = null;
+ let deleteDataContent = null;
+ let selectedTorrentCount = torrents.length;
+
+ if (selectedTorrentCount === 0) {
+ modalContent = this.props.intl.formatMessage({
+ id: 'torrents.remove.error.no.torrents.selected',
+ defaultMessage: 'You haven\'t selected any torrents.'
+ });
+ } else {
+ let torrentText = stringUtil.pluralize('torrent', selectedTorrentCount);
+ modalContent = this.props.intl.formatMessage({
+ id: 'torrents.remove.are.you.sure',
+ defaultMessage: `Are you sure you want to remove {count, plural,
+ =0 {no torrents}
+ =1 {one torrent}
+ other {# torrents}
+ }?`
+ }, {
+ count: selectedTorrentCount
+ });
+
+ deleteDataContent = (
+
+ );
+ }
+
+ return (
+
+
+ {deleteDataContent}
+
+ );
+ }
+
+ handleCheckboxChange(checkboxState) {
+ this.setState({deleteData: checkboxState});
+ }
+
+ handleRemovalConfirmation(torrents) {
+ TorrentActions.deleteTorrents(torrents, this.state.deleteData);
+ }
+
+ render() {
+ let selectedTorrents = TorrentStore.getSelectedTorrents() || [];
+ let modalHeading = this.props.intl.formatMessage({
+ id: 'torrents.remove',
+ defaultMessage: 'Remove Torrents'
+ });
+
+ return (
+
+ );
+ }
+}
+
+export default injectIntl(RemoveTorrentsModal);
diff --git a/client/scripts/components/Modals/index.js b/client/scripts/components/Modals/index.js
index 911e9846..fb3fc1d9 100644
--- a/client/scripts/components/Modals/index.js
+++ b/client/scripts/components/Modals/index.js
@@ -7,6 +7,7 @@ import ConfirmModal from './ConfirmModal';
import EventTypes from '../../constants/EventTypes';
import Modal from './Modal';
import MoveTorrentsModal from './MoveTorrentsModal';
+import RemoveTorrentsModal from './RemoveTorrentsModal';
import SetTagsModal from './SetTagsModal';
import SettingsModal from './SettingsModal';
import TorrentDetailsModal from './TorrentDetailsModal';
@@ -27,6 +28,7 @@ export default class Modals extends React.Component {
'add-torrents': AddTorrentsModal,
confirm: ConfirmModal,
'move-torrents': MoveTorrentsModal,
+ 'remove-torrents': RemoveTorrentsModal,
'set-taxonomy': SetTagsModal,
settings: SettingsModal,
'torrent-details': TorrentDetailsModal
diff --git a/client/scripts/components/TorrentList/ActionBar.js b/client/scripts/components/TorrentList/ActionBar.js
index aced09a3..a944269f 100644
--- a/client/scripts/components/TorrentList/ActionBar.js
+++ b/client/scripts/components/TorrentList/ActionBar.js
@@ -51,71 +51,9 @@ class ActionBar extends React.Component {
UIActions.displayModal({id: 'add-torrents'});
}
- handleRemoveTorrentConfirm(torrents) {
- TorrentActions.deleteTorrents(torrents);
- }
-
handleRemoveTorrents() {
- let selectedTorrents = TorrentStore.getSelectedTorrents() || [];
- let selectedTorrentCount = selectedTorrents.length;
-
- let actions = [
- {
- clickHandler: this.handleRemoveTorrentDecline,
- content: this.props.intl.formatMessage({
- id: 'button.no',
- defaultMessage: 'No'
- }),
- triggerDismiss: true,
- type: 'secondary'
- },
- {
- clickHandler: this.handleRemoveTorrentConfirm.bind(this, selectedTorrents),
- content: this.props.intl.formatMessage({
- id: 'button.yes',
- defaultMessage: 'Yes'
- }),
- triggerDismiss: true,
- type: 'primary'
- }
- ];
-
- let content = this.props.intl.formatMessage({
- id: 'torrents.remove.are.you.sure',
- defaultMessage: `Are you sure you want to remove {count, plural,
- =0 {no torrents}
- =1 {one torrent}
- other {# torrents}
- }?`
- }, {
- count: selectedTorrentCount
- });
-
- if (selectedTorrentCount === 0) {
- actions = [
- {
- clickHandler: null,
- content: 'OK',
- triggerDismiss: true,
- type: 'primary'
- }
- ];
- content = this.props.intl.formatMessage({
- id: 'torrents.remove.error.no.torrents.selected',
- defaultMessage: 'You haven\'t selected any torrents.'
- });
- }
-
UIActions.displayModal({
- id: 'confirm',
- options: {
- actions,
- content,
- heading: this.props.intl.formatMessage({
- id: 'torrents.remove',
- defaultMessage: 'Remove Torrents'
- })
- }
+ id: 'remove-torrents'
});
}
@@ -165,7 +103,6 @@ class ActionBar extends React.Component {
);
}
-
}
export default injectIntl(ActionBar);
diff --git a/client/scripts/components/TorrentList/index.js b/client/scripts/components/TorrentList/index.js
index 4a35948d..22dfe1fb 100644
--- a/client/scripts/components/TorrentList/index.js
+++ b/client/scripts/components/TorrentList/index.js
@@ -188,7 +188,7 @@ class TorrentListContainer extends React.Component {
TorrentActions.pauseTorrents(selectedTorrents);
break;
case 'remove':
- TorrentActions.deleteTorrents(selectedTorrents);
+ UIActions.displayModal({id: 'remove-torrents'});
break;
case 'move':
UIActions.displayModal({id: 'move-torrents'});
diff --git a/client/scripts/i18n/en.js b/client/scripts/i18n/en.js
index 8e0ba307..5d413136 100644
--- a/client/scripts/i18n/en.js
+++ b/client/scripts/i18n/en.js
@@ -203,6 +203,7 @@ export default {
=1 {one torrent}
other {# torrents}
}?`,
+ 'torrents.remove.delete.data': 'Delete data',
'torrents.remove.error.no.torrents.selected': 'You haven\'t selected any torrents.',
'torrents.remove': 'Remove Torrents'
};
diff --git a/client/scripts/stores/TorrentStore.js b/client/scripts/stores/TorrentStore.js
index 4531e4f5..6f53540e 100644
--- a/client/scripts/stores/TorrentStore.js
+++ b/client/scripts/stores/TorrentStore.js
@@ -198,6 +198,11 @@ class TorrentStoreClass extends BaseStore {
}
handleRemoveTorrentsSuccess(response) {
+ SettingsStore.saveFloodSettings({
+ id: 'deleteTorrentData',
+ data: response.deleteData
+ });
+
NotificationStore.add({
accumulation: {
id: 'notification.torrent.remove',
diff --git a/package.json b/package.json
index aeb0bb8c..e56436ee 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"cookie-parser": "^1.4.3",
"d3": "^3.5.6",
"debug": "^2.2.0",
+ "del": "^2.2.1",
"es6-promise": "^3.2.1",
"events": "^1.1.0",
"express": "^4.14.0",
diff --git a/server/models/ClientRequest.js b/server/models/ClientRequest.js
index 4625c3a5..4bb97a18 100644
--- a/server/models/ClientRequest.js
+++ b/server/models/ClientRequest.js
@@ -1,6 +1,5 @@
'use strict';
-let fs = require('fs');
let mv = require('mv');
let path = require('path');
let util = require('util');
diff --git a/server/models/Torrent.js b/server/models/Torrent.js
index 9198c1f0..1ce5a1f0 100644
--- a/server/models/Torrent.js
+++ b/server/models/Torrent.js
@@ -61,6 +61,10 @@ class Torrent {
this._torrentData = this.getCalculatedClientData(clientData, opts);
}
+ get basePath() {
+ return this._torrentData.basePath;
+ }
+
get data() {
// TODO: Only return the properties that are different than the last time
// get was called. Perhaps identify the last time it was called by ID so
diff --git a/server/models/client.js b/server/models/client.js
index d042c806..3503fd5f 100644
--- a/server/models/client.js
+++ b/server/models/client.js
@@ -1,6 +1,6 @@
'use strict';
-let fs = require('fs');
+let del = require('del');
let util = require('util');
let clientResponseUtil = require('../util/clientResponseUtil');
@@ -64,11 +64,34 @@ var client = {
request.send();
},
- deleteTorrents: (hashes, callback) => {
+ deleteTorrents: (options, callback) => {
+ let files = [];
let request = new ClientRequest();
- request.add('removeTorrents', {hashes});
- request.onComplete(callback);
+ if (options.deleteData) {
+ let torrents = torrentCollection.torrents;
+
+ files = options.hashes.reduce((memo, hash) => {
+ let filePath = torrents[hash].basePath;
+
+ // Let's not try to delete these files.
+ if (filePath != null && filePath !== '/' && filePath !== ''
+ && filePath !== '.') {
+ memo.push(filePath);
+ }
+
+ return memo;
+ }, []);
+ }
+
+ request.add('removeTorrents', {hashes: options.hashes});
+ request.onComplete((response, error) => {
+ if (options.deleteData && files.length > 0) {
+ del(files, {force: true});
+ }
+
+ callback(response, error);
+ });
request.send();
},
diff --git a/server/routes/client.js b/server/routes/client.js
index 6f0b00ff..4db6562a 100644
--- a/server/routes/client.js
+++ b/server/routes/client.js
@@ -69,7 +69,10 @@ router.post('/torrents/move', function(req, res, next) {
});
router.post('/torrents/delete', function(req, res, next) {
- client.deleteTorrents(req.body.hash, ajaxUtil.getResponseFn(res));
+ let deleteData = req.body.deleteData;
+ let hashes = req.body.hash;
+
+ client.deleteTorrents({hashes, deleteData}, ajaxUtil.getResponseFn(res));
});
router.get('/torrents/taxonomy', function(req, res, next) {