Implemented purge trash
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
6655677605
commit
2b2af1d965
@ -335,8 +335,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div hidden$="[[!user.maintainer]]" id="trash" class="flex layout vertical">
|
<div hidden$="[[!user.maintainer]]" id="trash" class="flex layout vertical">
|
||||||
<div><b>Trash</b></div>
|
<div><b>Trash</b></div>
|
||||||
<div>There are <b>[[add(thumbnails.length,pendingPhotos.length)]]</b> photos in the trash.</div>
|
<div>
|
||||||
<div>Do you want to purge the trash?</div>
|
<p>There are <b>[[add(thumbnails.length,pendingPhotos.length)]]</b> photos in the trash.</p>
|
||||||
|
<p>Files in the trash will be removed after 60 days.</p></div>
|
||||||
|
<div hidden$="[[!add(thumbnails.length,pendingPhotos.length)]]" class="layout vertical">
|
||||||
|
<div>Do you want to empty the trash now?</div>
|
||||||
|
<paper-button on-tap="purgeTrashAction">empty trash</paper-button>
|
||||||
|
<div><p><b>NOTE:</b> This can not be undone.</p></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div hidden$="[[!user.maintainer]]" id="duplicates" class="flex layout vertical">
|
<div hidden$="[[!user.maintainer]]" id="duplicates" class="flex layout vertical">
|
||||||
<div><b>Duplicate names</b></div>
|
<div><b>Duplicate names</b></div>
|
||||||
@ -1421,6 +1427,22 @@
|
|||||||
}.bind(this, thumbnail), {}, "PUT");
|
}.bind(this, thumbnail), {}, "PUT");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
purgeTrashAction: function() {
|
||||||
|
var query = "";
|
||||||
|
if (this.mode == "trash") {
|
||||||
|
console.log("TODO: Prompt user 'Are you sure?' ?");
|
||||||
|
query = "?permanent=1";
|
||||||
|
}
|
||||||
|
window.fetch("api/v1/photos/" + query, function(error) {
|
||||||
|
if (error) {
|
||||||
|
console.log("Unable to take action on photo: " + error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetPhotos();
|
||||||
|
}.bind(this), {}, "DELETE");
|
||||||
|
},
|
||||||
|
|
||||||
deleteAction: function(thumbnail) {
|
deleteAction: function(thumbnail) {
|
||||||
thumbnail.disabled = true;
|
thumbnail.disabled = true;
|
||||||
var query = "";
|
var query = "";
|
||||||
|
@ -5,7 +5,8 @@ const express = require("express"),
|
|||||||
config = require("config"),
|
config = require("config"),
|
||||||
moment = require("moment"),
|
moment = require("moment"),
|
||||||
crypto = require("crypto"),
|
crypto = require("crypto"),
|
||||||
util = require("util");
|
util = require("util"),
|
||||||
|
Promise = require("bluebird");
|
||||||
|
|
||||||
const execFile = util.promisify(require("child_process").execFile);
|
const execFile = util.promisify(require("child_process").execFile);
|
||||||
|
|
||||||
@ -314,32 +315,45 @@ const getPhoto = function(id) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
router.delete("/:id", function(req, res/*, next*/) {
|
router.delete("/:id?", function(req, res/*, next*/) {
|
||||||
if (!req.user.maintainer) {
|
if (!req.user.maintainer) {
|
||||||
return res.status(401).send("Unauthorized to delete photos.");
|
return res.status(401).send("Unauthorized to delete photos.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const replacements = {
|
const replacements = {
|
||||||
id: req.params.id
|
id: req.params.id || "*"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!req.params.id && !req.query.permanent) {
|
||||||
|
return res.status(400).send("Trash can only be emptied if permanent.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let where = "";
|
||||||
|
if (req.params.id) {
|
||||||
|
where = "photos.id=:id";
|
||||||
|
if (req.query.permanent) {
|
||||||
|
where += " AND photos.deleted=1";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
where = "photos.deleted=1";
|
||||||
|
}
|
||||||
|
|
||||||
console.log("DELETE /" + replacements.id, req.query);
|
console.log("DELETE /" + replacements.id, req.query);
|
||||||
|
|
||||||
return photoDB.sequelize.query("SELECT " +
|
return photoDB.sequelize.query("SELECT " +
|
||||||
"photos.*,albums.path AS path,photohashes.hash,(albums.path || photos.filename) AS filepath FROM photos " +
|
"photos.*,albums.path AS path,photohashes.hash,(albums.path || photos.filename) AS filepath FROM photos " +
|
||||||
"LEFT JOIN albums ON albums.id=photos.albumId " +
|
"LEFT JOIN albums ON albums.id=photos.albumId " +
|
||||||
"LEFT JOIN photohashes ON photohashes.photoId=photos.id " +
|
"LEFT JOIN photohashes ON photohashes.photoId=photos.id " +
|
||||||
"WHERE photos.id=:id", {
|
"WHERE " + where, {
|
||||||
replacements: replacements,
|
replacements: replacements,
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
raw: true
|
raw: true
|
||||||
}).then(function(photos) {
|
}).then(function(photos) {
|
||||||
if (photos.length == 0) {
|
if (photos.length == 0) {
|
||||||
res.status(404).send("Unable to find photo " + req.params.id);
|
res.status(404).send("Unable to find photo " + replacements.id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const photo = photos[0];
|
|
||||||
if (!req.query.permanent) {
|
if (!req.query.permanent) {
|
||||||
return photoDB.sequelize.query("UPDATE photos SET deleted=1,updated=CURRENT_TIMESTAMP WHERE id=:id", {
|
return photoDB.sequelize.query("UPDATE photos SET deleted=1,updated=CURRENT_TIMESTAMP WHERE id=:id", {
|
||||||
replacements: replacements
|
replacements: replacements
|
||||||
@ -348,82 +362,83 @@ router.delete("/:id", function(req, res/*, next*/) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Delete the asset from disk and the DB
|
/**
|
||||||
* 1. Look if there are duplicates.
|
* Delete the asset from disk and the DB
|
||||||
* 2. Update all other duplicates to be duplicates of the first image that remains
|
* 1. Look if there are duplicates.
|
||||||
* 3. If no duplicates, DELETE the entry from photohashes
|
* 2. Update all other duplicates to be duplicates of the first image that remains
|
||||||
* 4. If there are duplicates, update the HASH entry to point to the first image that remains
|
* 3. If no duplicates, DELETE the entry from photohashes
|
||||||
* 5. Delete the entry from photos
|
* 4. If there are duplicates, update the HASH entry to point to the first image that remains
|
||||||
* 6. Delete the scaled, thumb, and original from disk
|
* 5. Delete the entry from photos
|
||||||
*/
|
* 6. Delete the scaled, thumb, and original from disk
|
||||||
return photoDB.sequelize.transaction(function(transaction) {
|
*/
|
||||||
return photoDB.sequelize.query("SELECT id FROM photos WHERE duplicate=:id", {
|
return Promise.mapSeries(photos, function(photo) {
|
||||||
replacements: photo,
|
return photoDB.sequelize.transaction(function(transaction) {
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
return photoDB.sequelize.query("SELECT id FROM photos WHERE duplicate=:id", {
|
||||||
raw: true
|
replacements: photo,
|
||||||
}).then(function(duplicates) {
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
if (!duplicates.length) {
|
raw: true
|
||||||
return null;
|
}).then(function(duplicates) {
|
||||||
}
|
if (!duplicates.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let first = duplicates.shift();
|
let first = duplicates.shift();
|
||||||
let needsUpdate = [];
|
let needsUpdate = [];
|
||||||
duplicates.forEach(function(duplicate) {
|
duplicates.forEach(function(duplicate) {
|
||||||
needsUpdate.push(duplicate.id);
|
needsUpdate.push(duplicate.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!needsUpdate.length) {
|
if (!needsUpdate.length) {
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Update all other duplicates to be duplicates of the first image that remains
|
// 2. Update all other duplicates to be duplicates of the first image that remains
|
||||||
console.log("Updating " + needsUpdate + " to point to " + first.id);
|
console.log("Updating " + needsUpdate + " to point to " + first.id);
|
||||||
return photoDB.sequelize.query(
|
|
||||||
"UPDATE photos SET duplicate=:first WHERE id IN (:needsUpdate)", {
|
|
||||||
replacements: {
|
|
||||||
first: first.id,
|
|
||||||
needsUpdate: needsUpdate
|
|
||||||
},
|
|
||||||
transaction: transaction
|
|
||||||
}).then(function() {
|
|
||||||
return first;
|
|
||||||
});
|
|
||||||
}).then(function(first) {
|
|
||||||
if (!first) {
|
|
||||||
console.log("Deleting "+ photo.id + " from photohash.");
|
|
||||||
// 3. If no duplicates, DELETE the entry from photohashes
|
|
||||||
return photoDB.sequelize.query(
|
return photoDB.sequelize.query(
|
||||||
"DELETE FROM photohashes WHERE photoId=:photo", {
|
"UPDATE photos SET duplicate=:first WHERE id IN (:needsUpdate)", {
|
||||||
replacements: {
|
replacements: {
|
||||||
|
first: first.id,
|
||||||
|
needsUpdate: needsUpdate
|
||||||
|
},
|
||||||
|
transaction: transaction
|
||||||
|
}).then(function() {
|
||||||
|
return first;
|
||||||
|
});
|
||||||
|
}).then(function(first) {
|
||||||
|
if (!first) {
|
||||||
|
console.log("Deleting "+ photo.id + " from photohash.");
|
||||||
|
// 3. If no duplicates, DELETE the entry from photohashes
|
||||||
|
return photoDB.sequelize.query(
|
||||||
|
"DELETE FROM photohashes WHERE photoId=:id", {
|
||||||
|
replacements: photo,
|
||||||
|
transaction: transaction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log("Updating photohash for " + photo.id + " to point to " + first.id);
|
||||||
|
// 4. If there are duplicates, update the HASH entry to point to the first image that remains
|
||||||
|
return photoDB.sequelize.query(
|
||||||
|
"UPDATE photohashes SET photoId=:first WHERE photoId=:photo", {
|
||||||
|
replacements: {
|
||||||
|
first: first.id,
|
||||||
photo: photo.id
|
photo: photo.id
|
||||||
},
|
},
|
||||||
transaction: transaction
|
transaction: transaction
|
||||||
});
|
});
|
||||||
}
|
}).then(function() {
|
||||||
console.log("Updating photohash for " + photo.id + " to point to " + first.id);
|
console.log("Deleting " + photo.path + photo.filename + " from DB.");
|
||||||
// 4. If there are duplicates, update the HASH entry to point to the first image that remains
|
// 5. Delete the entry from photos
|
||||||
return photoDB.sequelize.query(
|
return photoDB.sequelize.query("DELETE FROM photos WHERE id=:id", {
|
||||||
"UPDATE photohashes SET photoId=:first WHERE photoId=:photo", {
|
replacements: photo,
|
||||||
replacements: {
|
transaction: transaction
|
||||||
first: first.id,
|
});
|
||||||
photo: photo.id
|
}).then(function() {
|
||||||
},
|
// 6. Delete the scaled, thumb, and original from disk
|
||||||
transaction: transaction
|
console.log("Deleting " + photo.path + photo.filename + " from disk.");
|
||||||
});
|
return unlink(photo.path + "thumbs/scaled/" + photo.filename).catch(function() {}).then(function() {
|
||||||
}).then(function() {
|
return unlink(photo.path + "thumbs/" + photo.filename).catch(function() {}).then(function() {
|
||||||
console.log("Deleting " + photo.path + photo.filename + " from DB.");
|
return unlink(photo.path + photo.filename).catch(function(error) {
|
||||||
// 5. Delete the entry from photos
|
console.log("Error removing file: " + error);
|
||||||
return photoDB.sequelize.query("DELETE FROM photos WHERE id=:id", {
|
});
|
||||||
replacements: replacements,
|
|
||||||
transaction: transaction
|
|
||||||
});
|
|
||||||
}).then(function() {
|
|
||||||
// 6. Delete the scaled, thumb, and original from disk
|
|
||||||
console.log("Deleting " + photo.path + photo.filename + " from disk.");
|
|
||||||
return unlink(photo.path + "thumbs/scaled/" + photo.filename).catch(function() {}).then(function() {
|
|
||||||
return unlink(photo.path + "thumbs/" + photo.filename).catch(function() {}).then(function() {
|
|
||||||
return unlink(photo.path + photo.filename).catch(function(error) {
|
|
||||||
console.log("Error removing file: " + error);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -565,7 +580,7 @@ router.get("/trash", function(req, res/*, next*/) {
|
|||||||
return photoDB.sequelize.query(
|
return photoDB.sequelize.query(
|
||||||
"SELECT photos.*,albums.path AS path,(albums.path || photos.filename) AS filepath FROM photos " +
|
"SELECT photos.*,albums.path AS path,(albums.path || photos.filename) AS filepath FROM photos " +
|
||||||
"LEFT JOIN albums ON albums.id=photos.albumId " +
|
"LEFT JOIN albums ON albums.id=photos.albumId " +
|
||||||
"WHERE deleted=1 ORDER BY photos.updated", {
|
"WHERE deleted=1 ORDER BY photos.updated DESC", {
|
||||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||||
raw: true
|
raw: true
|
||||||
}).then(function(photos) {
|
}).then(function(photos) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user