Delete works
Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
parent
f780fc7c4d
commit
82e5875e52
@ -30,6 +30,12 @@
|
||||
@apply --photo-thumbnail;
|
||||
}
|
||||
|
||||
:host([disabled]) {
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
#info {
|
||||
position: absolute;
|
||||
padding: 0.5em;
|
||||
@ -75,6 +81,9 @@
|
||||
Polymer({
|
||||
is: "photo-thumbnail",
|
||||
properties: {
|
||||
"disabled": {
|
||||
reflectToAttribute: true
|
||||
},
|
||||
"item": {
|
||||
type: Object
|
||||
},
|
||||
|
@ -1222,6 +1222,9 @@
|
||||
if (this.mode == "duplicates") {
|
||||
actions.unshift("text-format");
|
||||
}
|
||||
if (this.mode == "trash") {
|
||||
actions.unshift("undo");
|
||||
}
|
||||
thumbnail.actions = actions;
|
||||
thumbnail.addEventListener("action", this._imageAction.bind(this));
|
||||
}
|
||||
@ -1239,37 +1242,37 @@
|
||||
this.processing = false;
|
||||
},
|
||||
|
||||
_imageAction: function(event) {
|
||||
switch (event.detail) {
|
||||
case "delete": /* Delete image */
|
||||
var thumbnail = event.currentTarget;
|
||||
thumbnail.style.opacity = 0;
|
||||
_removeImageAfterFetch: function(thumbnail, error, xhr) {
|
||||
thumbnail.disabled = false;
|
||||
if (error) {
|
||||
console.log("Unable to take action on photo: " + error);
|
||||
return;
|
||||
}
|
||||
thumbnail.style.pointerEvents = "none";
|
||||
thumbnail.style.opacity = 0;
|
||||
|
||||
this.async(function(thumbnail) {
|
||||
var parent = thumbnail.parentElement;
|
||||
|
||||
for (var i = 0; i < this.thumbnails.length; i++) {
|
||||
if (this.thumbnails[i] == thumbnail) {
|
||||
console.log("Found thumbnail", this.thumbnails.length);
|
||||
var i = this.thumbnails.indexOf(thumbnail);
|
||||
if (i != -1) {
|
||||
if (thumbnail.visible) {
|
||||
console.log("Removing from visible list");
|
||||
thumbnail.visible = false;
|
||||
var j = this.visibleThumbs.indexOf(i);
|
||||
if (j != -1) {
|
||||
console.log("Removing visible thumb", this.visibleThumbs.length);
|
||||
this.visibleThumbs.splice(j, 1);
|
||||
}
|
||||
/* This changes the index of all thumbnails, so invalidate the entire
|
||||
* visibleThumbs list */
|
||||
this.visibleThumbs = [];
|
||||
}
|
||||
this.thumbnails.splice(i, 1);
|
||||
this.notifyPath("thumbnails.length");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Polymer.dom(parent).removeChild(thumbnail);
|
||||
|
||||
if (parent.querySelectorAll("photo-thumbnail").length == 0) {
|
||||
if (parent.querySelectorAll("photo-thumbnail").length != 0) {
|
||||
this.triggerVisibilityChecks();
|
||||
return;
|
||||
}
|
||||
|
||||
/* There are no more thumbnails, so look up the document ancestors
|
||||
* until we find the element with the date-line class, and then
|
||||
* remove it from it's parent */
|
||||
@ -1277,18 +1280,61 @@
|
||||
parent = parent.parentElement;
|
||||
}
|
||||
if (!parent) {
|
||||
this.triggerVisibilityChecks();
|
||||
return;
|
||||
}
|
||||
|
||||
parent.style.opacity = 0;
|
||||
|
||||
this.async(function(parent) {
|
||||
Polymer.dom(this.$.thumbnails).removeChild(parent);
|
||||
this.triggerVisibilityChecks();
|
||||
}.bind(this, parent), 250);
|
||||
} else {
|
||||
this.triggerVisibilityChecks();
|
||||
}
|
||||
}.bind(this, thumbnail), 250);
|
||||
},
|
||||
|
||||
_imageAction: function(event) {
|
||||
switch (event.detail) {
|
||||
case "undo": /* Undelete an image */
|
||||
var thumbnail = event.currentTarget, params = {};
|
||||
thumbnail.disabled = true;
|
||||
|
||||
params.undelete = 1;
|
||||
|
||||
var query = "";
|
||||
for (var key in params) {
|
||||
if (!query) {
|
||||
query = "?";
|
||||
} else {
|
||||
query += "&";
|
||||
}
|
||||
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
|
||||
}
|
||||
window.fetch("api/v1/photos/" + thumbnail.item.id + query,
|
||||
this._removeImageAfterFetch.bind(this, thumbnail), {}, "PUT");
|
||||
break;
|
||||
|
||||
case "delete": /* Delete image */
|
||||
var thumbnail = event.currentTarget, params = {};
|
||||
thumbnail.disabled = true;
|
||||
if (this.mode == "trash") {
|
||||
console.log("TODO: Prompt user 'Are you sure?' ?");
|
||||
params.permanent = 1;
|
||||
}
|
||||
|
||||
var query = "";
|
||||
for (var key in params) {
|
||||
if (!query) {
|
||||
query = "?";
|
||||
} else {
|
||||
query += "&";
|
||||
}
|
||||
query += encodeURIComponent(key) + "=" + encodeURIComponent(params[key]);
|
||||
}
|
||||
window.fetch("api/v1/photos/" + thumbnail.item.id + query,
|
||||
this._removeImageAfterFetch.bind(this, thumbnail), {}, "DELETE");
|
||||
break;
|
||||
|
||||
case "text-format": /* Rename this image */
|
||||
break;
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ const express = require("express"),
|
||||
|
||||
require("./console-line.js"); /* Monkey-patch console.log with line numbers */
|
||||
|
||||
const picturesPath = config.get("picturesPath").replace(/\/$/, ""),
|
||||
const picturesPath = config.get("picturesPath").replace(/\/$/, "") + "/",
|
||||
serverConfig = config.get("server");
|
||||
|
||||
let basePath = config.get("basePath");
|
||||
|
@ -13,6 +13,188 @@ require("../db/photos").then(function(db) {
|
||||
});
|
||||
|
||||
const router = express.Router();
|
||||
const picturesPath = config.get("picturesPath").replace(/\/$/, "") + "/";
|
||||
|
||||
const unlink = function (_path) {
|
||||
if (_path.indexOf(picturesPath.replace(/\/$/, "")) == 0) {
|
||||
_path = _path.substring(picturesPath.length);
|
||||
}
|
||||
|
||||
let path = picturesPath + _path;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.unlink(path, function (error, stats) {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(stats);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
router.put("/:id", function(req, res/*, next*/) {
|
||||
if (!req.user.maintainer) {
|
||||
return res.status(401).send("Unauthorized to delete photos.");
|
||||
}
|
||||
|
||||
const replacements = {
|
||||
id: req.params.id
|
||||
};
|
||||
|
||||
let query = "";
|
||||
|
||||
console.log("PUT /" + replacements.id, req.query);
|
||||
for (let key in req.query) {
|
||||
switch (key) {
|
||||
case "undelete":
|
||||
console.log("Undeleting " + req.params.id);
|
||||
query = "UPDATE photos SET deleted=0 WHERE id=:id";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!query) {
|
||||
return res.status(400).send("Invalid request");
|
||||
}
|
||||
|
||||
return photoDB.sequelize.query(query, {
|
||||
replacements: replacements
|
||||
}).then(function() {
|
||||
return res.status(200).send(req.params.id + " updated.");
|
||||
});
|
||||
});
|
||||
|
||||
router.delete("/:id", function(req, res/*, next*/) {
|
||||
if (!req.user.maintainer) {
|
||||
return res.status(401).send("Unauthorized to delete photos.");
|
||||
}
|
||||
|
||||
const replacements = {
|
||||
id: req.params.id
|
||||
};
|
||||
|
||||
console.log("DELETE /" + replacements.id, req.query);
|
||||
|
||||
return photoDB.sequelize.query("SELECT " +
|
||||
"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 photohashes ON photohashes.photoId=photos.id " +
|
||||
"WHERE photos.id=:id", {
|
||||
replacements: replacements,
|
||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||
raw: true
|
||||
}).then(function(photos) {
|
||||
if (photos.length == 0) {
|
||||
res.status(404).send("Unable to find photo " + req.params.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
const photo = photos[0];
|
||||
if (!req.query.permanent) {
|
||||
return photoDB.sequelize.query("UPDATE photos SET deleted=1 WHERE id=:id", {
|
||||
replacements: replacements
|
||||
}).then(function() {
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/* Delete the asset from disk and the DB
|
||||
* 1. Look if there are duplicates.
|
||||
* 2. Update all other duplicates to be duplicates of the first image that remains
|
||||
* 3. If no duplicates, DELETE the entry from photohashes
|
||||
* 4. If there are duplicates, update the HASH entry to point to the first image that remains
|
||||
* 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", {
|
||||
replacements: photo,
|
||||
type: photoDB.Sequelize.QueryTypes.SELECT,
|
||||
raw: true
|
||||
}).then(function(duplicates) {
|
||||
if (!duplicates.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let first = duplicates.shift();
|
||||
let needsUpdate = [];
|
||||
duplicates.forEach(function(duplicate) {
|
||||
needsUpdate.push(duplicate.id);
|
||||
});
|
||||
|
||||
if (!needsUpdate.length) {
|
||||
return first;
|
||||
}
|
||||
|
||||
// 2. Update all other duplicates to be duplicates of the first image that remains
|
||||
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(
|
||||
"DELETE FROM photohashes WHERE photoId=:photo", {
|
||||
replacements: {
|
||||
photo: photo.id
|
||||
},
|
||||
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 phothashes SET photoId=:first WHERE photoId=:photo", {
|
||||
replacements: {
|
||||
first: first.id,
|
||||
photo: photo.id
|
||||
},
|
||||
transaction: transaction
|
||||
});
|
||||
}).then(function() {
|
||||
console.log("Deleting " + photo.path + photo.filename + " from DB.");
|
||||
// 5. Delete the entry from photos
|
||||
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).then(function() {
|
||||
return unlink(photo.path + "thumbs/" + photo.filename).then(function() {
|
||||
return unlink(photo.path + photo.filename);
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(function() {
|
||||
return false;
|
||||
});
|
||||
}).then(function(sent) {
|
||||
if (sent) {
|
||||
return;
|
||||
}
|
||||
|
||||
return res.status(200).send({
|
||||
id: req.params.id,
|
||||
deleted: true,
|
||||
permanent: (req.query && req.query.permanent) || false
|
||||
});
|
||||
}).catch(function(error) {
|
||||
console.log(error);
|
||||
return res.status(500).send("Unable to delete photo " + req.params.id + ": " + error);
|
||||
});
|
||||
});
|
||||
|
||||
/* Each photos has:
|
||||
|
||||
|
@ -225,7 +225,9 @@ function processBlock(items) {
|
||||
setStatus("Duplicate asset: " +
|
||||
"'" + asset.album.path + asset.filename + "' is a copy of " +
|
||||
"'" + results[0].path + results[0].filename + "'");
|
||||
if (asset.duplicate != results[0].photoId) {
|
||||
duplicates.push(asset);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -394,22 +396,14 @@ function processBlock(items) {
|
||||
throw error;
|
||||
}).then(function() {
|
||||
setStatus("Completed processing queue. Marking " + duplicates.length + " duplicates.");
|
||||
let dups = [];
|
||||
duplicates.forEach(function(asset) {
|
||||
/* If not already marked as a duplicate, mark it. */
|
||||
if (!asset.duplicate) {
|
||||
dups.push(asset.id);
|
||||
}
|
||||
return photoDB.sequelize.transaction(function(transaction) {
|
||||
return Promise.mapSeries(duplicates, function(asset) {
|
||||
return photoDB.sequelize.query("UPDATE photos " +
|
||||
"SET duplicate=:duplicate,modified=CURRENT_TIMESTAMP,scanned=CURRENT_TIMESTAMP WHERE id=:id", {
|
||||
replacements: asset,
|
||||
transaction: transaction
|
||||
});
|
||||
});
|
||||
|
||||
if (dups.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return photoDB.sequelize.query("UPDATE photos SET duplicate=1,modified=CURRENT_TIMESTAMP,scanned=CURRENT_TIMESTAMP WHERE id IN (:dups)", {
|
||||
replacements: {
|
||||
dups: dups
|
||||
}
|
||||
});
|
||||
}).then(function() {
|
||||
setStatus("Looking for removed assets");
|
||||
|
Loading…
x
Reference in New Issue
Block a user