Implemented purge trash

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-10-23 19:43:19 -07:00
parent 6655677605
commit 2b2af1d965
2 changed files with 114 additions and 77 deletions

View File

@ -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 = "";

View File

@ -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,7 +362,8 @@ router.delete("/:id", function(req, res/*, next*/) {
}); });
} }
/* Delete the asset from disk and the DB /**
* Delete the asset from disk and the DB
* 1. Look if there are duplicates. * 1. Look if there are duplicates.
* 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
* 3. If no duplicates, DELETE the entry from photohashes * 3. If no duplicates, DELETE the entry from photohashes
@ -356,6 +371,7 @@ router.delete("/:id", function(req, res/*, next*/) {
* 5. Delete the entry from photos * 5. Delete the entry from photos
* 6. Delete the scaled, thumb, and original from disk * 6. Delete the scaled, thumb, and original from disk
*/ */
return Promise.mapSeries(photos, function(photo) {
return photoDB.sequelize.transaction(function(transaction) { return photoDB.sequelize.transaction(function(transaction) {
return photoDB.sequelize.query("SELECT id FROM photos WHERE duplicate=:id", { return photoDB.sequelize.query("SELECT id FROM photos WHERE duplicate=:id", {
replacements: photo, replacements: photo,
@ -393,10 +409,8 @@ router.delete("/:id", function(req, res/*, next*/) {
console.log("Deleting "+ photo.id + " from photohash."); console.log("Deleting "+ photo.id + " from photohash.");
// 3. If no duplicates, DELETE the entry from photohashes // 3. If no duplicates, DELETE the entry from photohashes
return photoDB.sequelize.query( return photoDB.sequelize.query(
"DELETE FROM photohashes WHERE photoId=:photo", { "DELETE FROM photohashes WHERE photoId=:id", {
replacements: { replacements: photo,
photo: photo.id
},
transaction: transaction transaction: transaction
}); });
} }
@ -414,7 +428,7 @@ router.delete("/:id", function(req, res/*, next*/) {
console.log("Deleting " + photo.path + photo.filename + " from DB."); console.log("Deleting " + photo.path + photo.filename + " from DB.");
// 5. Delete the entry from photos // 5. Delete the entry from photos
return photoDB.sequelize.query("DELETE FROM photos WHERE id=:id", { return photoDB.sequelize.query("DELETE FROM photos WHERE id=:id", {
replacements: replacements, replacements: photo,
transaction: transaction transaction: transaction
}); });
}).then(function() { }).then(function() {
@ -428,6 +442,7 @@ router.delete("/:id", function(req, res/*, next*/) {
}); });
}); });
}); });
});
}).then(function() { }).then(function() {
return false; return false;
}); });
@ -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) {