Commit b57ffdb5 authored by Adrien Pavie's avatar Adrien Pavie
Browse files

Basic admin page

parent 414b57d9
......@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Next version (to be released)
### Added
- Very basic admin page to display recent sketches
## 0.2.2 - 2020-03-04
......
......@@ -2,5 +2,7 @@
"PG_HOST": "localhost",
"PG_USER": "postgres",
"PG_PORT": "5432",
"PG_DB": "gribrouillon"
"PG_DB": "gribrouillon",
"ADMIN_USER": "gribrouillon_admin",
"ADMIN_PASS": "password"
}
......@@ -1630,6 +1630,14 @@
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
},
"basic-auth": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
"requires": {
"safe-buffer": "5.1.2"
}
},
"bbox-intersect": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/bbox-intersect/-/bbox-intersect-0.1.2.tgz",
......@@ -3001,6 +3009,14 @@
"vary": "1.1.2"
}
},
"express-basic-auth": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.0.tgz",
"integrity": "sha512-iJ0h1Gk6fZRrFmO7tP9nIbxwNgCUJASfNj5fb0Hy15lGtbqqsxpt7609+wq+0XlByZjXmC/rslWQtnuSTVRIcg==",
"requires": {
"basic-auth": "2.0.1"
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
......
......@@ -61,6 +61,15 @@ FROM (
});
};
/**
* List all interesting sketches from most recent to oldest one
* @return {Promise} A promise solving on sketches metadata
*/
exports.listSketches = () => {
return pool.query("SELECT s.id, s.created FROM sketch s JOIN shape sh ON s.id = sh.sketch GROUP BY s.id HAVING COUNT(sh.id) >= 2 ORDER BY s.created DESC")
.then(result => result.rows);
};
/**
* Create a new shape
* @param {string} sid The sketch ID
......
......@@ -5,6 +5,7 @@
const CONFIG = require('../config.json');
const express = require('express');
const cors = require('cors');
const basicAuth = require('express-basic-auth');
const db = require("./db");
const request = require("request-promise-native");
const fs = require("fs");
......@@ -135,6 +136,24 @@ app.get('/status', (req, res) => {
res.send({ "status": "ok" });
});
app.get('/admin/sketches', basicAuth({ challenge: true, users: { [CONFIG.ADMIN_USER]: CONFIG.ADMIN_PASS } }), (req, res) => {
fs.readFile("src/website/admin.html", "utf8", (err, data) => {
if(err) {
console.error(err);
return res.status(500).send("Can't load admin page");
}
db.listSketches()
.then(sketches => {
res.send(data.replace("[/* SKETCHES_LIST */]", JSON.stringify(sketches)));
})
.catch(e => {
console.error(e);
res.status(500).send("Can't access sketch list");
});
});
});
// 404
app.use((req, res) => {
res.status(404).send(req.originalUrl + ' not found')
......
<!DOCTYPE html5>
<html>
<head>
<title>Gribrouillon - Administration</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=0, maximum-scale=1, minimum-scale=1" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="icon" type="image/png" href="img/badge.128.png" />
<style>
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
iframe {
border: none; width: 100%; height: calc(100% - 50px);
}
#control {
position: absolute; bottom: 0; right: 0; left: 0;
height: 40px; background-color: #222; color: white;
display: flex; justify-content: space-between; padding: 5px;
}
#sketch-info { text-align: center; }
#sketch-title { margin: 0; font-size: 1.1em; }
#sketch-date { margin: 0; font-size: 0.7em; }
</style>
</head>
<body>
<iframe id="frame" src=""></iframe>
<div id="control">
<button id="prev" disabled>Précédent</button>
<div id="sketch-info">
<h2 id="sketch-title"></h2>
<p id="sketch-date"></p>
</div>
<button id="next">Suivant</button>
</div>
<script>
// This is to receive list from DB
var sketches = [/* SKETCHES_LIST */];
// Load frame
var currentSketch = 0;
var frame = document.getElementById("frame");
var prevBtn = document.getElementById("prev");
var nextBtn = document.getElementById("next");
var sketchTitle = document.getElementById("sketch-title");
var sketchDate = document.getElementById("sketch-date");
// Display sketch
function showSketch() {
if(sketches.length > 0 && currentSketch >= 0 && currentSketch < sketches.length) {
frame.src = "/?sid=" + sketches[currentSketch].id;
sketchTitle.innerHTML = "Dessin "+sketches[currentSketch].id;
sketchDate.innerHTML = "Créé le "+(new Date(sketches[currentSketch].created)).toLocaleString();
}
if(currentSketch === 0) {
prevBtn.setAttribute("disabled", true);
}
else {
prevBtn.removeAttribute("disabled");
}
if(currentSketch === sketches.length - 1) {
nextBtn.setAttribute("disabled", true);
}
else {
nextBtn.removeAttribute("disabled");
}
}
showSketch();
// Handle control buttons
prevBtn.addEventListener("click", function(e) {
currentSketch--;
showSketch();
});
nextBtn.addEventListener("click", function(e) {
currentSketch++;
showSketch();
});
</script>
</body>
</html>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment