diff --git a/frontend/identities.html b/frontend/identities.html new file mode 100644 index 0000000..8570e4e --- /dev/null +++ b/frontend/identities.html @@ -0,0 +1,278 @@ + + + + + +
+ \ No newline at end of file diff --git a/server/app.js b/server/app.js index 7888fa3..9167f50 100755 --- a/server/app.js +++ b/server/app.js @@ -264,7 +264,9 @@ app.use(basePath + "api/v1/photos", require("./routes/photos")); app.use(basePath + "api/v1/days", require("./routes/days")); app.use(basePath + "api/v1/albums", require("./routes/albums")); app.use(basePath + "api/v1/holidays", require("./routes/holidays")); +app.use(basePath + "api/v1/faces", require("./routes/faces")); app.use(basePath + "api/v1/scan", require("./routes/scan")(scanner)); +app.use(basePath + "api/v1/identities", require("./routes/identities")); /* Declare the "catch all" index route last; the final route is a 404 dynamic router */ app.use(basePath, index); diff --git a/server/routes/faces.js b/server/routes/faces.js new file mode 100644 index 0000000..064100a --- /dev/null +++ b/server/routes/faces.js @@ -0,0 +1,134 @@ +"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", function(req, res/*, next*/) { + if (!req.user.maintainer) { + return res.status(401).send("Unauthorized to modify photos."); + } + + return res.status(400).send("Invalid request"); +}); + +router.delete("/:id?", function(req, res/*, next*/) { + if (!req.user.maintainer) { + return res.status(401).send("Unauthorized to delete photos."); + } + + return res.status(400).send("Invalid request"); +}); + +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.face1Id,fd.face2Id,fd.distance,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.face1Id,fd.face2Id) " + + "INNER JOIN facedistances AS fd ON fd.distance<=0.5 " + + " AND (fd.face1Id=faces.id OR fd.face2Id=faces.id) " + + "WHERE (faces.id=fd.face1Id OR faces.id=fd.face2Id) " + + "ORDER BY fd.distance 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.face1Id == face.id || related.face2Id == face.id)); + }).map((related) => { + return { + distance: related.distance, + faceConfidence: related.faceConfidence, + photoId: related.photoId, + faceId: related.face1Id != face.id ? related.face1Id : related.face2Id + } + }); + }); + 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]"}); + } + } + + return 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) => { + 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 + }); + }).then((faces) => { + return photoDB.sequelize.query( + "SELECT relatedFaces.photoId AS photoId,fd.face1Id,fd.face2Id,fd.distance,relatedFaces.faceConfidence " + + "FROM (SELECT id,photoId,faceConfidence FROM faces WHERE faces.id IN (:ids)) AS faces " + + "INNER JOIN faces AS relatedFaces ON relatedFaces.faceConfidence>=0.9 AND relatedFaces.id IN (fd.face1Id,fd.face2Id) " + + "INNER JOIN facedistances AS fd ON fd.distance<=0.5 " + + " AND (fd.face1Id=faces.id OR fd.face2Id=faces.id) " + + "WHERE (faces.id=fd.face1Id OR faces.id=fd.face2Id) " + + "ORDER BY fd.distance 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.face1Id == face.id || related.face2Id == face.id)); + }).map((related) => { + return { + distance: related.distance, + faceConfidence: related.faceConfidence, + photoId: related.photoId, + faceId: related.face1Id != face.id ? related.face1Id : related.face2Id + } + }); + }); + 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; diff --git a/server/routes/identities.js b/server/routes/identities.js new file mode 100644 index 0000000..d173323 --- /dev/null +++ b/server/routes/identities.js @@ -0,0 +1,43 @@ +"use strict"; + +const express = require("express"); + +let photoDB; + +require("../db/photos").then(function(db) { + photoDB = db; +}); + +const router = express.Router(); + +router.post("/", (req, res) => { + console.log(req.body); + return res.status(200).json({}); +}); + +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]"}); + } + } + + const filter = id ? "WHERE id=:id" : ""; + + return photoDB.sequelize.query(`SELECT * FROM identities ${filter}`, { + replacements: { + id: id + }, + type: photoDB.Sequelize.QueryTypes.SELECT, + raw: true + }).then((results) => { + return res.status(200).json(results); + }).catch((error) => { + console.error(error); + return res.status(500).send("Error processing request."); + }); +}); + +module.exports = router;