"use strict"; const express = require("express"), config = require("config"), crypto = require("crypto"), Promise = require("bluebird"); let photoDB; require("../db/photos").then(function(db) { photoDB = db; }); const router = express.Router(); const picturesPath = config.get("picturesPath").replace(/\/$/, "") + "/"; router.put("/:id?", async (req, res/*, next*/) => { console.log(`PUT ${req.url}`); if (!req.user.maintainer) { return res.status(401).json({ message: "Unauthorized to modify photos."}); } let { id } = req.params, faces = []; if (id && isNaN(+id)) { return res.status(400).json({message: `Invalid id ${id}`}); } else { if (id) { faces = [ +id ]; } else { faces = req.body.faces; } } if (faces.length === 0) { return res.status(400).json({message: `No faces supplied.`}); } const { action } = req.body; console.log(`${action}: ${faces}`); switch (action) { case 'not-a-face': await photoDB.sequelize.query( `UPDATE faces SET classifiedBy='not-a-face',identityId=NULL ` + `WHERE id IN (:faces)`, { replacements: { faces } } ); /* faces = await photoDB.sequelize.query( 'SELECT * FROM faces WHERE id IN (:faces)', { replacements: { faces }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true } ); faces.forEach(face => { face.faceId = face.id; delete face.id; }); */ return res.status(200).json(faces); } return res.status(400).json({ message: "Invalid request" }); }); router.delete("/:id", function(req, res/*, next*/) { console.log(`DELETE /${req.params.id}`); if (!req.user.maintainer) { return res.status(401).send("Unauthorized to delete photos."); } return photoDB.sequelize.query("UPDATE faces SET faceConfidence=0 WHERE id=:id", { replacements: { id: req.params.id } }).then(() => { return res.status(200).send({ message: `${req.params.id} deleted` }); }).catch((error) => { return res.status(500).send({ error: error }); }) }); function getFacesForPhoto(id) { /* Get the set of faces in this photo */ return photoDB.sequelize.query( "SELECT * FROM faces WHERE photoId=:id AND faceConfidence>0.9", { replacements: { id: id, }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }).then((faces) => { /* For each face in the photo, get the related faces */ return photoDB.sequelize.query( "SELECT relatedFaces.photoId AS photoId,fd.descriptor1Id,fd.descriptor2Id,fd.distanceCosine,relatedFaces.faceConfidence " + "FROM (SELECT id,photoId,faceConfidence FROM faces WHERE faces.faceConfidence>=0.9 AND faces.id IN (:ids)) AS faces " + "INNER JOIN faces AS relatedFaces ON relatedFaces.faceConfidence>=0.9 AND relatedFaces.id IN (fd.descriptor1Id,fd.descriptor2Id) " + "INNER JOIN facedistances AS fd ON fd.distanceCosine<=0.5 " + " AND (fd.descriptor1Id=faces.id OR fd.descriptor2Id=faces.id) " + "WHERE (faces.id=fd.descriptor1Id OR faces.id=fd.descriptor2Id) " + "ORDER BY fd.distanceCosine ASC", { replacements: { ids: faces.map(face => face.id), }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }).then((relatedFaces) => { faces.forEach((face) => { face.relatedFaces = relatedFaces.filter((related) => { return (related.photoId != id && (related.descriptor1Id == face.id || related.descriptor2Id == face.id)); }).map((related) => { return { distanceCosine: related.distanceCosine, faceConfidence: related.faceConfidence, photoId: related.photoId, faceId: related.descriptor1Id != face.id ? related.descriptor1Id : related.descriptor2Id } }); }); return faces; }); }); } router.get("/:id?", (req, res) => { let id; if (req.params.id) { id = parseInt(req.params.id); if (id != req.params.id) { return res.status(400).send({ message: "Usage /[id]"}); } } let promise; if (id) { promise = photoDB.sequelize.query( "SELECT * FROM faces WHERE id=:id", { replacements: { id: id }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }); } else { promise = photoDB.sequelize.query( "SELECT COUNT(id) AS count FROM faces WHERE faceConfidence>=0.9 AND identityId IS NULL", { type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }).then((results) => { if (!results[0].count) { return []; } const random = Math.floor(Math.random() * results[0].count); return photoDB.sequelize.query( "SELECT * FROM faces WHERE faceConfidence>=0.9 AND identityId IS NULL ORDER BY id LIMIT :index,1", { replacements: { index: random }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }); }); } return promise.then((faces) => { if (!faces.length) { return []; } console.log("Looking up " + faces.map(face => face.id).join(",")); return photoDB.sequelize.query( "SELECT relatedFaces.photoId AS photoId,fd.descriptor1Id,fd.descriptor2Id,fd.distanceCosine,relatedFaces.faceConfidence " + "FROM (SELECT id,photoId,faceConfidence FROM faces WHERE faces.id IN (:ids)) AS faces " + "INNER JOIN faces AS relatedFaces ON relatedFaces.identityId IS NULL AND relatedFaces.faceConfidence>=0.9 AND relatedFaces.id IN (fd.descriptor1Id,fd.descriptor2Id) " + "INNER JOIN facedistances AS fd ON fd.distanceCosine<=0.5 " + " AND (fd.descriptor1Id=faces.id OR fd.descriptor2Id=faces.id) " + "WHERE (faces.id=fd.descriptor1Id OR faces.id=fd.descriptor2Id) " + "ORDER BY fd.distanceCosine ASC",{ replacements: { ids: faces.map(face => face.id) }, type: photoDB.Sequelize.QueryTypes.SELECT, raw: true }).then((relatedFaces) => { faces.forEach((face) => { face.relatedFaces = relatedFaces.filter((related) => { return (related.photoId != faces[0].photoId && (related.descriptor1Id == face.id || related.descriptor2Id == face.id)); }).map((related) => { return { distanceCosine: related.distanceCosine, faceConfidence: related.faceConfidence, photoId: related.photoId, faceId: related.descriptor1Id != face.id ? related.descriptor1Id : related.descriptor2Id } }); }); return faces; }); }).then((results) => { return res.status(200).json(results); }).catch((error) => { console.error(error); return res.status(500).send("Error processing request."); }); }); module.exports = router;